[gs-commits] ghostpdl branch, master, updated. jbig2dec-0.14-1555-gff856d0
[email protected] (Ken Sharp)
| Newsgroups | gmane.comp.printing.ghostscript.cvs |
|---|---|
| Message-ID | <[email protected]> |
The ghostpdl branch, master has been updated
via ff856d0c44ce7d3f4d204f4a405857a6a6672a80 (commit)
from f69b63a3dc3bb7671df956587fe2520f8badab88 (commit)
----------------------------------------------------------------------
commit ff856d0c44ce7d3f4d204f4a405857a6a6672a80
Author: Ken Sharp <[email protected]>
Date: Tue Aug 6 12:44:49 2019 +0100
pdfwrite - handle nested Patterns inside a transparency Group
Bug #701181 "Incorrect output after ghostscript processing of a PDF file"
The PDF file is constructed in a somewhat sub-optimal fashion. Each
background square 'grid' is a Form, each Form draws the content by
filling the area with a solid colour, and then drawing white lines
across it. The white lines (actually rectangles) are drawn using a
Pattern.
So far so good, however the Pattern simply executes a Form, that Form
then fills another rectangle, with another Pattern, its this final
pattern which does the drawing.
This is two levels of indirection more than required.
Normally this isn't a problem because we don't attempt to preserve
Forms from PDF files (and this is one example of why we don't). But....
If the file involves transparency Groups, then we must use a Form
XObject for the Group.
In this case the CTM of the first pattern is the CTM of the 'enclosing
context', ie the Form, but the CTM of the second pattern is also the
CTM of the 'enclosing context', but now that means the first pattern,
not the Group.
To cater for this we track the number of patterns defined since the last
Form definition. If its 0 (ie this is the first pattern since a Form
definition) then we just use the CTM. If its greatre than 0, however,
then we 'undo' the scaling applied by pdfwrite, in order to get back to
the CTM of the enclosing pattern.
Its possible that more extreme examples (patterns inside patterns
inside groups inside patterns inside groups) might still not be entirely
correct, but we have no examples of this (Patterns inside patterns are
relatively rare). If we find any we can revisit this.
diff --git a/devices/vector/gdevpdfb.h b/devices/vector/gdevpdfb.h
index 0991e4c..d000ee9 100644
--- a/devices/vector/gdevpdfb.h
+++ b/devices/vector/gdevpdfb.h
@@ -235,6 +235,7 @@ const gx_device_pdf PDF_DEVICE_IDENT =
0, /* HighLevelForm */
0, /* PatternDepth */
{0,0,0,0,0,0}, /* AccumulatedPatternMatrix */
+ 0, /* PatternsSinceForm */
0, /* substream_Resources */
1, /* pcm_color_info_index == DeviceRGB */
false, /* skip_colors */
diff --git a/devices/vector/gdevpdfi.c b/devices/vector/gdevpdfi.c
index a8b5aba..7dba5e6 100644
--- a/devices/vector/gdevpdfi.c
+++ b/devices/vector/gdevpdfi.c
@@ -2539,6 +2539,7 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size)
pprintg2(pdev->strm, "%g 0 0 %g 0 0 cm\n",
72.0 / pdev->HWResolution[0], 72.0 / pdev->HWResolution[1]);
pdev->PatternDepth++;
+ pdev->PatternsSinceForm++;
}
return 1;
case gxdso_pattern_finish_accum:
@@ -2578,6 +2579,7 @@ gdev_pdf_dev_spec_op(gx_device *pdev1, int dev_spec_op, void *data, int size)
} else if (pres->object->id < 0)
pdf_reserve_object_id(pdev, pres, 0);
pdev->PatternDepth--;
+ pdev->PatternsSinceForm--;
return 1;
case gxdso_pattern_load:
pres = pdf_find_resource_by_gs_id(pdev, resourcePattern, id);
diff --git a/devices/vector/gdevpdft.c b/devices/vector/gdevpdft.c
index c7883ae..e8fb227 100644
--- a/devices/vector/gdevpdft.c
+++ b/devices/vector/gdevpdft.c
@@ -195,6 +195,7 @@ pdf_begin_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev,
See doimagesmask in gs/lib/pdf_draw.ps .
Just set a flag for skipping pdf_end_transparency_group. */
pdev->image_with_SMask |= 1 << ++pdev->FormDepth;
+ pdev->PatternsSinceForm = 0;
} else {
pdf_resource_t *pres, *pres_gstate = NULL;
cos_dict_t *pcd = NULL, *pcd_Resources = NULL;
@@ -210,6 +211,7 @@ pdf_begin_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev,
if (code < 0)
return code;
pdev->FormDepth++;
+ pdev->PatternsSinceForm = 0;
code = pdf_make_form_dict(pdev, pparams, pgs, group_dict, (cos_dict_t *)pres->object);
if (code < 0)
return code;
@@ -237,6 +239,7 @@ pdf_end_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev)
/* An internal group for the image implementation.
See pdf_begin_transparency_group. */
pdev->image_with_SMask &= ~(1 << pdev->FormDepth--);
+ pdev->PatternsSinceForm = 0;
return 0;
} else if (pdev->sbstack_depth == bottom) {
/* We're closing the page group. */
@@ -249,6 +252,7 @@ pdf_end_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev)
uint ignore;
pdev->FormDepth--;
+ pdev->PatternsSinceForm = 0;
code = pdf_exit_substream(pdev);
if (code < 0)
return code;
@@ -381,6 +385,7 @@ pdf_end_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
* the FormDepth ourselves.
*/
pdev->FormDepth--;
+ pdev->PatternsSinceForm = 0;
}
return 0;
}
diff --git a/devices/vector/gdevpdfv.c b/devices/vector/gdevpdfv.c
index ff33f16..2f71d86 100644
--- a/devices/vector/gdevpdfv.c
+++ b/devices/vector/gdevpdfv.c
@@ -242,7 +242,7 @@ pdf_store_pattern1_params(gx_device_pdf *pdev, pdf_resource_t *pres,
* form is nested inside a form, the default space is the space of the
* first form, and therefore we do *not* remove the resolution scaling.
*/
- if (pdev->FormDepth == 0) {
+ if (pdev->FormDepth == 0 || (pdev->FormDepth > 0 && pdev->PatternsSinceForm > 0)) {
gs_matrix scaled;
gs_make_scaling(1 / scale_x, 1 / scale_y, &scaled);
diff --git a/devices/vector/gdevpdfx.h b/devices/vector/gdevpdfx.h
index 9736e8e..ca95a36 100644
--- a/devices/vector/gdevpdfx.h
+++ b/devices/vector/gdevpdfx.h
@@ -786,6 +786,19 @@ struct gx_device_pdf_s {
int PatternDepth;
gs_matrix AccumulatedPatternMatrix;
+ /* Normally the PDF itnerpreter doesn't call execform to pass a From XObject to
+ * pdfwrite, but it *does* create forms (and increment FormDepth) for transparent
+ * Groups, which are handled as Form XObjects. Because of the way that Pattterns work,
+ * the first pattern after a Form uses the Form co-ordinate system, but if the Pattern
+ * itself uses Patterns, then the nested Pattern needs to use the co-ordinate system
+ * of the parent Pattern. Unless, of course, we have another Form!
+ * So essentially we need to know the Pattern depth, since the last form was executed.
+ * If its 0, then we want to apply the current CTM, if its more than that then we want
+ * to undo the pdfwrite scaling (see gdevpdfv.c, pdf_store_pattern1_params() at about line
+ * 239.
+ */
+ int PatternsSinceForm;
+
/* Accessories */
cos_dict_t *substream_Resources; /* Substream resources */
gs_color_space_index pcm_color_info_index; /* Index of the ProcessColorModel space. */
Summary of changes:
devices/vector/gdevpdfb.h | 1 +
devices/vector/gdevpdfi.c | 2 ++
devices/vector/gdevpdft.c | 5 +++++
devices/vector/gdevpdfv.c | 2 +-
devices/vector/gdevpdfx.h | 13 +++++++++++++
5 files changed, 22 insertions(+), 1 deletion(-)