summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2013-05-21 14:13:59 +0100
committerRobin Watts <robin.watts@artifex.com>2013-05-21 14:20:50 +0100
commit23dea6df2cb85a136ba6d8d8e34eebe4e105db24 (patch)
tree24f17851de0fadc51ac9691361b1cca97a48c332
parente317abb479109200f2ec489b2868e671a060a585 (diff)
downloadmupdf-23dea6df2cb85a136ba6d8d8e34eebe4e105db24.tar.xz
Add monochrome PWG output routines.
-rw-r--r--apps/mudraw.c11
-rw-r--r--fitz/fitz-internal.h3
-rw-r--r--fitz/fitz.h17
-rw-r--r--fitz/res_bitmap.c4
-rw-r--r--fitz/res_halftone.c2
-rw-r--r--fitz/res_pwg.c182
6 files changed, 183 insertions, 36 deletions
diff --git a/apps/mudraw.c b/apps/mudraw.c
index c12b3964..0b5df0a8 100644
--- a/apps/mudraw.c
+++ b/apps/mudraw.c
@@ -71,7 +71,7 @@ static const format_cs_table_t format_cs_table[] =
{ OUT_PGM, CS_GRAY, { CS_GRAY, CS_RGB } },
{ OUT_PBM, CS_MONO, { CS_MONO } },
{ OUT_SVG, CS_UNSET, { CS_UNSET } },
- { OUT_PWG, CS_RGB, { CS_GRAY, CS_RGB } }
+ { OUT_PWG, CS_RGB, { CS_MONO, CS_GRAY, CS_RGB } }
};
/*
@@ -627,7 +627,14 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
{
if (strstr(output, "%d") != NULL)
append = 0;
- fz_write_pwg(ctx, pix, buf, append, NULL);
+ if (out_cs == CS_MONO)
+ {
+ fz_bitmap *bit = fz_halftone_pixmap(ctx, pix, NULL);
+ fz_write_pwg_bitmap(ctx, bit, buf, append, NULL);
+ fz_drop_bitmap(ctx, bit);
+ }
+ else
+ fz_write_pwg(ctx, pix, buf, append, NULL);
append = 1;
}
else if (output_format == OUT_PBM) {
diff --git a/fitz/fitz-internal.h b/fitz/fitz-internal.h
index 25ab6860..b72f09d0 100644
--- a/fitz/fitz-internal.h
+++ b/fitz/fitz-internal.h
@@ -853,10 +853,11 @@ struct fz_bitmap_s
{
int refs;
int w, h, stride, n;
+ int xres, yres;
unsigned char *samples;
};
-fz_bitmap *fz_new_bitmap(fz_context *ctx, int w, int h, int n);
+fz_bitmap *fz_new_bitmap(fz_context *ctx, int w, int h, int n, int xres, int yres);
void fz_bitmap_details(fz_bitmap *bitmap, int *w, int *h, int *n, int *stride);
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 7b3f33f5..790d65f8 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -1777,6 +1777,18 @@ struct fz_pwg_options_s
void fz_write_pwg(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, const fz_pwg_options *pwg);
/*
+ fz_write_pwg_bitmap: Save a bitmap as a pwg
+
+ filename: The filename to save as (including extension).
+
+ append: If non-zero, then append a new page to existing file.
+
+ pwg: NULL, or a pointer to an options structure (initialised to zero
+ before being filled in, for future expansion).
+*/
+void fz_write_pwg_bitmap(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, const fz_pwg_options *pwg);
+
+/*
fz_write_pbm: Save a bitmap as a pbm
filename: The filename to save as (including extension).
@@ -1919,6 +1931,11 @@ void fz_output_pwg_file_header(fz_output *out);
void fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg);
/*
+ Output a bitmap page to a pwg stream to follow a header, or other pages.
+*/
+void fz_output_pwg_bitmap_page(fz_output *out, const fz_bitmap *bitmap, const fz_pwg_options *pwg);
+
+/*
Get an image as a png in a buffer.
*/
fz_buffer *fz_image_as_png(fz_context *ctx, fz_image *image, int w, int h);
diff --git a/fitz/res_bitmap.c b/fitz/res_bitmap.c
index 4b871c23..af70f983 100644
--- a/fitz/res_bitmap.c
+++ b/fitz/res_bitmap.c
@@ -1,7 +1,7 @@
#include "fitz-internal.h"
fz_bitmap *
-fz_new_bitmap(fz_context *ctx, int w, int h, int n)
+fz_new_bitmap(fz_context *ctx, int w, int h, int n, int xres, int yres)
{
fz_bitmap *bit;
@@ -10,6 +10,8 @@ fz_new_bitmap(fz_context *ctx, int w, int h, int n)
bit->w = w;
bit->h = h;
bit->n = n;
+ bit->xres = xres;
+ bit->yres = yres;
/* Span is 32 bit aligned. We may want to make this 64 bit if we
* use SSE2 etc. */
bit->stride = ((n * w + 31) & ~31) >> 3;
diff --git a/fitz/res_halftone.c b/fitz/res_halftone.c
index f8bef236..b0094cb4 100644
--- a/fitz/res_halftone.c
+++ b/fitz/res_halftone.c
@@ -179,7 +179,7 @@ fz_bitmap *fz_halftone_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht)
ht = fz_default_halftone(ctx, n);
}
ht_line = fz_malloc(ctx, pix->w * n);
- out = fz_new_bitmap(ctx, pix->w, pix->h, n);
+ out = fz_new_bitmap(ctx, pix->w, pix->h, n, pix->xres, pix->yres);
o = out->samples;
p = pix->samples;
diff --git a/fitz/res_pwg.c b/fitz/res_pwg.c
index 620be86e..87ac8c74 100644
--- a/fitz/res_pwg.c
+++ b/fitz/res_pwg.c
@@ -9,26 +9,11 @@ fz_output_pwg_file_header(fz_output *out)
fz_write(out, pwgsig, 4);
}
-void
-fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg)
+static void
+output_header(fz_output *out, const fz_pwg_options *pwg, int xres, int yres, int w, int h, int bpp)
{
static const char zero[64] = { 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--;
+ int i;
/* Page Header: */
fz_write(out, pwg ? pwg->media_class : zero, 64);
@@ -40,8 +25,8 @@ fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options
fz_write_int32be(out, pwg ? pwg->collate : 0);
fz_write_int32be(out, pwg ? pwg->cut_media : 0);
fz_write_int32be(out, pwg ? pwg->duplex : 0);
- fz_write_int32be(out, pixmap->xres);
- fz_write_int32be(out, pixmap->yres);
+ fz_write_int32be(out, xres);
+ fz_write_int32be(out, 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)
@@ -61,24 +46,24 @@ fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options
fz_write_int32be(out, pwg ? pwg->num_copies : 0);
fz_write_int32be(out, pwg ? pwg->orientation : 0);
fz_write_int32be(out, pwg ? pwg->output_face_up : 0);
- fz_write_int32be(out, pixmap->w * 72/ pixmap->xres); /* Page size in points */
- fz_write_int32be(out, pixmap->h * 72/ pixmap->yres);
+ fz_write_int32be(out, w * 72/ xres); /* Page size in points */
+ fz_write_int32be(out, h * 72/ yres);
fz_write_int32be(out, pwg ? pwg->separations : 0);
fz_write_int32be(out, pwg ? pwg->tray_switch : 0);
fz_write_int32be(out, pwg ? pwg->tumble : 0);
- fz_write_int32be(out, pixmap->w); /* Page image in pixels */
- fz_write_int32be(out, pixmap->h);
+ fz_write_int32be(out, w); /* Page image in pixels */
+ fz_write_int32be(out, h);
fz_write_int32be(out, pwg ? pwg->media_type_num : 0);
- 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, bpp < 8 ? 1 : 8); /* Bits per color */
+ fz_write_int32be(out, bpp); /* Bits per pixel */
+ fz_write_int32be(out, (w * bpp + 7)/8); /* Bytes per line */
fz_write_int32be(out, 0); /* Chunky pixels */
- fz_write_int32be(out, dn == 1 ? 18 /* Sgray */ : 19 /* Srgb */); /* Colorspace */
+ fz_write_int32be(out, bpp == 1 ? 3 /* Black */ : (bpp == 8 ? 18 /* Sgray */ : 19 /* Srgb */)); /* Colorspace */
fz_write_int32be(out, pwg ? pwg->compression : 0);
fz_write_int32be(out, pwg ? pwg->row_count : 0);
fz_write_int32be(out, pwg ? pwg->row_feed : 0);
fz_write_int32be(out, pwg ? pwg->row_step : 0);
- fz_write_int32be(out, dn); /* Num Colors */
+ fz_write_int32be(out, bpp <= 8 ? 1 : 3); /* Num Colors */
for (i=424; i < 452; i += 4)
fz_write(out, zero, 4);
fz_write_int32be(out, 1); /* TotalPageCount */
@@ -86,12 +71,35 @@ fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options
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 */
+ fz_write_int32be(out, w); /* ImageBoxRight */
+ fz_write_int32be(out, h); /* ImageBoxBottom */
for (i=480; i < 1668; i += 4)
fz_write(out, zero, 4);
fz_write(out, pwg ? pwg->rendering_intent : zero, 64);
fz_write(out, pwg ? pwg->page_size_name : zero, 64);
+}
+
+void
+fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg)
+{
+ unsigned char *sp;
+ int y, x, 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--;
+
+ output_header(out, pwg, pixmap->xres, pixmap->yres, pixmap->w, pixmap->h, dn*8);
/* Now output the actual bitmap, using a packbits like compression */
sp = pixmap->samples;
@@ -162,6 +170,86 @@ fz_output_pwg_page(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options
}
void
+fz_output_pwg_bitmap_page(fz_output *out, const fz_bitmap *bitmap, const fz_pwg_options *pwg)
+{
+ unsigned char *sp;
+ int y, x, ss;
+ fz_context *ctx;
+ int byte_width;
+
+ if (!out || !bitmap)
+ return;
+
+ ctx = out->ctx;
+
+ output_header(out, pwg, bitmap->xres, bitmap->yres, bitmap->w, bitmap->h, 1);
+
+ /* Now output the actual bitmap, using a packbits like compression */
+ sp = bitmap->samples;
+ ss = bitmap->stride;
+ byte_width = (bitmap->w+7)/8;
+ y = 0;
+ while (y < bitmap->h)
+ {
+ int yrep;
+
+ assert(sp == bitmap->samples + y * ss);
+
+ /* Count the number of times this line is repeated */
+ for (yrep = 1; yrep < 256 && y+yrep < bitmap->h; yrep++)
+ {
+ if (memcmp(sp, sp + yrep * ss, byte_width) != 0)
+ break;
+ }
+ fz_write_byte(out, yrep-1);
+
+ /* Encode the line */
+ x = 0;
+ while (x < byte_width)
+ {
+ int d;
+
+ assert(sp == bitmap->samples + y * ss + x);
+
+ /* How far do we have to look to find a repeated value? */
+ for (d = 1; d < 128 && x+d < byte_width; d++)
+ {
+ if (sp[d-1] == sp[d])
+ 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 < byte_width; xrep++)
+ {
+ if (sp[0] != sp[xrep])
+ break;
+ }
+ fz_write_byte(out, xrep-1);
+ fz_write(out, sp, 1);
+ sp += xrep;
+ x += xrep;
+ }
+ else
+ {
+ fz_write_byte(out, 257-d);
+ fz_write(out, sp, d);
+ sp += d;
+ x += d;
+ }
+ }
+
+ /* Move to the next line */
+ sp += ss*yrep - byte_width;
+ y += yrep;
+ }
+}
+
+void
fz_output_pwg(fz_output *out, const fz_pixmap *pixmap, const fz_pwg_options *pwg)
{
fz_output_pwg_file_header(out);
@@ -199,3 +287,35 @@ fz_write_pwg(fz_context *ctx, fz_pixmap *pixmap, char *filename, int append, con
fz_rethrow(ctx);
}
}
+
+void
+fz_write_pwg_bitmap(fz_context *ctx, fz_bitmap *bitmap, char *filename, int append, const fz_pwg_options *pwg)
+{
+ 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_bitmap_page(out, bitmap, pwg);
+ }
+ fz_always(ctx)
+ {
+ fz_close_output(out);
+ fclose(fp);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}