summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'devices/vector/gdevpdfi.c')
-rw-r--r--devices/vector/gdevpdfi.c512
1 files changed, 291 insertions, 221 deletions
diff --git a/devices/vector/gdevpdfi.c b/devices/vector/gdevpdfi.c
index c6bdee9d..08e217fa 100644
--- a/devices/vector/gdevpdfi.c
+++ b/devices/vector/gdevpdfi.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2020 Artifex Software, Inc.
+/* Copyright (C) 2001-2021 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -958,6 +958,86 @@ static int setup_image_colorspace(gx_device_pdf *pdev, image_union_t *image, con
return 0;
}
+/* Basically, sets up the BBox for Eps2Write case */
+static int
+pdf_image_handle_eps(gx_device_pdf *pdev, const gs_gstate * pgs,
+ const gs_matrix *pmat, const gs_image_common_t *pic,
+ const gs_int_rect *prect,
+ const gx_clip_path * pcpath)
+{
+ int code = 0;
+ gs_rect sbox, dbox, *Box;
+ gs_point corners[4];
+ gs_fixed_rect ibox;
+ gs_matrix * pmat1 = (gs_matrix *)pmat;
+ gs_matrix mat;
+
+ if (!pdev->Eps2Write)
+ return 0;
+
+ if (!pdev->accumulating_charproc)
+ Box = &pdev->BBox;
+ else
+ Box = &pdev->charproc_BBox;
+ if (pmat1 == 0)
+ pmat1 = (gs_matrix *)&ctm_only(pgs);
+ if ((code = gs_matrix_invert(&pic->ImageMatrix, &mat)) < 0 ||
+ (code = gs_matrix_multiply(&mat, pmat1, &mat)) < 0)
+ goto exit;
+ sbox.p.x = prect->p.x;
+ sbox.p.y = prect->p.y;
+ sbox.q.x = prect->q.x;
+ sbox.q.y = prect->q.y;
+ gs_bbox_transform_only(&sbox, &mat, corners);
+ gs_points_bbox(corners, &dbox);
+ ibox.p.x = float2fixed(dbox.p.x);
+ ibox.p.y = float2fixed(dbox.p.y);
+ ibox.q.x = float2fixed(dbox.q.x);
+ ibox.q.y = float2fixed(dbox.q.y);
+ if (pcpath != NULL &&
+ !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
+ ibox.q.x, ibox.q.y)
+ ) {
+ /* Let the target do the drawing, but drive two triangles */
+ /* through the clipping path to get an accurate bounding box. */
+ gx_device_clip cdev;
+ gx_drawing_color devc;
+
+ fixed x0 = float2fixed(corners[0].x), y0 = float2fixed(corners[0].y);
+ fixed bx2 = float2fixed(corners[2].x) - x0, by2 = float2fixed(corners[2].y) - y0;
+
+ pdev->AccumulatingBBox++;
+ gx_make_clip_device_on_stack(&cdev, pcpath, (gx_device *)pdev);
+ set_nonclient_dev_color(&devc, gx_device_black((gx_device *)pdev)); /* any non-white color will do */
+ gx_default_fill_triangle((gx_device *) & cdev, x0, y0,
+ float2fixed(corners[1].x) - x0,
+ float2fixed(corners[1].y) - y0,
+ bx2, by2, &devc, lop_default);
+ gx_default_fill_triangle((gx_device *) & cdev, x0, y0,
+ float2fixed(corners[3].x) - x0,
+ float2fixed(corners[3].y) - y0,
+ bx2, by2, &devc, lop_default);
+ pdev->AccumulatingBBox--;
+ } else {
+ /* Just use the bounding box. */
+ float x0, y0, x1, y1;
+ x0 = fixed2float(ibox.p.x) / (pdev->HWResolution[0] / 72.0);
+ y0 = fixed2float(ibox.p.y) / (pdev->HWResolution[1] / 72.0);
+ x1 = fixed2float(ibox.q.x) / (pdev->HWResolution[0] / 72.0);
+ y1 = fixed2float(ibox.q.y) / (pdev->HWResolution[1] / 72.0);
+ if (Box->p.x > x0)
+ Box->p.x = x0;
+ if (Box->p.y > y0)
+ Box->p.y = y0;
+ if (Box->q.x < x1)
+ Box->q.x = x1;
+ if (Box->q.y < y1)
+ Box->q.y = y1;
+ }
+ exit:
+ return code;
+}
+
static int
pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
const gs_matrix *pmat, const gs_image_common_t *pic,
@@ -967,7 +1047,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
gx_image_enum_common_t ** pinfo,
pdf_typed_image_context_t context)
{
- int code, i;
+ int code = 0, i;
unsigned int use_fallback = 0, in_line = 0, is_mask = 0,
force_lossless = 0, convert_to_process_colors = 0;
int width, height;
@@ -976,9 +1056,9 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
const gs_pixel_image_t *pim;
gs_int_rect rect;
gs_image_format_t format;
- gs_color_space *pcs;
+ gs_color_space *pcs = NULL;
int num_components;
- pdf_image_enum *pie;
+ pdf_image_enum *pie = NULL;
const pdf_color_space_names_t *names;
gs_color_space *pcs_orig = NULL;
gs_color_space *pcs_device = NULL;
@@ -1006,14 +1086,15 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
until the mask is completed due to equal image merging. */
pdev->image_mask_id = gs_no_id;
+ pim = (const gs_pixel_image_t *)pic;
+
/* Check for the image types we can handle. */
switch (pic->type->index) {
case 1:
is_mask = ((const gs_image_t *)pic)->ImageMask;
code = setup_type1_image(pdev, pic, pdcolor, image, context);
- if (code < 0) {
+ if (code < 0)
use_fallback = 1;
- }
else
in_line = code;
break;
@@ -1039,55 +1120,107 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
(prect && !(prect->p.x == 0 && prect->p.y == 0 &&
prect->q.x == ((const gs_image3_t *)pic)->Width &&
prect->q.y == ((const gs_image3_t *)pic)->Height))) {
- gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t),
- "pdf_begin_typed_image(image)");
- return (gx_default_begin_typed_image((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor,
- pcpath, mem, pinfo));
+ use_fallback = 1;
+ goto exit;
}
- gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t),
- "pdf_begin_typed_image(image)");
- return (setup_type3_image(pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pinfo, image));
- break;
+ code = setup_type3_image(pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pinfo, image);
+ goto exit;
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 ||
(prect && !(prect->p.x == 0 && prect->p.y == 0 &&
prect->q.x == ((const gs_image3x_t *)pic)->Width &&
prect->q.y == ((const gs_image3x_t *)pic)->Height))) {
- return (gx_default_begin_typed_image((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor,
- pcpath, mem, pinfo));
+ use_fallback = 1;
+ goto exit;
}
pdev->image_mask_is_SMask = true;
- return gx_begin_image3x_generic((gx_device *)pdev, pgs, pmat, pic,
+ code = gx_begin_image3x_generic((gx_device *)pdev, pgs, pmat, pic,
prect, pdcolor, pcpath, mem,
pdf_image3x_make_mid,
pdf_image3x_make_mcde, pinfo);
- break;
+ goto exit;
case 4:
+ /* If we are colour converting then we may not be able to preserve the
+ * type 4 image, if it has a /Mask entry which is a range of colours
+ * (chroma-key masking). If its a stencil mask then we can just conver the
+ * underlying image and leave the mask alone.
+ */
+ if (pdev->params.ColorConversionStrategy != ccs_LeaveColorUnchanged) {
+ gs_color_space *pcs2;
+ int csi = 0;
+ bool fallback = false;
+ gs_image4_t *pim4 = (gs_image4_t *)pic;
+
+ /* If the /Mask is chroma-key rather than a stencil */
+ if (pim4->MaskColor_is_range) {
+ /* Find the colour space */
+ pcs2 = pim->ColorSpace;
+ csi = gs_color_space_get_index(pcs2);
+ /* If its /Indexed, get the base space */
+ if (csi == gs_color_space_index_Indexed) {
+ pcs2 = pim->ColorSpace->base_space;
+ csi = gs_color_space_get_index(pcs2);
+ }
+ if (csi == gs_color_space_index_ICC)
+ csi = gsicc_get_default_type(pcs2->cmm_icc_profile_data);
+ /* If the base space matches the target for colour conversion
+ * then no conversion is needed, so we can preserve the type
+ * 4 image.
+ */
+ switch(csi) {
+ case gs_color_space_index_DeviceGray:
+ if (pdev->params.ColorConversionStrategy != ccs_Gray)
+ fallback = true;
+ break;
+ case gs_color_space_index_DeviceRGB:
+ if (pdev->params.ColorConversionStrategy != ccs_RGB)
+ fallback = true;
+ break;
+ case gs_color_space_index_DeviceCMYK:
+ if (pdev->params.ColorConversionStrategy != ccs_CMYK)
+ fallback = true;
+ break;
+ default:
+ fallback = true;
+ break;
+ }
+ if (fallback == true && pdev->CompatibilityLevel > 1.2) {
+ /* We've arrived at the point where we have a chroma-keyed
+ * type 4 image, and the image needs to be converted to a
+ * different space. We can't do that, so fall back to a
+ * default implementation, create a clip path and apply it to
+ * the image.
+ */
+ pdev->JPEG_PassThrough = 0;
+ use_fallback = 0;
+ code = convert_type4_to_masked_image(pdev, pgs, pic, prect, pdcolor,
+ pcpath, mem,pinfo);
+ goto exit;
+ }
+ /* Note that we fall through to the original code, so if we are not
+ * producing at least PDF 1.2 (for image mask support) then we will
+ * fall back further filled to rectangles.
+ */
+ }
+ }
pdev->JPEG_PassThrough = 0;
code = convert_type4_image(pdev, pgs, pmat, pic, prect, pdcolor,
pcpath, mem, pinfo, context, image, pnamed);
- if (code < 0) {
+ if (code < 0)
use_fallback = 1;
- }
- if (code == 0) {
- gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t),
- "pdf_begin_typed_image(image)");
- return code;
- }
+ if (code == 0)
+ goto exit;
/* No luck. Masked images require PDF 1.3 or higher. */
- if (pdev->CompatibilityLevel < 1.2) {
+ if (pdev->CompatibilityLevel < 1.2)
use_fallback = 1;
- }
if (pdev->CompatibilityLevel < 1.3 && !pdev->PatternImagemask) {
- gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t),
- "pdf_begin_typed_image(image)");
- return (convert_type4_to_masked_image(pdev, pgs, pic, prect, pdcolor,
- pcpath, mem,pinfo));
+ use_fallback = 0;
+ code = convert_type4_to_masked_image(pdev, pgs, pic, prect, pdcolor,
+ pcpath, mem,pinfo);
+ goto exit;
}
image[0].type4 = *(const gs_image4_t *)pic;
break;
@@ -1097,7 +1230,6 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
break;
}
- pim = (const gs_pixel_image_t *)pic;
format = pim->format;
switch (format) {
case gs_image_format_chunky:
@@ -1115,14 +1247,12 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
case 2:
case 4:
case 8:
- break;
case 12:
case 16:
break;
default:
- gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t),
- "pdf_begin_typed_image(image)");
- return_error(gs_error_rangecheck);
+ code = gs_note_error(gs_error_rangecheck);
+ goto exit;
}
if (prect)
rect = *prect;
@@ -1135,82 +1265,15 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
(is_mask && pim->CombineWithColor))
use_fallback = 1;
- if (pdev->Eps2Write) {
- gs_rect sbox, dbox, *Box;
- gs_point corners[4];
- gs_fixed_rect ibox;
- gs_matrix * pmat1 = (gs_matrix *)pmat;
- gs_matrix mat;
-
- if (!pdev->accumulating_charproc)
- Box = &pdev->BBox;
- else
- Box = &pdev->charproc_BBox;
- if (pmat1 == 0)
- pmat1 = (gs_matrix *)&ctm_only(pgs);
- if ((code = gs_matrix_invert(&pic->ImageMatrix, &mat)) < 0 ||
- (code = gs_matrix_multiply(&mat, pmat1, &mat)) < 0)
- return code;
- sbox.p.x = rect.p.x;
- sbox.p.y = rect.p.y;
- sbox.q.x = rect.q.x;
- sbox.q.y = rect.q.y;
- gs_bbox_transform_only(&sbox, &mat, corners);
- gs_points_bbox(corners, &dbox);
- ibox.p.x = float2fixed(dbox.p.x);
- ibox.p.y = float2fixed(dbox.p.y);
- ibox.q.x = float2fixed(dbox.q.x);
- ibox.q.y = float2fixed(dbox.q.y);
- if (pcpath != NULL &&
- !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y,
- ibox.q.x, ibox.q.y)
- ) {
- /* Let the target do the drawing, but drive two triangles */
- /* through the clipping path to get an accurate bounding box. */
- gx_device_clip cdev;
- gx_drawing_color devc;
-
- fixed x0 = float2fixed(corners[0].x), y0 = float2fixed(corners[0].y);
- fixed bx2 = float2fixed(corners[2].x) - x0, by2 = float2fixed(corners[2].y) - y0;
-
- pdev->AccumulatingBBox++;
- gx_make_clip_device_on_stack(&cdev, pcpath, (gx_device *)pdev);
- set_nonclient_dev_color(&devc, gx_device_black((gx_device *)pdev)); /* any non-white color will do */
- gx_default_fill_triangle((gx_device *) & cdev, x0, y0,
- float2fixed(corners[1].x) - x0,
- float2fixed(corners[1].y) - y0,
- bx2, by2, &devc, lop_default);
- gx_default_fill_triangle((gx_device *) & cdev, x0, y0,
- float2fixed(corners[3].x) - x0,
- float2fixed(corners[3].y) - y0,
- bx2, by2, &devc, lop_default);
- pdev->AccumulatingBBox--;
- } else {
- /* Just use the bounding box. */
- float x0, y0, x1, y1;
- x0 = fixed2float(ibox.p.x) / (pdev->HWResolution[0] / 72.0);
- y0 = fixed2float(ibox.p.y) / (pdev->HWResolution[1] / 72.0);
- x1 = fixed2float(ibox.q.x) / (pdev->HWResolution[0] / 72.0);
- y1 = fixed2float(ibox.q.y) / (pdev->HWResolution[1] / 72.0);
- if (Box->p.x > x0)
- Box->p.x = x0;
- if (Box->p.y > y0)
- Box->p.y = y0;
- if (Box->q.x < x1)
- Box->q.x = x1;
- if (Box->q.y < y1)
- Box->q.y = y1;
- }
+ /* Handle BBox for Eps2Write, if applicable */
+ code = pdf_image_handle_eps(pdev, pgs, pmat, pic, &rect, pcpath);
+ if (code < 0) {
+ use_fallback = 0;
+ goto exit;
}
- 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
- ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem,
- pinfo);
- }
+ if (use_fallback)
+ goto exit;
pcs = pim->ColorSpace;
rc_increment_cs(pcs);
@@ -1218,19 +1281,13 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
code = pdf_check_soft_mask(pdev, (gs_gstate *)pgs);
if (code < 0)
- return code;
+ goto exit;
if (pdf_must_put_clip_path(pdev, pcpath))
code = pdf_unclip(pdev);
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
- ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem,
- pinfo);
- }
+ if (code < 0)
+ goto fail_and_fallback;
if (context == PDF_IMAGE_TYPE3_MASK) {
/*
@@ -1247,21 +1304,14 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
code = pdf_prepare_imagemask(pdev, pgs, pdcolor);
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
- ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem,
- pinfo);
- }
+ if (code < 0)
+ goto fail_and_fallback;
pie = gs_alloc_struct(mem, pdf_image_enum, &st_pdf_image_enum,
"pdf_begin_image");
if (pie == 0) {
- gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t),
- "pdf_begin_typed_image(image)");
- return_error(gs_error_VMerror);
+ code = gs_note_error(gs_error_VMerror);
+ goto exit;
}
memset(pie, 0, sizeof(*pie)); /* cleanup entirely for GC to work in all cases. */
*pinfo = (gx_image_enum_common_t *) pie;
@@ -1305,24 +1355,18 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
(code = gs_matrix_multiply(&bmat, &mat, &mat)) < 0 ||
(code = gs_matrix_multiply(&mat, pmat, &pie->mat)) < 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");
- return code;
- }
+ )
+ goto exit;
/* AR3,AR4 show no image when CTM is singular; AR5 reports an error */
- if (pie->mat.xx * pie->mat.yy == pie->mat.xy * pie->mat.yx)
+ if (pie->mat.xx * pie->mat.yy == pie->mat.xy * pie->mat.yx) {
+ use_fallback = 1;
goto fail_and_fallback;
+ }
}
code = pdf_put_clip_path(pdev, pcpath);
- if (code < 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");
- return code;
- }
+ if (code < 0)
+ goto exit;
pdf_image_writer_init(&pie->writer);
/* Note : Possible values for alt_writer_count are 1,2,3,4.
1 means no alternative streams.
@@ -1352,8 +1396,10 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
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)
+ if (pim->BitsPerComponent > 8 && convert_to_process_colors) {
+ use_fallback = 1;
goto fail_and_fallback;
+ }
if (convert_to_process_colors == 4) {
code = convert_DeviceN_alternate(pdev, pgs, pcs, NULL, NULL, NULL, NULL, &cs_value, in_line);
if (code < 0)
@@ -1368,6 +1414,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
code = make_device_color_space(pdev, pdev->pcm_color_info_index, &pcs_device);
if (code < 0)
goto fail_and_fallback;
+ rc_decrement(image[0].pixel.ColorSpace, "pdf_begin_typed_image(pixel.ColorSpace)");
image[0].pixel.ColorSpace = pcs_device;
image[0].pixel.BitsPerComponent = 8;
code = pdf_color_space_named(pdev, pgs, &cs_value, &pranges, pcs_device, names,
@@ -1400,53 +1447,6 @@ 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;
-
- /* 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
- * are writing compressed streams, we have one for the compressed stream
- * and one for the compression chooser.
- * For type 4 images being converted (for old versions of PDF or for ps2write)
- * we need an additional stream to write a mask, which masks the real
- * image.
- * For colour conversion we will place an additional filter in front of all
- * 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);
- } else {
- if (force_lossless) {
- /*
- * Some regrettable PostScript code (such as LanguageLevel 1 output
- * from Microsoft's PSCRIPT.DLL driver) misuses the transfer
- * function to accomplish the equivalent of indexed color.
- * Downsampling (well, only averaging) or JPEG compression are not
- * compatible with this. Play it safe by using only lossless
- * filters if the transfer function(s) is/are other than the
- * identity and by setting the downsample type to Subsample..
- */
- int saved_downsample = pdev->params.ColorImage.DownsampleType;
-
- pdev->params.ColorImage.DownsampleType = ds_Subsample;
- code = new_setup_image_filters((gx_device_psdf *) pdev,
- &pie->writer.binary[0], &image[0].pixel,
- pmat, pgs, true, in_line, convert_to_process_colors);
- pdev->params.ColorImage.DownsampleType = saved_downsample;
- } else {
- code = new_setup_image_filters((gx_device_psdf *) pdev,
- &pie->writer.binary[0], &image[0].pixel,
- pmat, pgs, true, in_line, convert_to_process_colors);
- }
- }
-
- if (code < 0)
- goto fail_and_fallback;
-
if (!convert_to_process_colors)
{
gs_color_space_index csi;
@@ -1501,10 +1501,53 @@ 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 */
+ /* If we are not preserving the colour space unchanged, then we can't pass through JPEG */
else
pdev->JPEG_PassThrough = 0;
+ /* 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
+ * are writing compressed streams, we have one for the compressed stream
+ * and one for the compression chooser.
+ * For type 4 images being converted (for old versions of PDF or for ps2write)
+ * we need an additional stream to write a mask, which masks the real
+ * image.
+ * For colour conversion we will place an additional filter in front of all
+ * 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);
+ } else {
+ if (force_lossless) {
+ /*
+ * Some regrettable PostScript code (such as LanguageLevel 1 output
+ * from Microsoft's PSCRIPT.DLL driver) misuses the transfer
+ * function to accomplish the equivalent of indexed color.
+ * Downsampling (well, only averaging) or JPEG compression are not
+ * compatible with this. Play it safe by using only lossless
+ * filters if the transfer function(s) is/are other than the
+ * identity and by setting the downsample type to Subsample..
+ */
+ int saved_downsample = pdev->params.ColorImage.DownsampleType;
+
+ pdev->params.ColorImage.DownsampleType = ds_Subsample;
+ code = new_setup_image_filters((gx_device_psdf *) pdev,
+ &pie->writer.binary[0], &image[0].pixel,
+ pmat, pgs, true, in_line, convert_to_process_colors);
+ pdev->params.ColorImage.DownsampleType = saved_downsample;
+ } else {
+ code = new_setup_image_filters((gx_device_psdf *) pdev,
+ &pie->writer.binary[0], &image[0].pixel,
+ pmat, pgs, true, in_line, convert_to_process_colors);
+ }
+ }
+
+ if (code < 0)
+ goto fail_and_fallback;
if (convert_to_process_colors) {
image[0].pixel.ColorSpace = pcs_orig;
@@ -1529,9 +1572,8 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
if (pie->writer.alt_writer_count > 1) {
code = pdf_make_alt_stream(pdev, &pie->writer.binary[1]);
- if (code) {
+ if (code < 0)
goto fail_and_fallback;
- }
code = new_setup_image_filters((gx_device_psdf *) pdev,
&pie->writer.binary[1], &image[1].pixel,
pmat, pgs, force_lossless, in_line, convert_to_process_colors);
@@ -1542,8 +1584,11 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
cos_stream_t *pcos = cos_stream_from_pipeline(pie->writer.binary[i].strm);
s_close_filters(&s, NULL);
gs_free_object(pdev->pdf_memory, s, "compressed image stream");
- if (pcos == 0L)
- return gs_note_error(gs_error_ioerror);
+ if (pcos == 0L) {
+ /* TODO: Seems like something should be freed here */
+ code = gs_note_error(gs_error_ioerror);
+ goto exit;
+ }
pcos->cos_procs->release((cos_object_t *)pcos, "pdf_begin_typed_image_impl");
gs_free_object(pdev->pdf_memory, pcos, "compressed image cos_stream");
}
@@ -1558,9 +1603,8 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
image[1].pixel.BitsPerComponent = pim->BitsPerComponent;
code = psdf_setup_image_colors_filter(&pie->writer.binary[1],
(gx_device_psdf *)pdev, pim, &image[1].pixel, pgs);
- if (code < 0) {
+ if (code < 0)
goto fail_and_fallback;
- }
image[1].pixel.ColorSpace = pcs_device;
}
}
@@ -1588,7 +1632,7 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
/* Won't use image[2]. */
code = pdf_begin_write_image(pdev, &pie->writer, gs_no_id, width,
height, NULL, false);
- if (code)
+ if (code < 0)
goto fail_and_fallback;
code = psdf_setup_image_filters((gx_device_psdf *) pdev,
&pie->writer.binary[i], &image[i].pixel,
@@ -1609,20 +1653,38 @@ pdf_begin_typed_image(gx_device_pdf *pdev, const gs_gstate * pgs,
++pie->writer.alt_writer_count;
}
- gs_free(mem->non_gc_memory, image, 4, sizeof(image_union_t),
- "pdf_begin_typed_image(image)");
- rc_decrement(pcs, "pdf_begin_typed_image(pcs)");
- return 0;
+ /* use_fallback = 0, so this will drop through the below labels, doing only the cleanup parts */
+ code = 0;
+
+ /* This label is used when code < 0 and we want to do the fallback code */
+ fail_and_fallback:
+ if (code != 0)
+ use_fallback = 1;
-fail_and_fallback:
+ /* This label is used either when there's no error and we are just exiting normally
+ * (possibly with use_fallback=1), or there is an error but we don't want to do
+ * the fallback code.
+ */
+ exit:
+ /* Free everything */
rc_decrement(pcs, "pdf_begin_typed_image(pcs)");
- pdev->JPEG_PassThrough = 0;
+ rc_decrement(pcs_device, "pdf_begin_typed_image(pcs_device)");
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");
- return gx_default_begin_typed_image
- ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem,
- pinfo);
+
+ /* Free pie only if there was an error or we are falling back */
+ if (code < 0 || use_fallback) {
+ if (pie)
+ gs_free_object(mem, pie, "pdf_begin_typed_image(pie)");
+ *pinfo = NULL;
+ }
+ /* Do the fallback */
+ if (use_fallback) {
+ pdev->JPEG_PassThrough = 0;
+ code = gx_default_begin_typed_image
+ ((gx_device *)pdev, pgs, pmat, pic, prect, pdcolor, pcpath, mem, pinfo);
+ }
+ return code;
}
int
@@ -1730,7 +1792,7 @@ pdf_image_plane_data(gx_image_enum_common_t * info,
if (pie->JPEG_PassThrough) {
pie->rows_left -= height;
*rows_used = height;
- return 0;
+ return !pie->rows_left;
}
for (i = 0; i < pie->writer.alt_writer_count; i++) {
@@ -1922,6 +1984,10 @@ pdf_image_end_image_data(gx_image_enum_common_t * info, bool draw_last,
} else
code = pdf_end_and_do_image(pdev, &pie->writer, &pie->mat, info->id, do_image);
pie->writer.alt_writer_count--; /* For GC. */
+ } else {
+ code = pdf_end_image_binary(pdev, &pie->writer, data_height);
+ code = pdf_end_abort_image(pdev, &pie->writer);
+ pie->writer.alt_writer_count--; /* For GC. */
}
if (pie->initial_colorspace != pdev->pcm_color_info_index)
pdf_set_process_color_model(pdev, pie->initial_colorspace);
@@ -2286,7 +2352,7 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size)
if (code < 0)
return code;
pcd = cos_stream_dict((cos_stream_t *)pres->object);
- pcd_Resources = cos_dict_alloc(pdev, "pdf_pattern(Resources)");
+ pcd_Resources = cos_dict_alloc(pdev, "pdf_form(Resources)");
if (pcd == NULL || pcd_Resources == NULL)
return_error(gs_error_VMerror);
code = cos_dict_put_c_strings(pcd, "/Type", "/XObject");
@@ -2467,6 +2533,13 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size)
pres->where_used |= pdev->used_mask;
} else if (pres->object->id < 0)
pdf_reserve_object_id(pdev, pres, 0);
+ pdev->LastFormID = pdf_resource_id(pres);
+ pdev->HighLevelForm--;
+ if (pdev->accumulating_substream_resource) {
+ code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pres);
+ if (code < 0)
+ return code;
+ }
if (pdev->PDFFormName) {
cos_value_t value;
@@ -2476,19 +2549,14 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size)
if (code < 0)
return code;
pdf_drop_resource_from_chain(pdev, pres, resourceXObject);
+ pres->object = NULL;
+ gs_free_object(pdev->pdf_memory, pres, "free redundant resource");
- gs_free_object(pdev->memory->non_gc_memory, pdev->PDFFormName, "free Name oof Form for pdfmark");
+ gs_free_object(pdev->memory->non_gc_memory, pdev->PDFFormName, "free Name of Form for pdfmark");
pdev->PDFFormName = 0x00;
} else {
pprintld1(pdev->strm, "/R%ld Do Q\n", pdf_resource_id(pres));
}
- pdev->HighLevelForm--;
- if (pdev->accumulating_substream_resource) {
- code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pres);
- if (code < 0)
- return code;
- }
- pdev->LastFormID = pdf_resource_id(pres);
}
return 0;
case gxdso_get_form_ID:
@@ -2690,6 +2758,8 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size)
return 0;
}
break;
+ case gxdso_in_smask_construction:
+ return pdev->smask_construction;
case gxdso_get_dev_param:
{
int code;