summaryrefslogtreecommitdiff
path: root/base/sdctd.c
diff options
context:
space:
mode:
authorKen Sharp <ken.sharp@artifex.com>2018-01-22 15:20:29 +0000
committerKen Sharp <ken.sharp@artifex.com>2018-01-22 15:20:29 +0000
commiteb5d417375e1c7052aeb9f2532d34573bfd07f53 (patch)
tree38f254b734af60cdf6ec62d8e0c8db9c82f6f68e /base/sdctd.c
parentf858f560061560cbd3670509206dfdd98fea4d07 (diff)
downloadghostpdl-eb5d417375e1c7052aeb9f2532d34573bfd07f53.tar.gz
Feature - JPEG Pass through
This commit adds the capability for the PostScript and PDF interpreters to pass JPEG compressed image data directly to a device (currently the pdfwrite family of devices) as the original JPEG data. This allows us to avoid the compression artefacts caused by decompressing JPEG image data, and then applying JPEG compression again. This works by having the JPEG decoder inquire (via spec_op) if the current device would like the original uncompressed data. If so then it instructs the JPEG stream decoder to call a routine which will use more spec_ops to pass the uncompressed data to the device. The interpreter still calls the image methods with the decompressed data, its up to the device to ignore these calls while handling JPEG pass-through. We have to work this way in PostScript, as we must decompress the data as it arrives in order to find the end of the DCT compressed data. In addition, this allows the device to change its mind about accepting compressed data directly if it discovers from the image data that it is not suitable for preserving unchanged. This approach does not work with the PXL and XPS interpreters. These interpreters appear to completely decompress the JPEG data before starting an image, unlike the PostScript and PDF interpreters where the image methods are called as the stream is decopressed. As a result this feature is disabled for these interpreters.
Diffstat (limited to 'base/sdctd.c')
-rw-r--r--base/sdctd.c48
1 files changed, 45 insertions, 3 deletions
diff --git a/base/sdctd.c b/base/sdctd.c
index 3a3535e11..8d3308e3d 100644
--- a/base/sdctd.c
+++ b/base/sdctd.c
@@ -73,6 +73,13 @@ dctd_skip_input_data(j_decompress_ptr dinfo, long num_bytes)
static void
dctd_term_source(j_decompress_ptr dinfo)
{
+ jpeg_decompress_data *jddp =
+ (jpeg_decompress_data *) ((char *)dinfo -
+ offset_of(jpeg_decompress_data, dinfo));
+
+ if (jddp->PassThrough && jddp->PassThroughfn)
+ (jddp->PassThroughfn)(jddp->device, NULL, 0);
+ return;
}
/* Set the defaults for the DCTDecode filter. */
@@ -173,6 +180,7 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
jpeg_decompress_data *jddp = ss->data.decompress;
struct jpeg_source_mgr *src = jddp->dinfo.src;
int code;
+ byte *Buf;
if_debug3m('w', st->memory, "[wdd]process avail=%u, skip=%u, last=%d\n",
(uint) (pr->limit - pr->ptr), (uint) jddp->skip, last);
@@ -180,17 +188,25 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
long avail = pr->limit - pr->ptr;
if (avail < jddp->skip) {
+ if (jddp->PassThrough && jddp->PassThroughfn)
+ (jddp->PassThroughfn)(jddp->device, (byte *)pr->ptr + 1, (byte *)pr->limit - (byte *)pr->ptr);
+
jddp->skip -= avail;
pr->ptr = pr->limit;
if (!last)
return 0; /* need more data */
jddp->skip = 0; /* don't skip past input EOD */
}
+ Buf = (byte *)pr->ptr + 1;
pr->ptr += jddp->skip;
+ if (jddp->PassThrough && jddp->PassThroughfn)
+ (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
+
jddp->skip = 0;
}
src->next_input_byte = pr->ptr + 1;
src->bytes_in_buffer = pr->limit - pr->ptr;
+ Buf = (byte *)pr->ptr + 1;
jddp->input_eod = last;
switch (ss->phase) {
case 0: /* not initialized yet */
@@ -199,10 +215,17 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
* even though neither the standard nor Adobe's own
* documentation mention this.
*/
+ if (jddp->PassThrough && jddp->PassThroughfn && !jddp->StartedPassThrough) {
+ jddp->StartedPassThrough = 1;
+ (jddp->PassThroughfn)(jddp->device, NULL, 1);
+ }
while (pr->ptr < pr->limit && pr->ptr[1] != 0xff)
pr->ptr++;
- if (pr->ptr == pr->limit)
+ if (pr->ptr == pr->limit) {
+ if (jddp->PassThrough && jddp->PassThroughfn)
+ (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
return 0;
+ }
src->next_input_byte = pr->ptr + 1;
src->bytes_in_buffer = pr->limit - pr->ptr;
ss->phase = 1;
@@ -222,6 +245,8 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
(jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
switch (code) {
case JPEG_SUSPENDED:
+ if (jddp->PassThrough && jddp->PassThroughfn)
+ (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
return 0;
/*case JPEG_HEADER_OK: */
}
@@ -260,8 +285,11 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
return ERRC;
pr->ptr =
(jddp->faked_eoi ? pr->limit : src->next_input_byte - 1);
- if (code == 0)
+ if (code == 0) {
+ if (jddp->PassThrough && jddp->PassThroughfn)
+ (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
return 0;
+ }
ss->scan_line_size =
jddp->dinfo.output_width * jddp->dinfo.output_components;
if_debug4m('w', ss->memory, "[wdd]width=%u, components=%d, scan_line_size=%u, min_out_size=%u\n",
@@ -305,7 +333,12 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
((jddp->bytes_in_scanline == 0) && (tomove > 0) && /* 1 scancopy completed */
(avail < tomove) && /* still room for 1 more scan */
(jddp->dinfo.output_height > jddp->dinfo.output_scanline))) /* more scans to do */
+ {
+ if (jddp->PassThrough && jddp->PassThroughfn) {
+ (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
+ }
return 1; /* need more room */
+ }
}
/* while not done with image, decode 1 scan, otherwise fall into phase 4 */
while (jddp->dinfo.output_height > jddp->dinfo.output_scanline) {
@@ -315,8 +348,12 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
if (jddp->scanline_buffer != NULL)
samples = jddp->scanline_buffer;
else {
- if ((uint) (pw->limit - pw->ptr) < ss->scan_line_size)
+ if ((uint) (pw->limit - pw->ptr) < ss->scan_line_size) {
+ if (jddp->PassThrough && jddp->PassThroughfn) {
+ (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
+ }
return 1; /* need more room */
+ }
samples = pw->ptr + 1;
}
read = gs_jpeg_read_scanlines(ss, &samples, 1);
@@ -345,6 +382,9 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
(pr->limit - pr->ptr >= ss->templat->min_in_size) &&
(compact_jpeg_buffer(pr) == 0))
return ERRC;
+ if (jddp->PassThrough && jddp->PassThroughfn) {
+ (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
+ }
return 0; /* need more data */
}
if (jddp->scanline_buffer != NULL) {
@@ -356,6 +396,8 @@ s_DCTD_process(stream_state * st, stream_cursor_read * pr,
ss->phase = 4;
/* falls through */
case 4: /* end of image; scan for EOI */
+ if (jddp->PassThrough && jddp->PassThroughfn)
+ (jddp->PassThroughfn)(jddp->device, Buf, pr->ptr - (Buf - 1));
if ((code = gs_jpeg_finish_decompress(ss)) < 0)
return ERRC;
pr->ptr =