diff options
author | Ken Sharp <ken.sharp@artifex.com> | 2018-01-22 15:20:29 +0000 |
---|---|---|
committer | Ken Sharp <ken.sharp@artifex.com> | 2018-01-22 15:20:29 +0000 |
commit | eb5d417375e1c7052aeb9f2532d34573bfd07f53 (patch) | |
tree | 38f254b734af60cdf6ec62d8e0c8db9c82f6f68e /base/sdctd.c | |
parent | f858f560061560cbd3670509206dfdd98fea4d07 (diff) | |
download | ghostpdl-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.c | 48 |
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 = |