summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Resource/Init/gs_pdfwr.ps2
-rw-r--r--base/gxdevsop.h6
-rw-r--r--base/sdct.h10
-rw-r--r--base/sdctd.c48
-rw-r--r--devices/vector/gdevpdfb.h3
-rw-r--r--devices/vector/gdevpdfi.c76
-rw-r--r--devices/vector/gdevpdfj.c3
-rw-r--r--devices/vector/gdevpdfx.h4
-rw-r--r--devices/vector/gdevpsdf.h9
-rw-r--r--devices/vector/gdevpsdi.c8
-rw-r--r--devices/vector/gdevpsdp.c1
-rw-r--r--doc/VectorDevices.htm13
-rw-r--r--pcl/pxl/pximage.c6
-rw-r--r--pcl/pxl/pxvendor.c3
-rw-r--r--psi/int.mak3
-rw-r--r--psi/zfdctd.c32
-rw-r--r--xps/xpsjpeg.c3
-rw-r--r--xps/xpstiff.c3
-rw-r--r--xps/xpstile.c2
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, &params, pdev->params.GrayImage.Dict, pim, in_line);
}
+ pdev->JPEG_PassThrough = 0;
code = setup_downsampling(pbw, &params, pim, pgs, resolution, lossless);
} else {
adjust_auto_filter_strategy(pdev, &params, 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(&params, pim, resolution)) {
adjust_auto_filter_strategy(pdev, &params, pdev->params.ColorImage.Dict, pim, in_line);
+ pdev->JPEG_PassThrough = 0;
code = setup_downsampling(pbw, &params, pim, pgs, resolution, lossless);
} else {
adjust_auto_filter_strategy(pdev, &params, 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;