diff options
author | Robin Watts <robin.watts@artifex.com> | 2013-05-21 14:13:59 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2013-05-21 14:20:50 +0100 |
commit | 23dea6df2cb85a136ba6d8d8e34eebe4e105db24 (patch) | |
tree | 24f17851de0fadc51ac9691361b1cca97a48c332 /fitz | |
parent | e317abb479109200f2ec489b2868e671a060a585 (diff) | |
download | mupdf-23dea6df2cb85a136ba6d8d8e34eebe4e105db24.tar.xz |
Add monochrome PWG output routines.
Diffstat (limited to 'fitz')
-rw-r--r-- | fitz/fitz-internal.h | 3 | ||||
-rw-r--r-- | fitz/fitz.h | 17 | ||||
-rw-r--r-- | fitz/res_bitmap.c | 4 | ||||
-rw-r--r-- | fitz/res_halftone.c | 2 | ||||
-rw-r--r-- | fitz/res_pwg.c | 182 |
5 files changed, 174 insertions, 34 deletions
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); + } +} |