summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2018-10-15 15:54:39 +0100
committerRobin Watts <robin.watts@artifex.com>2018-10-18 15:19:25 +0100
commit22fa8866a4fa753ebe9aefa08f2cdc101b399119 (patch)
tree4a820fe0548dd0f59dc7b67e2dfb015aeab4700b /source
parent854a2cd9a4e9700b5f829409d268f61d7adc4509 (diff)
downloadmupdf-22fa8866a4fa753ebe9aefa08f2cdc101b399119.tar.xz
Bug 699967: Fix crash with wide format output to color PCL.
Writing to wide format output was causing uncompressed lines of more than 32K to be written to a 32K buffer. I now recognise that there is an inherent limitation in PCL where image data can't be larger than 32K, so we'll have to split page output into subimages and hope they register well enough. This new commit does that (and solves the overwrite). I am seeing problems when feeding the output from this into gpcl due to the delta compression. We believe this is a bug in gpcl, and is being investigated as bug 699969.
Diffstat (limited to 'source')
-rw-r--r--source/fitz/output-pcl.c210
1 files changed, 115 insertions, 95 deletions
diff --git a/source/fitz/output-pcl.c b/source/fitz/output-pcl.c
index c25c59ff..cb405d6b 100644
--- a/source/fitz/output-pcl.c
+++ b/source/fitz/output-pcl.c
@@ -487,6 +487,12 @@ pcl_header(fz_context *ctx, fz_output *out, fz_pcl_options *pcl, int num_copies,
/* Set resolution. */
fz_write_printf(ctx, out, "\033*t%dR", xres);
+
+ /* Raster units */
+ /* 96,100,120,144,150,160,180,200,225,240,288,300,360,400,450,480,600,720,800,900,1200,1440,1800,2400,3600,7200 */
+ /* FIXME: xres vs yres */
+ fz_write_printf(ctx, out, "\033&u%dD", xres);
+
pcl->page_count++;
}
@@ -721,11 +727,8 @@ typedef struct color_pcl_band_writer_s
fz_band_writer super;
fz_pcl_options options;
unsigned char *linebuf;
- unsigned char *compbuf;
- unsigned char *prev;
- unsigned char *curr;
- int fill;
- int seed_valid;
+ unsigned char compbuf[32768];
+ unsigned char compbuf2[32768];
} color_pcl_band_writer;
static void
@@ -749,11 +752,6 @@ color_pcl_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colors
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);
- writer->prev = writer->linebuf;
- writer->curr = writer->linebuf + w * 3;
- writer->fill = 0;
- writer->seed_valid = 0;
guess_paper_size(&writer->options, w, h, xres, yres);
@@ -778,73 +776,50 @@ color_pcl_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colors
/* Supposed to be strictly 75, 100, 150, 200, 300, 600 */
/* FIXME: xres vs yres */
fz_write_printf(ctx, out, "\033*t%dR", xres);
+}
- /* Raster height */
- fz_write_printf(ctx, out, "\033*r%dT", h);
-
- /* Raster width */
- fz_write_printf(ctx, out, "\033*r%dS", w);
-
- /* start raster graphics */
- /* 0 = start at default left graphics margin */
- fz_write_string(ctx, out, "\033*r0A");
-
- /* Now output the actual bitmap */
- /* Adaptive Compression */
- fz_write_string(ctx, out, "\033*b5M");
+static void flush_if_not_room(fz_context *ctx, fz_output *out, const unsigned char *comp, int *fill, int len)
+{
+ if (len + *fill >= 32767)
+ {
+ /* Can't fit any data, so flush */
+ fz_write_printf(ctx, out, "\033*b%dW", *fill);
+ fz_write_data(ctx, out, comp, *fill);
+ *fill = 0;
+ }
}
static void
-color_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_start, int band_height, const unsigned char *sp)
+color_pcl_compress_column(fz_context *ctx, color_pcl_band_writer *writer, const unsigned char *sp, int w, int h, int stride)
{
- color_pcl_band_writer *writer = (color_pcl_band_writer *)writer_;
fz_output *out = writer->super.out;
- int w = writer->super.w;
- int h = writer->super.h;
- int y, ss, ds, seed_valid, fill;
- unsigned char *prev;
- unsigned char *curr;
- unsigned char *comp;
-
- if (!out)
- return;
-
- ds = w * 3;
- ss = w * 3;
-
- prev = writer->prev;
- curr = writer->curr;
- fill = writer->fill;
- comp = writer->compbuf;
- seed_valid = writer->seed_valid;
-
- if (band_start+band_height >= h)
- band_height = h - band_start;
-
- y = 0;
- while (y < band_height)
+ int ss = w * 3;
+ int seed_valid = 0;
+ int fill = 0;
+ int y = 0;
+ unsigned char *prev = writer->linebuf + w * 3;
+ unsigned char *curr = writer->linebuf;
+ unsigned char *comp = writer->compbuf;
+ unsigned char *comp2 = writer->compbuf2;
+
+ while (y < h)
{
/* Skip over multiple blank lines */
int blanks;
do
{
blanks = 0;
- while (blanks < 32767 && y < band_height)
+ while (blanks < 32767 && y < h)
{
if (!line_is_blank(curr, sp, w))
break;
blanks++;
+ y++;
}
if (blanks)
{
- if (fill + 3 >= 32767)
- {
- /* Can't fit into the block, so flush */
- fz_write_printf(ctx, out, "\033*b%dW", fill);
- fz_write_data(ctx, out, comp, fill);
- fill = 0;
- }
+ flush_if_not_room(ctx, out, comp, &fill, 3);
comp[fill++] = 4; /* Empty row */
comp[fill++] = blanks>>8;
comp[fill++] = blanks & 0xFF;
@@ -853,11 +828,11 @@ color_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int b
}
while (blanks == 32767);
- if (y == band_height)
+ if (y == h)
break;
/* So, at least 1 more line to copy, and it's in curr */
- if (seed_valid && fill + 5 <= 32767 && memcmp(curr, prev, ds) == 0)
+ if (seed_valid && memcmp(curr, prev, ss) == 0)
{
int count = 1;
sp += stride;
@@ -870,6 +845,7 @@ color_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int b
sp += stride;
y++;
}
+ flush_if_not_room(ctx, out, comp, &fill, 3);
comp[fill++] = 5; /* Duplicate row */
comp[fill++] = count>>8;
comp[fill++] = count & 0xFF;
@@ -879,43 +855,34 @@ color_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int b
unsigned char *tmp;
int len = 0;
+ /* Compress the line into our fixed buffer. */
if (seed_valid)
- len = delta_compression(curr, prev, &comp[fill+3], ds, fz_mini(ds, 32767 - fill - len - 3));
-
- if (fill + len + 3 > 32767)
- {
- /* Can't fit this into the block, so flush and send uncompressed */
- fz_write_printf(ctx, out, "\033*b%dW", fill);
- fz_write_data(ctx, out, comp, fill);
- fill = 0;
- len = 0;
- }
+ len = delta_compression(curr, prev, comp2, ss, fz_mini(ss-1, 32767-3));
- if (len)
+ if (len > 0)
{
- /* Delta compression - Data already in the buffer. */
+ /* Delta compression */
+ flush_if_not_room(ctx, out, comp, &fill, len+3);
comp[fill++] = 3; /* Delta compression */
comp[fill++] = len>>8;
comp[fill++] = len & 0xFF;
+ memcpy(&comp[fill], comp2, len);
fill += len;
}
else
{
- if (fill + ds + 3 > 32767)
- {
- /* Can't fit a line uncompressed, so flush */
- fz_write_printf(ctx, out, "\033*b%dW", fill);
- fz_write_data(ctx, out, comp, fill);
- fill = 0;
- }
+ flush_if_not_room(ctx, out, comp, &fill, 3 + ss);
+
+ /* PCL requires that all rows MUST fit in at most 1 block, so
+ * we are carefully sending columns that are only so wide. */
/* Unencoded */
- /* Transfer Raster Data: ds+3 bytes, 0 = Unencoded, count high, count low */
+ /* Transfer Raster Data: ss+3 bytes, 0 = Unencoded, count high, count low */
comp[fill++] = 0;
- comp[fill++] = ds>>8;
- comp[fill++] = ds & 0xFF;
- memcpy(&comp[fill], curr, ds);
- fill += ds;
+ comp[fill++] = ss>>8;
+ comp[fill++] = ss & 0xFF;
+ memcpy(&comp[fill], curr, ss);
+ fill += ss;
seed_valid = 1;
}
@@ -925,28 +892,82 @@ color_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int b
y++;
}
}
+ /* And flush */
+ if (fill) {
+ fz_write_printf(ctx, out, "\033*b%dW", fill);
+ fz_write_data(ctx, out, comp, fill);
+ }
- writer->prev = prev;
- writer->curr = curr;
- writer->fill = fill;
- writer->compbuf = comp;
- writer->seed_valid = seed_valid;
+ /* End Raster Graphics */
+ fz_write_string(ctx, out, "\033*rC");
}
static void
-color_pcl_write_trailer(fz_context *ctx, fz_band_writer *writer_)
+color_pcl_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_start, int band_height, const unsigned char *sp)
{
color_pcl_band_writer *writer = (color_pcl_band_writer *)writer_;
fz_output *out = writer->super.out;
+ int w = writer->super.w;
+ int h = writer->super.h;
+ int xres = writer->super.xres;
+ int yres = writer->super.yres;
+ int y = 0;
+ int cw;
+ int x;
+
+ if (!out)
+ return;
+
+ if (band_start+band_height >= h)
+ band_height = h - band_start;
+
+ /* We have to specify image output size in decipoints (720dpi).
+ * Most usual PCL resolutions are a multiple of 75.
+ * Pick our maximum column size to be 10800 = 15*720 = 144*75
+ * to give us good results. 10800 * 3 = 32400 < 32760 */
+ cw = 10800; /* Limited by how much rowdata we can send at once */
+ if (cw > w)
+ cw = w;
- if (writer->fill)
+ for (x = 0; x*cw < w; x++)
{
- fz_write_printf(ctx, out, "\033*b%dW", writer->fill);
- fz_write_data(ctx, out, writer->compbuf, writer->fill);
+ int col_w = w - cw*x;
+ if (col_w > cw)
+ col_w = cw;
+
+ /* Top left corner */
+ fz_write_printf(ctx, out, "\033*p%dx%dY", x*cw, band_start);
+
+ /* Raster height */
+ fz_write_printf(ctx, out, "\033*r%dT", band_height);
+
+ /* Raster width */
+ fz_write_printf(ctx, out, "\033*r%dS", col_w);
+
+ /* Destination height */
+ fz_write_printf(ctx, out, "\033*t%dV", band_height*720/xres);
+
+ /* Destination width */
+ fz_write_printf(ctx, out, "\033*t%dH", col_w*720/xres);
+
+ /* start raster graphics */
+ /* 1 = start at cursor position */
+ fz_write_string(ctx, out, "\033*r3A");
+
+ /* Now output the actual bitmap */
+ /* Adaptive Compression */
+ fz_write_string(ctx, out, "\033*b5M");
+
+ color_pcl_compress_column(ctx, writer, sp + x * cw * 3, col_w, band_height, stride);
}
+}
+
+static void
+color_pcl_write_trailer(fz_context *ctx, fz_band_writer *writer_)
+{
+ color_pcl_band_writer *writer = (color_pcl_band_writer *)writer_;
+ fz_output *out = writer->super.out;
- /* End Raster Graphics */
- fz_write_string(ctx, out, "\033*rC");
}
static void
@@ -954,7 +975,6 @@ color_pcl_drop_band_writer(fz_context *ctx, fz_band_writer *writer_)
{
color_pcl_band_writer *writer = (color_pcl_band_writer *)writer_;
- fz_free(ctx, writer->compbuf);
fz_free(ctx, writer->linebuf);
}