summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2013-05-16 17:03:29 +0100
committerRobin Watts <robin.watts@artifex.com>2013-05-16 18:54:48 +0100
commit5157d7cac960316e76ac408d1f6ec1d24867bdb7 (patch)
tree994b30b4256b6298d5ec8314a2bea8ba9f1799b3
parentd7a79bb7a88abfca9b1e0bc79703951f5a1e4bc5 (diff)
downloadmupdf-5157d7cac960316e76ac408d1f6ec1d24867bdb7.tar.xz
Add PWG raster output to mudraw.
-rw-r--r--apps/mudraw.c11
-rw-r--r--fitz/fitz-internal.h20
-rw-r--r--fitz/fitz.h25
-rw-r--r--fitz/res_pixmap.c204
4 files changed, 248 insertions, 12 deletions
diff --git a/apps/mudraw.c b/apps/mudraw.c
index efc06f25..dac5f42e 100644
--- a/apps/mudraw.c
+++ b/apps/mudraw.c
@@ -12,7 +12,7 @@
enum { TEXT_PLAIN = 1, TEXT_HTML = 2, TEXT_XML = 3 };
-enum { OUT_PNG, OUT_PPM, OUT_PNM, OUT_PAM, OUT_PGM, OUT_PBM, OUT_SVG };
+enum { OUT_PNG, OUT_PPM, OUT_PNM, OUT_PAM, OUT_PGM, OUT_PBM, OUT_SVG, OUT_PWG };
typedef struct
{
@@ -29,6 +29,7 @@ static const suffix_t suffix_table[] =
{ ".pam", OUT_PAM },
{ ".pbm", OUT_PBM },
{ ".svg", OUT_SVG },
+ { ".pwg", OUT_PWG },
};
/*
@@ -102,6 +103,7 @@ static int fit = 0;
static int errored = 0;
static int ignore_errors = 0;
static int output_format;
+static int append = 0;
static fz_text_sheet *sheet = NULL;
static fz_colorspace *colorspace;
@@ -577,6 +579,13 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
fz_write_pam(ctx, pix, buf, savealpha);
else if (output_format == OUT_PNG)
fz_write_png(ctx, pix, buf, savealpha);
+ else if (output_format == OUT_PWG)
+ {
+ if (strstr(output, "%d") != NULL)
+ append = 0;
+ fz_write_pwg(ctx, pix, buf, append);
+ append = 1;
+ }
else if (output_format == OUT_PBM) {
fz_bitmap *bit = fz_halftone_pixmap(ctx, pix, NULL);
fz_write_pbm(ctx, bit, buf);
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,