summaryrefslogtreecommitdiff
path: root/source/fitz/output-pcl.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2016-03-24 11:03:52 +0000
committerRobin Watts <robin.watts@artifex.com>2016-03-25 14:28:46 +0000
commitbcfb276b494c7b1825527d14c9bcd4d3736a2ffd (patch)
treeca74d5f6c3be75c7633472f7c1b0d1b48cb60a18 /source/fitz/output-pcl.c
parentd111a26ca8911ff39b251b23e6587f5c0355b6d2 (diff)
downloadmupdf-bcfb276b494c7b1825527d14c9bcd4d3736a2ffd.tar.xz
Add 24 bit RGB PCL output mode.
Output uses adaptive compression mode.
Diffstat (limited to 'source/fitz/output-pcl.c')
-rw-r--r--source/fitz/output-pcl.c290
1 files changed, 237 insertions, 53 deletions
diff --git a/source/fitz/output-pcl.c b/source/fitz/output-pcl.c
index 65fff2fa..57116b79 100644
--- a/source/fitz/output-pcl.c
+++ b/source/fitz/output-pcl.c
@@ -583,93 +583,277 @@ 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 it line
+ * was blank. */
+static int
+line_is_blank(unsigned char *dst, const unsigned char *sp, int w)
+{
+ int zero = 0;
+
+ while (w-- > 0)
+ {
+ zero |= (*dst++ = *sp++);
+ zero |= (*dst++ = *sp++);
+ zero |= (*dst++ = *sp++);
+ sp++;
+ }
+
+ return zero == 0;
+}
+
+static int
+delta_compression(unsigned char *curr, unsigned char *prev, unsigned char *comp, int ds, int space)
+{
+ int left = space;
+ int x = ds;
+
+ while (x > 0)
+ {
+ /* Count matching bytes */
+ int match = 0;
+ int diff = 0;
+ while (x > 0 && *curr == *prev)
+ {
+ curr++;
+ prev++;
+ match++;
+ x--;
+ }
+
+ /* Count different bytes */
+ while (x > 0 && *curr != *prev)
+ {
+ curr++;
+ prev++;
+ diff++;
+ x--;
+ }
+
+ while (diff > 0)
+ {
+ int exts;
+ int mini_diff = diff;
+ if (mini_diff > 8)
+ mini_diff = 8;
+
+ exts = (match+255-31)/255;
+ left -= 1 + mini_diff + exts;
+ if (left < 0)
+ return 0;
+ *comp++ = ((mini_diff-1)<<5) | (match < 31 ? match : 31);
+ if (exts > 0)
+ {
+ match -= 31;
+ while (--exts)
+ {
+ *comp++ = 255;
+ match -= 255;
+ }
+ *comp++ = match;
+ }
+ memcpy(comp, curr-diff, mini_diff);
+ comp += mini_diff;
+
+ match = 0;
+ diff -= mini_diff;
+ }
+ }
+ return space - left;
+}
+
void
fz_write_pixmap_as_pcl(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap, fz_pcl_options *pcl)
{
unsigned char *sp;
- int y, x, sn, dn, ss;
+ int y, ss, ds, valid_seed, fill;
+ unsigned char *linebuf;
+ unsigned char *prev;
+ unsigned char *curr;
+ unsigned char *comp = NULL;
if (!out || !pixmap)
return;
- if (pixmap->n != 1 && pixmap->n != 2 && pixmap->n != 4)
- fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or rgb to write as pcl");
+ if (pixmap->n != 4)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be rgb to write as pcl");
guess_paper_size(pcl, pixmap->w, pixmap->h, pixmap->xres, pixmap->yres);
pcl_header(ctx, out, pcl, 1, pixmap->xres, pixmap->yres, pixmap->w, pixmap->h);
- sn = pixmap->n;
- dn = pixmap->n;
- if (dn == 2 || dn == 4)
- dn--;
+ /* Raster presentation */
+ /* Print in orientation of the logical page */
+ fz_printf(ctx, out, "\033&r0F");
- /* Now output the actual bitmap, using a packbits like compression */
- sp = pixmap->samples;
- ss = pixmap->w * sn;
- y = 0;
- while (y < pixmap->h)
- {
- int yrep;
+ /* Set color mode */
+ fz_write(ctx, out, "\033*v6W"
+ "\000" /* Colorspace 0 = Device RGB */
+ "\003" /* Pixel encoding mode: 3 = Direct by Pixel*/
+ "\000" /* Bits per index: 0 = no palette */
+ "\010" /* Red bits */
+ "\010" /* Green bits */
+ "\010", /* Blue bits */
+ 11
+ );
- assert(sp == pixmap->samples + y * ss);
+ /* Raster resolution */
+ /* Supposed to be strictly 75, 100, 150, 200, 300, 600 */
+ /* FIXME: xres vs yres */
+ fz_printf(ctx, out, "\033*t%dR", pixmap->xres);
- /* Count the number of times this line is repeated */
- for (yrep = 1; yrep < 256 && y+yrep < pixmap->h; yrep++)
- {
- if (memcmp(sp, sp + yrep * ss, ss) != 0)
- break;
- }
- fz_write_byte(ctx, out, yrep-1);
+ /* Raster height */
+ fz_printf(ctx, out, "\033*r%dT", pixmap->h);
- /* Encode the line */
- x = 0;
- while (x < pixmap->w)
- {
- int d;
+ /* Raster width */
+ fz_printf(ctx, out, "\033*r%dS", pixmap->w);
+
+ /* start raster graphics */
+ /* 0 = start at default left graphics margin */
+ fz_printf(ctx, out, "\033*r0A");
- assert(sp == pixmap->samples + y * ss + x * sn);
+ ds = pixmap->w * 3;
+ ss = pixmap->w * 4;
- /* How far do we have to look to find a repeated value? */
- for (d = 1; d < 128 && x+d < pixmap->w; d++)
+ linebuf = fz_malloc(ctx, ds * 2);
+ prev = linebuf;
+ curr = linebuf + ds;
+ fill = 0;
+ memset(prev, 0, ds);
+
+ fz_var(comp);
+
+ fz_try(ctx)
+ {
+ comp = fz_malloc(ctx, 32767);
+ /* Now output the actual bitmap */
+ /* Adaptive Compression */
+ fz_printf(ctx, out, "\033*b5M");
+
+ sp = pixmap->samples;
+ y = 0;
+ valid_seed = 0;
+ while (y < pixmap->h)
+ {
+ /* Skip over multiple blank lines */
+ int blanks;
+ do
{
- if (memcmp(sp + (d-1)*sn, sp + d*sn, sn) == 0)
- break;
+ blanks = 0;
+ while (blanks < 32767 && y < pixmap->h)
+ {
+ if (!line_is_blank(curr, sp, pixmap->w))
+ break;
+ blanks++;
+ }
+
+ if (blanks)
+ {
+ if (fill + 3 >= 32767)
+ {
+ /* Can't fit into the block, so flush */
+ fz_printf(ctx, out, "\033*b%dW", fill);
+ fz_write(ctx, out, comp, fill);
+ fill = 0;
+ }
+ comp[fill++] = 4; /* Empty row */
+ comp[fill++] = blanks>>8;
+ comp[fill++] = blanks & 0xFF;
+ valid_seed = 0;
+ }
}
- if (d == 1)
- {
- int xrep;
+ while (blanks == 32767);
- /* 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 < pixmap->w; xrep++)
+ if (y == pixmap->h)
+ break;
+
+ /* So, at least 1 more line to copy, and it's in curr */
+ if (valid_seed && fill + 5 <= 32767 && memcmp(curr, prev, ds) == 0)
+ {
+ int count = 1;
+ sp += ss;
+ y++;
+ while (count < 32767 && y < pixmap->h)
{
- if (memcmp(sp, sp + xrep*sn, sn) != 0)
+ if (memcmp(sp-ss, sp, ss) != 0)
break;
+ count++;
+ sp += ss;
+ y++;
}
- fz_write_byte(ctx, out, xrep-1);
- fz_write(ctx, out, sp, dn);
- sp += sn*xrep;
- x += xrep;
+ comp[fill++] = 5; /* Duplicate row */
+ comp[fill++] = count>>8;
+ comp[fill++] = count & 0xFF;
}
else
{
- fz_write_byte(ctx, out, 257-d);
- x += d;
- while (d > 0)
+ unsigned char *tmp;
+ int len = 0;
+
+ if (valid_seed)
+ 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_printf(ctx, out, "\033*b%dW", fill);
+ fz_write(ctx, out, comp, fill);
+ fill = 0;
+ len = 0;
+ }
+
+ if (len)
{
- fz_write(ctx, out, sp, dn);
- sp += sn;
- d--;
+ /* Delta compression - Data already in the buffer. */
+ comp[fill++] = 3; /* Delta compression */
+ comp[fill++] = len>>8;
+ comp[fill++] = len & 0xFF;
+ fill += len;
}
+ else
+ {
+ if (fill + ds + 3 > 32767)
+ {
+ /* Can't fit a line uncompressed, so flush */
+ fz_printf(ctx, out, "\033*b%dW", fill);
+ fz_write(ctx, out, comp, fill);
+ fill = 0;
+ }
+
+ /* Unencoded */
+ /* Transfer Raster Data: ds+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;
+ valid_seed = 1;
+ }
+
+ /* curr becomes prev */
+ tmp = prev; prev = curr; curr = tmp;
+ sp += ss;
+ y++;
}
}
- /* Move to the next line */
- sp += ss*(yrep-1);
- y += yrep;
+ if (fill)
+ {
+ fz_printf(ctx, out, "\033*b%dW", fill);
+ fz_write(ctx, out, comp, fill);
+ }
}
+ fz_always(ctx)
+ {
+ fz_free(ctx, linebuf);
+ fz_free(ctx, comp);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+
+ /* End Raster Graphics */
+ fz_printf(ctx, out, "\033*rC");
}
/*