[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(-)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.