diff options
author | Robin Watts <robin.watts@artifex.com> | 2013-05-16 17:03:29 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2013-05-16 18:54:48 +0100 |
commit | 5157d7cac960316e76ac408d1f6ec1d24867bdb7 (patch) | |
tree | 994b30b4256b6298d5ec8314a2bea8ba9f1799b3 /fitz | |
parent | d7a79bb7a88abfca9b1e0bc79703951f5a1e4bc5 (diff) | |
download | mupdf-5157d7cac960316e76ac408d1f6ec1d24867bdb7.tar.xz |
Add PWG raster output to mudraw.
Diffstat (limited to 'fitz')
-rw-r--r-- | fitz/fitz-internal.h | 20 | ||||
-rw-r--r-- | fitz/fitz.h | 25 | ||||
-rw-r--r-- | fitz/res_pixmap.c | 204 |
3 files changed, 238 insertions, 11 deletions
diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h index 22947cf4..24895591 100644 --- a/fitz/fitz-internal.h +++ b/fitz/fitz-internal.h @@ -799,6 +799,26 @@ static inline int fz_is_eof_bits(fz_stream *stm) return fz_is_eof(stm) && (stm->avail == 0 || stm->bits == EOF); } +static inline int fz_write_int32be(fz_output *out, int x) +{ + char data[4]; + + data[0] = x>>24; + data[1] = x>>16; + data[2] = x>>8; + data[3] = x; + + return fz_write(out, data, 4); +} + +static inline void +fz_write_byte(fz_output *out, int x) +{ + char data = x; + + fz_write(out, &data, 1); +} + /* * Data filters. */ diff --git a/fitz/fitz.h b/fitz/fitz.h index 5eb570d0..f18efe6b 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -1703,6 +1703,14 @@ void fz_write_pam(fz_context *ctx, fz_pixmap *pixmap, char *filename, int saveal void fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha); /* + fz_write_pwg: Save a pixmap as a pwg + + filename: The filename to save as (including extension). + append: If non-zero, then append a new page to existing file. +*/ +void fz_write_pwg(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append); + +/* fz_write_pbm: Save a bitmap as a pbm filename: The filename to save as (including extension). @@ -1827,7 +1835,22 @@ int fz_write(fz_output *out, const void *data, int len); /* Output a pixmap to an output stream as a png. */ -void fz_output_png(fz_context *ctx, const fz_pixmap *pixmap, fz_output *out, int savealpha); +void fz_output_png(fz_output *out, const fz_pixmap *pixmap, int savealpha); + +/* + Output a pixmap to an output stream as a pwg raster. +*/ +void fz_output_pwg(fz_output *out, const fz_pixmap *pixmap); + +/* + Output the file header to a pwg stream, ready for pages to follow it. +*/ +void fz_output_pwg_file_header(fz_output *out); + +/* + Output a page to a pwg stream to follow a header, or other pages. +*/ +void fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap); /* Get an image as a png in a buffer. diff --git a/fitz/res_pixmap.c b/fitz/res_pixmap.c index 5c12f19b..6a931486 100644 --- a/fitz/res_pixmap.c +++ b/fitz/res_pixmap.c @@ -545,39 +545,39 @@ static inline void big32(unsigned char *buf, unsigned int v) buf[3] = (v) & 0xff; } -static inline void put32(unsigned int v, fz_output *out) -{ - fz_printf(out, "%c%c%c%c", v>>24, v>>16, v>>8, v); -} - static void putchunk(char *tag, unsigned char *data, int size, fz_output *out) { unsigned int sum; - put32(size, out); + fz_write_int32be(out, size); fz_write(out, tag, 4); fz_write(out, data, size); sum = crc32(0, NULL, 0); sum = crc32(sum, (unsigned char*)tag, 4); sum = crc32(sum, data, size); - put32(sum, out); + fz_write_int32be(out, sum); } void fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha) { FILE *fp = fopen(filename, "wb"); + fz_output *out = NULL; if (!fp) { fz_throw(ctx, "cannot open file '%s': %s", filename, strerror(errno)); } + fz_var(out); + fz_try(ctx) { - fz_output_png(ctx, pixmap, fz_new_output_with_file(ctx, fp), savealpha); + out = fz_new_output_with_file(ctx, fp); + fz_output_png(out, pixmap, savealpha); } fz_always(ctx) { + fz_close_output(out); fclose(fp); } fz_catch(ctx) @@ -587,7 +587,7 @@ fz_write_png(fz_context *ctx, fz_pixmap *pixmap, char *filename, int savealpha) } void -fz_output_png(fz_context *ctx, const fz_pixmap *pixmap, fz_output *out, int savealpha) +fz_output_png(fz_output *out, const fz_pixmap *pixmap, int savealpha) { static const unsigned char pngsig[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; unsigned char head[13]; @@ -598,6 +598,12 @@ fz_output_png(fz_context *ctx, const fz_pixmap *pixmap, fz_output *out, int save int y, x, k, sn, dn; int color; int err; + fz_context *ctx; + + if (!out || !pixmap) + return; + + ctx = out->ctx; fz_var(udata); fz_var(cdata); @@ -697,7 +703,7 @@ fz_image_as_png(fz_context *ctx, fz_image *image, int w, int h) } buf = fz_new_buffer(ctx, 1024); out = fz_new_output_with_buffer(ctx, buf); - fz_output_png(ctx, pix, out, 0); + fz_output_png(out, pix, 0); } fz_always(ctx) { @@ -720,6 +726,184 @@ fz_pixmap_size(fz_context *ctx, fz_pixmap * pix) return sizeof(*pix) + pix->n * pix->w * pix->h; } +void +fz_output_pwg_file_header(fz_output *out) +{ + static const unsigned char pwgsig[4] = { 'R', 'a', 'S', '2' }; + + /* Sync word */ + fz_write(out, pwgsig, 4); +} + +void +fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap) +{ + static const unsigned char zero[4] = { 0 }; + unsigned char *sp; + int y, x, i, sn, dn, ss; + fz_context *ctx; + + if (!out || !pixmap) + return; + + ctx = out->ctx; + + if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4) + fz_throw(ctx, "pixmap must be grayscale or rgb to write as pwg"); + + sn = pixmap->n; + dn = pixmap->n; + if (dn == 2 || dn == 4) + dn--; + + /* Page Header: */ + for (i=0; i < 276; i += 4) + fz_write(out, zero, 4); + fz_write_int32be(out, pixmap->xres); + fz_write_int32be(out, pixmap->yres); + /* CUPS format says that 284->300 are supposed to be the bbox of the + * page in points. PWG says 'Reserved'. */ + for (i=284; i < 300; i += 4) + fz_write(out, zero, 4); + for (i=300; i < 340; i += 4) + fz_write(out, zero, 4); + fz_write_int32be(out, 1); /* 1 copy */ + for (i=344; i < 352; i += 4) + fz_write(out, zero, 4); + fz_write_int32be(out, pixmap->w * 72/ pixmap->xres); /* Page size in points */ + fz_write_int32be(out, pixmap->h * 72/ pixmap->yres); + for (i=360; i < 372; i += 4) + fz_write(out, zero, 4); + fz_write_int32be(out, pixmap->w); /* Page image in pixels */ + fz_write_int32be(out, pixmap->h); + fz_write_int32be(out, 0); /* Reserved */ + fz_write_int32be(out, 8); /* Bits per color */ + fz_write_int32be(out, 8*dn); /* Bits per pixel */ + fz_write_int32be(out, pixmap->w * dn); /* Bytes per line */ + fz_write_int32be(out, 0); /* Chunky pixels */ + fz_write_int32be(out, dn == 1 ? 18 /* Sgray */ : 19 /* Srgb */); /* Colorspace */ + for (i=404; i < 420; i += 4) + fz_write(out, zero, 4); + fz_write_int32be(out, dn); /* Num Colors */ + for (i=424; i < 452; i += 4) + fz_write(out, zero, 4); + fz_write_int32be(out, 1); /* TotalPageCount */ + fz_write_int32be(out, 1); /* CrossFeedTransform */ + fz_write_int32be(out, 1); /* FeedTransform */ + fz_write_int32be(out, 0); /* ImageBoxLeft */ + fz_write_int32be(out, 0); /* ImageBoxTop */ + fz_write_int32be(out, pixmap->w); /* ImageBoxRight */ + fz_write_int32be(out, pixmap->h); /* ImageBoxBottom */ + for (i=480; i < 1796; i += 4) + fz_write(out, zero, 4); + + /* Now output the actual bitmap, using a packbits like compression */ + sp = pixmap->samples; + ss = pixmap->w * sn; + y = 0; + while (y < pixmap->h) + { + int yrep; + + assert(sp == pixmap->samples + y * ss); + + /* Count the number of times this line is repeated */ + for (yrep = 1; yrep < 256 && y+yrep < pixmap->h; yrep++) + { + if (memcmp(sp, sp + yrep * ss, ss) != 0) + break; + } + fz_write_byte(out, yrep-1); + + /* Encode the line */ + x = 0; + while (x < pixmap->w) + { + int d; + + assert(sp == pixmap->samples + y * ss + x * sn); + + /* How far do we have to look to find a repeated value? */ + for (d = 1; d < 128 && x+d < pixmap->w; d++) + { + if (memcmp(sp + (d-1)*sn, sp + d*sn, sn) == 0) + break; + } + if (d == 1) + { + int xrep; + + /* We immediately have a repeat (or we've hit + * the end of the line). Count the number of + * times this value is repeated. */ + for (xrep = 1; xrep < 128 && x+xrep < pixmap->w; xrep++) + { + if (memcmp(sp, sp + xrep*sn, sn) != 0) + break; + } + fz_write_byte(out, xrep-1); + fz_write(out, sp, dn); + sp += sn*xrep; + x += xrep; + } + else + { + fz_write_byte(out, 257-d); + x += d; + while (d > 0) + { + fz_write(out, sp, dn); + sp += sn; + d--; + } + } + } + + /* Move to the next line */ + sp += ss*(yrep-1); + y += yrep; + } +} + +void +fz_output_pwg(fz_output *out, const fz_pixmap *pixmap) +{ + fz_output_pwg_file_header(out); + fz_output_pwg_page(out, pixmap); +} + +void +fz_write_pwg(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append) +{ + FILE *fp; + fz_output *out = NULL; + + fp = fopen(filename, append ? "ab" : "wb"); + if (!fp) + { + fz_throw(ctx, "cannot open file '%s': %s", filename, strerror(errno)); + } + + fz_var(out); + + fz_try(ctx) + { + out = fz_new_output_with_file(ctx, fp); + if (!append) + fz_output_pwg_file_header(out); + fz_output_pwg_page(out, pixmap); + } + fz_always(ctx) + { + fz_close_output(out); + fclose(fp); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } +} + #ifdef ARCH_ARM static void fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor, |