diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2017-08-11 15:55:26 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2017-08-17 13:38:48 +0200 |
commit | c930c80f31a13c2aea907a0d8b4ec24271ca5276 (patch) | |
tree | eeb9156f538401461593ced9154aa1f7f9251d72 /source | |
parent | d447754cc9a6220df1b2f8395101b5d79adac9fe (diff) | |
download | mupdf-c930c80f31a13c2aea907a0d8b4ec24271ca5276.tar.xz |
Add PCL document writer.
Fix color PCL writing bugs introduced when making alpha channels
in pixmaps optional.
Diffstat (limited to 'source')
-rw-r--r-- | source/fitz/output-pcl.c | 231 | ||||
-rw-r--r-- | source/fitz/writer.c | 2 | ||||
-rw-r--r-- | source/tools/muconvert.c | 1 |
3 files changed, 174 insertions, 60 deletions
diff --git a/source/fitz/output-pcl.c b/source/fitz/output-pcl.c index bb3a82dd..32072518 100644 --- a/source/fitz/output-pcl.c +++ b/source/fitz/output-pcl.c @@ -210,6 +210,25 @@ static void copy_opts(fz_pcl_options *dst, const fz_pcl_options *src) *dst = *src; } +const char *fz_pcl_write_options_usage = + "PCL output options:\n" + "\tcolorspace=mono: render 1-bit black and white page\n" + "\tcolorspace=rgb: render full color page\n" + "\tpreset=generic|ljet4|dj500|fs600|lj|lj2|lj3|lj3d|lj4|lj4pl|lj4d|lp2563b|oce9050\n" + "\tspacing=0: No vertical spacing capability\n" + "\tspacing=1: PCL 3 spacing (<ESC>*p+<n>Y)\n" + "\tspacing=2: PCL 4 spacing (<ESC>*b<n>Y)\n" + "\tspacing=3: PCL 5 spacing (<ESC>*b<n>Y and clear seed row)\n" + "\tmode2: Enable mode 2 graphics compression\n" + "\tmode3: Enable mode 3 graphics compression\n" + "\teog_reset: End of graphics (<ESC>*rB) resets all parameters\n" + "\thas_duplex: Duplex supported (<ESC>&l<duplex>S)\n" + "\thas_papersize: Papersize setting supported (<ESC>&l<sizecode>A)\n" + "\thas_copies: Number of copies supported (<ESC>&l<copies>X)\n" + "\tis_ljet4pjl: Disable/Enable HP 4PJL model-specific output\n" + "\tis_oce9050: Disable/Enable Oce 9050 model-specific output\n" + "\n"; + void fz_pcl_preset(fz_context *ctx, fz_pcl_options *opts, const char *preset) { if (preset == NULL || *preset == 0 || !strcmp(preset, "generic")) @@ -242,105 +261,103 @@ void fz_pcl_preset(fz_context *ctx, fz_pcl_options *opts, const char *preset) fz_throw(ctx, FZ_ERROR_GENERIC, "Unknown preset '%s'", preset); } -void fz_pcl_option(fz_context *ctx, fz_pcl_options *opts, const char *option, int val) +fz_pcl_options * +fz_parse_pcl_options(fz_context *ctx, fz_pcl_options *opts, const char *args) { - if (opts == NULL) - return; + const char *val; - if (!strcmp(option, "spacing")) + memset(opts, 0, sizeof *opts); + + if (fz_has_option(ctx, args, "preset", &val)) + fz_pcl_preset(ctx, opts, val); + else + fz_pcl_preset(ctx, opts, "generic"); + + if (fz_has_option(ctx, args, "spacing", &val)) { - switch (val) + switch (atoi(val)) { - case 0: - opts->features &= ~PCL_ANY_SPACING; - break; - case 1: - opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL3_SPACING; - break; - case 2: - opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL4_SPACING; - break; - case 3: - opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL5_SPACING; - break; - default: - fz_throw(ctx, FZ_ERROR_GENERIC, "Unsupported PCL spacing %d (0-3 only)", val); + case 0: opts->features &= ~PCL_ANY_SPACING; break; + case 1: opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL3_SPACING; break; + case 2: opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL4_SPACING; break; + case 3: opts->features = (opts->features & ~PCL_ANY_SPACING) | PCL5_SPACING; break; + default: fz_throw(ctx, FZ_ERROR_GENERIC, "Unsupported PCL spacing %d (0-3 only)", atoi(val)); } } - else if (!strcmp(option, "mode2")) + if (fz_has_option(ctx, args, "mode2", &val)) { - if (val == 0) + if (fz_option_eq(val, "no")) opts->features &= ~PCL_MODE_2_COMPRESSION; - else if (val == 1) + else if (fz_option_eq(val, "yes")) opts->features |= PCL_MODE_2_COMPRESSION; else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for mode2 value"); + fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 'yes' or 'no' for mode2 value"); } - else if (!strcmp(option, "mode3")) + if (fz_has_option(ctx, args, "mode3", &val)) { - if (val == 0) + if (fz_option_eq(val, "no")) opts->features &= ~PCL_MODE_3_COMPRESSION; - else if (val == 1) + else if (fz_option_eq(val, "yes")) opts->features |= PCL_MODE_3_COMPRESSION; else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for mode3 value"); + fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 'yes' or 'no' for mode3 value"); } - else if (!strcmp(option, "eog_reset")) + if (fz_has_option(ctx, args, "eog_reset", &val)) { - if (val == 0) + if (fz_option_eq(val, "no")) opts->features &= ~PCL_END_GRAPHICS_DOES_RESET; - else if (val == 1) + else if (fz_option_eq(val, "yes")) opts->features |= PCL_END_GRAPHICS_DOES_RESET; else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for eog_reset value"); + fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 'yes' or 'no' for eog_reset value"); } - else if (!strcmp(option, "has_duplex")) + if (fz_has_option(ctx, args, "has_duplex", &val)) { - if (val == 0) + if (fz_option_eq(val, "no")) opts->features &= ~PCL_HAS_DUPLEX; - else if (val == 1) + else if (fz_option_eq(val, "yes")) opts->features |= PCL_HAS_DUPLEX; else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for has_duplex value"); + fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 'yes' or 'no' for has_duplex value"); } - else if (!strcmp(option, "has_papersize")) + if (fz_has_option(ctx, args, "has_papersize", &val)) { - if (val == 0) + if (fz_option_eq(val, "no")) opts->features &= ~PCL_CAN_SET_PAPER_SIZE; - else if (val == 1) + else if (fz_option_eq(val, "yes")) opts->features |= PCL_CAN_SET_PAPER_SIZE; else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for has_papersize value"); + fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 'yes' or 'no' for has_papersize value"); } - else if (!strcmp(option, "has_copies")) + if (fz_has_option(ctx, args, "has_copies", &val)) { - if (val == 0) + if (fz_option_eq(val, "no")) opts->features &= ~PCL_CAN_PRINT_COPIES; - else if (val == 1) + else if (fz_option_eq(val, "yes")) opts->features |= PCL_CAN_PRINT_COPIES; else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for has_papersize value"); + fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 'yes' or 'no' for has_papersize value"); } - else if (!strcmp(option, "is_ljet4pjl")) + if (fz_has_option(ctx, args, "is_ljet4pjl", &val)) { - if (val == 0) + if (fz_option_eq(val, "no")) opts->features &= ~HACK__IS_A_LJET4PJL; - else if (val == 1) + else if (fz_option_eq(val, "yes")) opts->features |= HACK__IS_A_LJET4PJL; else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for is_ljet4pjl value"); + fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 'yes' or 'no' for is_ljet4pjl value"); } - else if (!strcmp(option, "is_oce9050")) + if (fz_has_option(ctx, args, "is_oce9050", &val)) { - if (val == 0) + if (fz_option_eq(val, "no")) opts->features &= ~HACK__IS_A_OCE9050; - else if (val == 1) + else if (fz_option_eq(val, "yes")) opts->features |= HACK__IS_A_OCE9050; else - fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 0 or 1 for is_oce9050 value"); + fz_throw(ctx, FZ_ERROR_GENERIC, "Expected 'yes' or 'no' for is_oce9050 value"); } - else - fz_throw(ctx, FZ_ERROR_GENERIC, "Unknown pcl option '%s'", option); + + return opts; } static void @@ -602,8 +619,7 @@ static void guess_paper_size(fz_pcl_options *pcl, int w, int h, int xres, int yr pcl->orientation = rotated; } -/* Copy a line, removing the alpha, returning true if the line - * was blank. */ +/* Copy a line, returning true if the line was blank. */ static int line_is_blank(unsigned char *dst, const unsigned char *sp, int w) { @@ -614,7 +630,6 @@ line_is_blank(unsigned char *dst, const unsigned char *sp, int w) zero |= (*dst++ = *sp++); zero |= (*dst++ = *sp++); zero |= (*dst++ = *sp++); - sp++; } return zero == 0; @@ -720,11 +735,17 @@ color_pcl_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colors int w = writer->super.w; int h = writer->super.h; int n = writer->super.n; + int s = writer->super.s; + int a = writer->super.alpha; int xres = writer->super.xres; int yres = writer->super.yres; - if (n != 4 || writer->super.s != 0) - fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be rgb to write as pcl"); + if (a != 0) + fz_throw(ctx, FZ_ERROR_GENERIC, "color PCL cannot write alpha channel"); + if (s != 0) + fz_throw(ctx, FZ_ERROR_GENERIC, "color PCL cannot write spot colors"); + if (n != 3) + fz_throw(ctx, FZ_ERROR_GENERIC, "color PCL must be RGB"); writer->linebuf = fz_malloc(ctx, w * 3 * 2); writer->compbuf = fz_malloc(ctx, 32767); @@ -788,7 +809,7 @@ color_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int b return; ds = w * 3; - ss = w * 4; + ss = w * 3; prev = writer->prev; curr = writer->curr; @@ -1111,8 +1132,12 @@ mono_pcl_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorsp int max_mode_2_size; int max_mode_3_size; + if (writer->super.alpha != 0) + fz_throw(ctx, FZ_ERROR_GENERIC, "mono PCL cannot write alpha channel"); if (writer->super.s != 0) - fz_throw(ctx, FZ_ERROR_GENERIC, "Mono PCL cannot write spot colors"); + fz_throw(ctx, FZ_ERROR_GENERIC, "mono PCL cannot write spot colors"); + if (writer->super.n != 1) + fz_throw(ctx, FZ_ERROR_GENERIC, "mono PCL must be grayscale"); line_size = (w + 7)/8; max_mode_2_size = line_size + (line_size/127) + 1; @@ -1371,3 +1396,89 @@ fz_save_bitmap_as_pcl(fz_context *ctx, fz_bitmap *bitmap, char *filename, int ap fz_catch(ctx) fz_rethrow(ctx); } + +/* High-level document writer interface */ + +typedef struct fz_pcl_writer_s fz_pcl_writer; + +struct fz_pcl_writer_s +{ + fz_document_writer super; + fz_draw_options draw; + fz_pcl_options pcl; + fz_pixmap *pixmap; + int mono; + fz_output *out; +}; + +static fz_device * +pcl_begin_page(fz_context *ctx, fz_document_writer *wri_, const fz_rect *mediabox) +{ + fz_pcl_writer *wri = (fz_pcl_writer*)wri_; + return fz_new_draw_device_with_options(ctx, &wri->draw, mediabox, &wri->pixmap); +} + +static void +pcl_end_page(fz_context *ctx, fz_document_writer *wri_, fz_device *dev) +{ + fz_pcl_writer *wri = (fz_pcl_writer*)wri_; + + fz_close_device(ctx, dev); + fz_drop_device(ctx, dev); + + if (wri->mono) + { + fz_bitmap *bitmap = fz_new_bitmap_from_pixmap(ctx, wri->pixmap, NULL); + fz_try(ctx) + fz_write_bitmap_as_pcl(ctx, wri->out, bitmap, &wri->pcl); + fz_always(ctx) + fz_drop_bitmap(ctx, bitmap); + fz_catch(ctx) + fz_rethrow(ctx); + } + else + { + fz_write_pixmap_as_pcl(ctx, wri->out, wri->pixmap, &wri->pcl); + } + + fz_drop_pixmap(ctx, wri->pixmap); + wri->pixmap = NULL; +} + +static void +pcl_close_writer(fz_context *ctx, fz_document_writer *wri_) +{ +} + +static void +pcl_drop_writer(fz_context *ctx, fz_document_writer *wri_) +{ + fz_pcl_writer *wri = (fz_pcl_writer*)wri_; + fz_drop_pixmap(ctx, wri->pixmap); + fz_drop_output(ctx, wri->out); +} + +fz_document_writer * +fz_new_pcl_writer(fz_context *ctx, const char *path, const char *options) +{ + fz_pcl_writer *wri = fz_new_derived_document_writer(ctx, fz_pcl_writer, pcl_begin_page, pcl_end_page, pcl_close_writer, pcl_drop_writer); + const char *val; + + fz_try(ctx) + { + fz_parse_draw_options(ctx, &wri->draw, options); + fz_parse_pcl_options(ctx, &wri->pcl, options); + if (fz_has_option(ctx, options, "colorspace", &val)) + if (fz_option_eq(val, "mono")) + wri->mono = 1; + wri->out = fz_new_output_with_path(ctx, path ? path : "out.pcl", 0); + } + fz_catch(ctx) + { + fz_drop_output(ctx, wri->out); + fz_free(ctx, wri); + fz_rethrow(ctx); + } + + return (fz_document_writer*)wri; +} diff --git a/source/fitz/writer.c b/source/fitz/writer.c index f0e00256..ba7c16cf 100644 --- a/source/fitz/writer.c +++ b/source/fitz/writer.c @@ -140,6 +140,8 @@ fz_new_document_writer(fz_context *ctx, const char *path, const char *format, co if (!fz_strcasecmp(format, "pkm")) return fz_new_pkm_pixmap_writer(ctx, path, options); + if (!fz_strcasecmp(format, "pcl")) + return fz_new_pcl_writer(ctx, path, options); if (!fz_strcasecmp(format, "pwg")) return fz_new_pwg_writer(ctx, path, options); diff --git a/source/tools/muconvert.c b/source/tools/muconvert.c index f306664d..08932772 100644 --- a/source/tools/muconvert.c +++ b/source/tools/muconvert.c @@ -52,6 +52,7 @@ static void usage(void) "\n" ); fputs(fz_draw_options_usage, stderr); + fputs(fz_pcl_write_options_usage, stderr); fputs(fz_pwg_write_options_usage, stderr); fputs(fz_stext_options_usage, stderr); #if FZ_ENABLE_PDF |