diff options
-rw-r--r-- | Resource/Init/gs_pdfwr.ps | 2 | ||||
-rw-r--r-- | base/gxdevsop.h | 6 | ||||
-rw-r--r-- | base/sdct.h | 10 | ||||
-rw-r--r-- | base/sdctd.c | 48 | ||||
-rw-r--r-- | devices/vector/gdevpdfb.h | 3 | ||||
-rw-r--r-- | devices/vector/gdevpdfi.c | 76 | ||||
-rw-r--r-- | devices/vector/gdevpdfj.c | 3 | ||||
-rw-r--r-- | devices/vector/gdevpdfx.h | 4 | ||||
-rw-r--r-- | devices/vector/gdevpsdf.h | 9 | ||||
-rw-r--r-- | devices/vector/gdevpsdi.c | 8 | ||||
-rw-r--r-- | devices/vector/gdevpsdp.c | 1 | ||||
-rw-r--r-- | doc/VectorDevices.htm | 13 | ||||
-rw-r--r-- | pcl/pxl/pximage.c | 6 | ||||
-rw-r--r-- | pcl/pxl/pxvendor.c | 3 | ||||
-rw-r--r-- | psi/int.mak | 3 | ||||
-rw-r--r-- | psi/zfdctd.c | 32 | ||||
-rw-r--r-- | xps/xpsjpeg.c | 3 | ||||
-rw-r--r-- | xps/xpstiff.c | 3 | ||||
-rw-r--r-- | xps/xpstile.c | 2 |
19 files changed, 226 insertions, 9 deletions
diff --git a/Resource/Init/gs_pdfwr.ps b/Resource/Init/gs_pdfwr.ps index b49eec43f..79fd6b75b 100644 --- a/Resource/Init/gs_pdfwr.ps +++ b/Resource/Init/gs_pdfwr.ps @@ -101,6 +101,7 @@ languagelevel 2 .setlanguagelevel /TransferFunctionInfo /Preserve /UseFlateCompression //true /UsePrologue //false + /PassThroughJPEGImages //true .dicttomark readonly def /.distillersettings mark @@ -829,6 +830,7 @@ currentdict /.pdf_hook_DSC_Creator undef /MaxSubsetPct { } /SubsetFonts { } /DSCEncodingToUnicode { } + /PassThroughJPEGImages { } /PSDocOptions { } /PSPageOptions { } .dicttomark readonly def diff --git a/base/gxdevsop.h b/base/gxdevsop.h index d9bc1d716..7ff411730 100644 --- a/base/gxdevsop.h +++ b/base/gxdevsop.h @@ -319,6 +319,12 @@ enum { /* Restrict the supplied bbox to that actually used by the underlying device. * Used to restrict alphabits drawing to the area defined by compositors etc.*/ gxdso_restrict_bbox, + /* JPEG passthrough requests/control. Currently used for the pdfwrite family only. + */ + gxdso_JPEG_passthrough_query, + gxdso_JPEG_passthrough_begin, + gxdso_JPEG_passthrough_data, + gxdso_JPEG_passthrough_end, /* Add new gxdso_ keys above this. */ gxdso_pattern__LAST }; diff --git a/base/sdct.h b/base/sdct.h index bdb93f453..46e27232a 100644 --- a/base/sdct.h +++ b/base/sdct.h @@ -82,6 +82,9 @@ extern_st(st_jpeg_compress_data); gs_public_st_ptrs1(st_jpeg_compress_data, jpeg_compress_data,\ "JPEG compress data", jpeg_compress_data_enum_ptrs, jpeg_compress_data_reloc_ptrs, dummy) +#define DCTD_PassThrough(proc)\ + int proc(void *d, byte *Buffer, int Size) + typedef struct jpeg_decompress_data_s { jpeg_stream_data_common; /* dinfo must immediately follow the common fields, */ @@ -93,6 +96,13 @@ typedef struct jpeg_decompress_data_s { bool faked_eoi; /* true when fill_input_buffer inserted EOI */ byte *scanline_buffer; /* buffer for oversize scanline, or NULL */ uint bytes_in_scanline; /* # of bytes remaining to output from same */ + int PassThrough; /* 0 or 1 */ + bool StartedPassThrough; /* Don't signal multiple starts for the same decode */ + DCTD_PassThrough((*PassThroughfn)); /* We don't want the stream code or + * JPEG code to have to handle devices + * so we use a function at the interpreter level + */ + void *device; /* The device we need to send PassThrough data to */ } jpeg_decompress_data; #define private_st_jpeg_decompress_data() /* in zfdctd.c */\ 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 = diff --git a/devices/vector/gdevpdfb.h b/devices/vector/gdevpdfb.h index d728c5e32..65470fdfd 100644 --- a/devices/vector/gdevpdfb.h +++ b/devices/vector/gdevpdfb.h @@ -284,5 +284,6 @@ const gx_device_pdf PDF_DEVICE_IDENT = false, /* FlattenFonts, writes text as outlines instead of fonts */ -1, /* Last Form ID, start with -1 which means 'none' */ 0, /* ExtensionMetadata */ - 0 /* PDFFormName */ + 0, /* PDFFormName */ + 0 /* PassThroughWriter */ }; diff --git a/devices/vector/gdevpdfi.c b/devices/vector/gdevpdfi.c index bc5128fd7..3a6402c5c 100644 --- a/devices/vector/gdevpdfi.c +++ b/devices/vector/gdevpdfi.c @@ -79,6 +79,7 @@ typedef struct pdf_image_enum_s { pdf_image_writer writer; gs_matrix mat; gs_color_space_index initial_colorspace; + int JPEG_PassThrough; } pdf_image_enum; gs_private_st_composite(st_pdf_image_enum, pdf_image_enum, "pdf_image_enum", pdf_image_enum_enum_ptrs, pdf_image_enum_reloc_ptrs); @@ -1018,6 +1019,21 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, break; case 3: + /* Currently we can't handle images with masks, because we have two + * image enumerators, and the JPEG passthrough is stored at the device + * level, not the enumerator level. This means that when we skip the + * image data (because its handled as JPEG) we also skip the mask data, + * which is no use at all. FIXME: not sure how but if possible I + * should fix this. Probably need to store the PassThrough in the + * enumerator, and then store a pointer to the enumerator in the + * device in place of the flag, so that when we get JPEG data supplied + * we know where to send it. Of course, that won't work if we ever end + * up in the situation where we have two JPEG sources at the same time..... + * That can probably be handled with some judicious work in the DCTDecode + * structure, to hold some reference to the particular stream that + * should get the data. But lets get the simple code working first. + */ + pdev->JPEG_PassThrough = 0; pdev->image_mask_is_SMask = false; if (pdev->CompatibilityLevel < 1.2 || (prect && !(prect->p.x == 0 && prect->p.y == 0 && @@ -1034,6 +1050,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, break; case IMAGE3X_IMAGETYPE: + pdev->JPEG_PassThrough = 0; gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), "pdf_begin_typed_image(image)"); if (pdev->CompatibilityLevel < 1.4 || @@ -1051,6 +1068,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, break; case 4: + pdev->JPEG_PassThrough = 0; code = convert_type4_image(pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pinfo, context, image, pnamed); if (code < 0) { @@ -1186,6 +1204,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, } if (use_fallback) { + pdev->JPEG_PassThrough = 0; gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), "pdf_begin_typed_image(image)"); return gx_default_begin_typed_image @@ -1204,6 +1223,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, else code = pdf_open_page(pdev, PDF_IN_STREAM); if (code < 0) { + pdev->JPEG_PassThrough = 0; gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), "pdf_begin_typed_image(image)"); return gx_default_begin_typed_image @@ -1226,6 +1246,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, else code = pdf_prepare_image(pdev, pgs); if (code < 0) { + pdev->JPEG_PassThrough = 0; gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), "pdf_begin_typed_image(image)"); return gx_default_begin_typed_image @@ -1328,6 +1349,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, if (!is_mask) { if (image[0].pixel.ColorSpace != NULL && !(context == PDF_IMAGE_TYPE3_MASK)) convert_to_process_colors = setup_image_colorspace(pdev, &image[0], pcs, &pcs_orig, names, &cs_value); + if (pim->BitsPerComponent > 8 && convert_to_process_colors) goto fail_and_fallback; if (convert_to_process_colors == 4) { @@ -1375,6 +1397,12 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, if (code < 0) goto fail_and_fallback; + if (pdev->params.TransferFunctionInfo == tfi_Apply && pdev->transfer_not_identity && !is_mask) + pdev->JPEG_PassThrough = 0; + +/* if (pdev->JPEG_PassThrough) + uncompressed = pie->writer.binary[0].strm;*/ + /* Code below here deals with setting up the multiple data stream writing. * We can have up to 4 stream writers, which we keep in an array. We must * always have at least one which writes the uncompressed stream. If we @@ -1387,6 +1415,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, * the streams which does the conversion. */ if (in_line) { + pdev->JPEG_PassThrough = 0; code = new_setup_lossless_filters((gx_device_psdf *) pdev, &pie->writer.binary[0], &image[0].pixel, in_line, convert_to_process_colors, (gs_matrix *)pmat, (gs_gstate *)pgs); @@ -1423,6 +1452,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, gs_color_space_index csi; if (pdev->params.TransferFunctionInfo == tfi_Apply && pdev->transfer_not_identity && !is_mask) { + pdev->JPEG_PassThrough = 0; csi = gs_color_space_get_index(image[0].pixel.ColorSpace); if (csi == gs_color_space_index_Indexed) { csi = gs_color_space_get_index(image[0].pixel.ColorSpace->base_space); @@ -1471,6 +1501,10 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, } } } + /* If we are not preserving the colour space unchanged, thenwe can't pass through JPEG */ + else + pdev->JPEG_PassThrough = 0; + if (convert_to_process_colors) { image[0].pixel.ColorSpace = pcs_orig; @@ -1481,6 +1515,17 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, image[0].pixel.ColorSpace = pcs_device; } + if (pdev->JPEG_PassThrough) { +/* if (pie->writer.alt_writer_count > 1) { + s_close_filters(&pie->writer.binary[0].strm, uncompressed); + memset(pie->writer.binary + 1, 0, sizeof(pie->writer.binary[1])); + memset(pie->writer.binary + 2, 0, sizeof(pie->writer.binary[1])); + }*/ + pdev->PassThroughWriter = pie->writer.binary[0].strm; + pie->writer.alt_writer_count = 1; + } + pie->JPEG_PassThrough = pdev->JPEG_PassThrough; + if (pie->writer.alt_writer_count > 1) { code = pdf_make_alt_stream(pdev, &pie->writer.binary[1]); if (code) { @@ -1563,6 +1608,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs, return 0; fail_and_fallback: + pdev->JPEG_PassThrough = 0; gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t), "pdf_begin_typed_image(image)"); gs_free_object(mem, pie, "pdf_begin_image"); @@ -1673,6 +1719,12 @@ pdf_image_plane_data(gx_image_enum_common_t * info, pdf_image_enum *pie = (pdf_image_enum *) info; int i; + if (pie->JPEG_PassThrough) { + pie->rows_left -= height; + *rows_used = height; + return 0; + } + for (i = 0; i < pie->writer.alt_writer_count; i++) { int code = pdf_image_plane_data_alt(info, planes, height, rows_used, i); if (code) @@ -2557,6 +2609,29 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size) * palette entries after the colour space has been set. */ return 1; + case gxdso_JPEG_passthrough_query: + pdev->JPEG_PassThrough = pdev->params.PassThroughJPEGImages; + return 1; + break; + case gxdso_JPEG_passthrough_begin: + return 0; + break; + case gxdso_JPEG_passthrough_data: + if (pdev->JPEG_PassThrough && pdev->PassThroughWriter) + { + uint ignore; + if (sputs(pdev->PassThroughWriter, + data, size, + &ignore) < 0) + return_error(gs_error_ioerror); + } + return 0; + break; + case gxdso_JPEG_passthrough_end: + pdev->JPEG_PassThrough = 0; + pdev->PassThroughWriter = 0; + return 0; + break; case gxdso_get_dev_param: { int code; @@ -2565,6 +2640,7 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size) if (code != gs_error_undefined) return code; } + /* Fall through */ } return gx_default_dev_spec_op(pdev1, dev_spec_op, data, size); } diff --git a/devices/vector/gdevpdfj.c b/devices/vector/gdevpdfj.c index 7ce74c952..42c04dfe7 100644 --- a/devices/vector/gdevpdfj.c +++ b/devices/vector/gdevpdfj.c @@ -409,6 +409,9 @@ pdf_begin_image_data(gx_device_pdf * pdev, pdf_image_writer * piw, COS_FREE(piw->data, "pdf_begin_image_data"); piw->data = 0; } + if (pdev->JPEG_PassThrough) { + CHECK(cos_dict_put_c_strings(pcd, "/Filter", "/DCTDecode")); + } return code; } diff --git a/devices/vector/gdevpdfx.h b/devices/vector/gdevpdfx.h index 6bf807661..fa998a420 100644 --- a/devices/vector/gdevpdfx.h +++ b/devices/vector/gdevpdfx.h @@ -889,6 +889,10 @@ struct gx_device_pdf_s { * after the form is processed. The name will be used to create a * local named object which pdfmark can reference. */ + stream *PassThroughWriter; /* A copy of the stream that the image enumerator points to, if we are + * doing JPEG pass through we write the JPEG data here, and don't write + * anything in the image processing routines. + */ }; #define is_in_page(pdev)\ diff --git a/devices/vector/gdevpsdf.h b/devices/vector/gdevpsdf.h index e0b624405..c7f42539f 100644 --- a/devices/vector/gdevpsdf.h +++ b/devices/vector/gdevpsdf.h @@ -174,6 +174,7 @@ typedef struct psdf_distiller_params_s { bool EmbedAllFonts; int MaxSubsetPct; bool SubsetFonts; + bool PassThroughJPEGImages; gs_param_string PSDocOptions; gs_param_string_array PSPageOptions; } psdf_distiller_params; @@ -263,7 +264,10 @@ extern const stream_template s_zlibE_template; cefp_Warning, /* CannotEmbedFontPolicy */ \ 1, /* EmbedAllFonts (true) */ \ 100, /* Max Subset Percent */ \ - 1 /* Subset Fonts (true) */\ + 1 /* Subset Fonts (true) */ + +#define psdf_JPEGPassThrough_param_defaults\ + 1 /* PassThroughJPEGImages */ #define psdf_PSOption_param_defaults\ {0}, /* PSDocOptions */\ @@ -288,6 +292,7 @@ typedef enum { bool HaveTrueTypes;\ bool HaveCIDSystem;\ double ParamCompatibilityLevel;\ + bool JPEG_PassThrough;\ psdf_distiller_params params typedef struct gx_device_psdf_s { @@ -302,11 +307,13 @@ typedef struct gx_device_psdf_s { true,\ false,\ 1.3,\ + 0,\ { psdf_general_param_defaults(ascii),\ psdf_color_image_param_defaults,\ psdf_gray_image_param_defaults,\ psdf_mono_image_param_defaults,\ psdf_font_param_defaults,\ + psdf_JPEGPassThrough_param_defaults,\ psdf_PSOption_param_defaults\ } /* st_device_psdf is never instantiated per se, but we still need to */ diff --git a/devices/vector/gdevpsdi.c b/devices/vector/gdevpsdi.c index c2b66c98b..5a655ed35 100644 --- a/devices/vector/gdevpsdi.c +++ b/devices/vector/gdevpsdi.c @@ -276,7 +276,7 @@ setup_image_compression(psdf_binary_writer *pbw, const psdf_image_params *pdip, templat = lossless_template; if (dict != NULL) /* Some interpreters don't supply filter parameters. */ gs_c_param_list_read(dict); /* ensure param list is in read mode */ - if (templat == 0) /* no compression */ + if (templat == 0 || pdev->JPEG_PassThrough) /* no compression */ return 0; if (pim->Width < 200 && pim->Height < 200) /* Prevent a fixed overflow. */ if (pim->Width * pim->Height * Colors * pim->BitsPerComponent <= 160) @@ -962,6 +962,10 @@ new_setup_image_filters(gx_device_psdf * pdev, psdf_binary_writer * pbw, if (resolutiony < resolution) resolution = resolutiony; } + + if (bpc != bpc_out) + pdev->JPEG_PassThrough = 0; + if (ncomp == 1 && pim->ColorSpace && pim->ColorSpace->type->index != gs_color_space_index_Indexed) { /* Monochrome, gray, or mask */ /* Check for downsampling. */ @@ -978,6 +982,7 @@ new_setup_image_filters(gx_device_psdf * pdev, psdf_binary_writer * pbw, params.Dict = pdev->params.GrayImage.Dict; adjust_auto_filter_strategy(pdev, ¶ms, pdev->params.GrayImage.Dict, pim, in_line); } + pdev->JPEG_PassThrough = 0; code = setup_downsampling(pbw, ¶ms, pim, pgs, resolution, lossless); } else { adjust_auto_filter_strategy(pdev, ¶ms, pdev->params.GrayImage.Dict, pim, in_line); @@ -992,6 +997,7 @@ new_setup_image_filters(gx_device_psdf * pdev, psdf_binary_writer * pbw, params.Depth = (colour_conversion ? 8 : bpc_out); if (do_downsample(¶ms, pim, resolution)) { adjust_auto_filter_strategy(pdev, ¶ms, pdev->params.ColorImage.Dict, pim, in_line); + pdev->JPEG_PassThrough = 0; code = setup_downsampling(pbw, ¶ms, pim, pgs, resolution, lossless); } else { adjust_auto_filter_strategy(pdev, ¶ms, pdev->params.ColorImage.Dict, pim, in_line); diff --git a/devices/vector/gdevpsdp.c b/devices/vector/gdevpsdp.c index 3582fdad9..178314bc0 100644 --- a/devices/vector/gdevpsdp.c +++ b/devices/vector/gdevpsdp.c @@ -254,6 +254,7 @@ static const gs_param_item_t psdf_param_items[] = { pi("EmbedAllFonts", gs_param_type_bool, EmbedAllFonts), pi("MaxSubsetPct", gs_param_type_int, MaxSubsetPct), pi("SubsetFonts", gs_param_type_bool, SubsetFonts), + pi("PassThroughJPEGImages", gs_param_type_bool, PassThroughJPEGImages), #undef pi gs_param_item_end diff --git a/doc/VectorDevices.htm b/doc/VectorDevices.htm index 92149446a..759229677 100644 --- a/doc/VectorDevices.htm +++ b/doc/VectorDevices.htm @@ -364,6 +364,7 @@ Cells in the table below containing '=' mean that the value of the parameter is <tr valign=top><td><code>UCRandBGInfo</code><td><td><td><td>/Remove<td><td>/Remove<td><td>/Remove<td><td>/Preserve<td><td>/Preserve <tr valign=top><td><code>UseFlateCompression</code><td><td><a href="#note_2">(2)</a><td><td>true<td><td>=<td><td>=<td><td>=<td><td>= <tr valign=top><td><code>UsePrologue</code><td><td><a href="#note_0">(0)</a><td><td>false<td><td>=<td><td>=<td><td>=<td><td>= +<tr valign=top><td><code>PassThroughJPEGImages</code><td><td><a href="#note_15">(15)</a><td><td>true<td><td>=<td><td>=<td><td>=<td><td>= </table></blockquote> <p> @@ -506,7 +507,17 @@ in.ps</code></blockquote> <p> <a name="note_14">(note 14)</a> -The default value of CompressPages is <code>false</code> for ps2write and eps2write. +The default value of <code>CompressPages</code> is <code>false</code> for ps2write and eps2write. + +<p> +<a name="note_15">(note 15)</a> +When <code>true</code> image data in the source which is encoded using the DCT (JPEG) filter will not be decompressed +and then recompressed on output. This prevents the multiplication of JPEG artefacts caused by lossy compression. +</code><code>PassThroughJPEGImages</code> currently only affects simple JPEG images. It has no effect on JPX (JPEG2000) encoded images, +or masked images. In addition this parameter will be ignored if the pdfwrite device needs to modify the source data. This can happen if the image +is being downsampled, changing colour space or havign transfer functions applied. Note that this parameter essentially overrides +the 'EncodeColorImages' and 'EncodeGrayImages' parameters if they are false, the image will still be written with a DCTDecode filter. NB this +feature currently only works with PostScript or PDF input, it does not work with PCL, PXL or XPS input. <h4><a name="Color_Conversion_and_Management"></a>Color Conversion and Management</h4> <p> diff --git a/pcl/pxl/pximage.c b/pcl/pxl/pximage.c index 5ef04ec5c..4a4fba310 100644 --- a/pcl/pxl/pximage.c +++ b/pcl/pxl/pximage.c @@ -182,6 +182,9 @@ px_jpeg_init(px_bitmap_enum_t * benum, px_bitmap_params_t * params, px_args_t * jddp->templat = s_DCTD_template; jddp->memory = benum->mem; jddp->scanline_buffer = NULL; + jddp->PassThrough = 0; + jddp->PassThroughfn = 0; + jddp->device = (void *)0; if (gs_jpeg_create_decompress(ss) < 0) return_error(errorInsufficientMemory); @@ -342,6 +345,9 @@ read_jpeg_bitmap_data(px_bitmap_enum_t * benum, byte ** pdata, jddp->memory = ss->jpeg_memory = benum->mem; /* set this early for safe error exit */ jddp->scanline_buffer = NULL; + jddp->PassThrough = 0; + jddp->PassThroughfn = 0; + jddp->device = (void *)0; if (gs_jpeg_create_decompress(ss) < 0) return_error(errorInsufficientMemory); (*s_DCTD_template.init) ((stream_state *) ss); diff --git a/pcl/pxl/pxvendor.c b/pcl/pxl/pxvendor.c index d6641c075..4ecc096f5 100644 --- a/pcl/pxl/pxvendor.c +++ b/pcl/pxl/pxvendor.c @@ -510,6 +510,9 @@ read_headless_jpeg_bitmap_data(byte ** pdata, jddp->memory = ss->jpeg_memory = pxs->memory; /* set this early for safe error exit */ jddp->scanline_buffer = NULL; + jddp->PassThrough = 0; + jddp->PassThroughfn = 0; + jddp->device = (void *)0; if (gs_jpeg_create_decompress(ss) < 0) return_error(errorInsufficientMemory); (*s_DCTD_template.init) ((stream_state *) ss); diff --git a/psi/int.mak b/psi/int.mak index 7c090c33d..d75f6a7f8 100644 --- a/psi/int.mak +++ b/psi/int.mak @@ -1597,7 +1597,8 @@ $(PSD)dctd.dev : $(ECHOGS_XE) $(GLD)sdctd.dev $(GLD)sddparam.dev\ $(PSOBJ)zfdctd.$(OBJ) : $(PSSRC)zfdctd.c $(OP)\ $(memory__h) $(stdio__h) $(jpeglib__h) $(gsmemory_h)\ $(ialloc_h) $(ifilter_h) $(iparam_h) $(sdct_h) $(sjpeg_h)\ - $(strimpl_h) $(INT_MAK) $(MAKEDIRS) + $(strimpl_h) $(igstate_h) $(gxdevcli_h) $(gxdevsop_h)\ + $(INT_MAK) $(MAKEDIRS) $(PSCC) $(PSO_)zfdctd.$(OBJ) $(C_) $(PSSRC)zfdctd.c # ================ Display PostScript ================ # diff --git a/psi/zfdctd.c b/psi/zfdctd.c index f69465d0b..754a73569 100644 --- a/psi/zfdctd.c +++ b/psi/zfdctd.c @@ -28,6 +28,10 @@ #include "ifilter.h" #include "iparam.h" +#include "igstate.h" /* For igs macro */ +#include "gxdevcli.h" /* for dev_spec_op */ +#include "gxdevsop.h" /* For spec_op enumerated types */ + private_st_jpeg_decompress_data(); /* Import the parameter processing procedure from sddparam.c */ @@ -48,6 +52,21 @@ find_stream_memory(i_ctx_t *i_ctx_p, int npop, uint *space) return idmemory->spaces_indexed[*space >> r_space_shift]; } +static int PS_DCTD_PassThrough(void *d, byte *Buffer, int Size) +{ + gx_device *dev = (gx_device *)d; + + if (Buffer == NULL) { + if (Size == 0) + dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_end, NULL, 0); + else + dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_begin, NULL, 0); + } else { + dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_data, Buffer, Size); + } + return 0; +} + /* <source> <dict> DCTDecode/filter <file> */ /* <source> DCTDecode/filter <file> */ static int @@ -61,6 +80,7 @@ zDCTD(i_ctx_t *i_ctx_p) int code; const ref *dop; uint dspace; + gx_device *dev = gs_currentdevice(igs); if (r_has_type(op, t_dictionary)) dop = op, dspace = r_space(op); @@ -86,6 +106,18 @@ zDCTD(i_ctx_t *i_ctx_p) goto fail; if ((code = s_DCTD_put_params((gs_param_list *) & list, &state)) < 0) goto rel; + + if (dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_query, NULL, 0) > 0) { + jddp->StartedPassThrough = 0; + jddp->PassThrough = 1; + jddp->PassThroughfn = (PS_DCTD_PassThrough); + jddp->device = (void *)dev; + } + else { + jddp->PassThrough = 0; + jddp->device = (void *)NULL; + } + /* Create the filter. */ jddp->templat = s_DCTD_template; code = filter_read(i_ctx_p, 0, &jddp->templat, diff --git a/xps/xpsjpeg.c b/xps/xpsjpeg.c index d419ed121..96f6c9714 100644 --- a/xps/xpsjpeg.c +++ b/xps/xpsjpeg.c @@ -55,6 +55,9 @@ xps_decode_jpeg(xps_context_t *ctx, byte *rbuf, int rlen, xps_image_t *image) jddp.templat = s_DCTD_template; jddp.memory = ctx->memory; jddp.scanline_buffer = NULL; + jddp.PassThrough = 0; + jddp.device = (void *)NULL; + jddp.PassThroughfn = 0; if ((code = gs_jpeg_create_decompress(&state)) < 0) return gs_throw(-1, "cannot gs_jpeg_create_decompress"); diff --git a/xps/xpstiff.c b/xps/xpstiff.c index 79aaed8a9..5c7d4e36e 100644 --- a/xps/xpstiff.c +++ b/xps/xpstiff.c @@ -383,6 +383,9 @@ xps_decode_tiff_jpeg(xps_context_t *ctx, xps_tiff_t *tiff, byte *rp, byte *rl, b jddp.templat = s_DCTD_template; jddp.memory = ctx->memory; jddp.scanline_buffer = NULL; + jddp.PassThrough = 0; + jddp.PassThroughfn = 0; + jddp.device = (void *)0; if ((code = gs_jpeg_create_decompress(&state)) < 0) return gs_throw(-1, "error in gs_jpeg_create_decompress"); diff --git a/xps/xpstile.c b/xps/xpstile.c index 4532a06d9..454c90e31 100644 --- a/xps/xpstile.c +++ b/xps/xpstile.c @@ -199,7 +199,7 @@ xps_high_level_pattern(xps_context_t *ctx) static int xps_remap_pattern(const gs_client_color *pcc, gs_gstate *pgs) { - const gs_client_pattern *ppat = gs_getpattern(pcc); + gs_client_pattern *ppat = (gs_client_pattern *)gs_getpattern(pcc); struct tile_closure_s *c = ppat->client_data; xps_context_t *ctx = c->ctx; int code; |