summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2017-08-11 15:55:26 +0200
committerTor Andersson <tor.andersson@artifex.com>2017-08-17 13:38:48 +0200
commitc930c80f31a13c2aea907a0d8b4ec24271ca5276 (patch)
treeeeb9156f538401461593ced9154aa1f7f9251d72 /source
parentd447754cc9a6220df1b2f8395101b5d79adac9fe (diff)
downloadmupdf-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.c231
-rw-r--r--source/fitz/writer.c2
-rw-r--r--source/tools/muconvert.c1
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