Bug 698337 - When converting/extracting a png from an AI or PDF file the layers are improperly positioned for some documents
Summary: When converting/extracting a png from an AI or PDF file the layers are improp...
Status: RESOLVED INVALID
Alias: None
Product: Ghostscript
Classification: Unclassified
Component: Graphics Library (show other bugs)
Version: 9.21
Hardware: All All
: P4 normal
Assignee: Robin Watts
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-08-07 07:30 UTC by Carl Buxbaum
Modified: 2022-06-06 14:07 UTC (History)
1 user (show)

See Also:
Customer:
Word Size: ---


Attachments
source Adobe Illustrator file (1.77 MB, application/postscript)
2017-08-07 07:30 UTC, Carl Buxbaum
Details
source pdf file (710.86 KB, application/pdf)
2017-08-07 07:31 UTC, Carl Buxbaum
Details
target png (645.60 KB, image/png)
2017-08-07 07:32 UTC, Carl Buxbaum
Details
simplified file (438.45 KB, application/pdf)
2017-08-07 08:42 UTC, Ken Sharp
Details
reduced4.pdf (101.49 KB, application/pdf)
2022-06-06 10:46 UTC, Robin Watts
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Carl Buxbaum 2017-08-07 07:30:36 UTC
Created attachment 14047 [details]
source Adobe Illustrator file

Hello, we have an integration with Ghostscript in our application that extracts thumbnails from source documents.  In the case of the attached source document (AI or PDF), the resulting png has layers mispositioned.

Here is the command I am running:

/usr/local/bin/gs -dQUIET -dNOPROMPT -dNOPAUSE -dBATCH -dSAFER -r300 -sDEVICE=png16m -sOutputFile=target.png source.ai

or

/usr/local/bin/gs -dQUIET -dNOPROMPT -dNOPAUSE -dBATCH -dSAFER -r300 -sDEVICE=png16m -sOutputFile=target.png source.pdf

Please see attached source and target files for reference.

Thanks,

Carl
Comment 1 Carl Buxbaum 2017-08-07 07:31:20 UTC
Created attachment 14048 [details]
source pdf file
Comment 2 Carl Buxbaum 2017-08-07 07:32:15 UTC
Created attachment 14049 [details]
target png
Comment 3 Ken Sharp 2017-08-07 08:36:27 UTC
This is nothing to do with layers (which are q
Comment 4 Ken Sharp 2017-08-07 08:42:51 UTC
Created attachment 14050 [details]
simplified file

Oops, pressed submit by accident.

This is nothing to do with layers, which are a specific feature of PDF files. The problem is something to do with patterns. The important part of this is reproduced in the reduced file (attached) which is an irregular path filled with a pattern. The pattern simply draws an image.

At different resolutions the image appears to be scaled differently, or possibly the pattern offset is slightly different, resulting in different portions of the image underlying the fill.

As a quick test tried using -dNOINTERPOLATE and -dNOTRANSPARENCY, no difference.
Comment 5 Ray Johnston 2017-08-07 09:44:14 UTC
Looks like a pattern or image issue. I'll have a look.
Comment 6 Peter Cherepanov 2020-12-29 05:50:50 UTC
This is the result of mismatch between adjusted and unadjusted sizes used in the calculation of the pattern phase, when translation values in the pattern matrix are large.
Comment 7 Ken Sharp 2021-10-12 11:14:20 UTC
The problem here seems to be that the Pattern has a TilingType of 3 (constant spacing and faster tiling), which permits us to distort the pattern cell and it's placement, for better performance. The exact nature of the distortion is not documented for type 3.

If I alter the TilingType to 2 (no distortion) then the pattern is painted as expected.

To me this looks like a combination of using a small image to create a pattern, scaling that image up by a large amount, and then permitting the interpreter to be lax about the position and size of the cell. Basically; "don't do that"

However I'd like another (ideally better informed) opinion so I'm assigning this to Robin on the basis that he seems to have been the last one to work on gs_pattern1_make_pattern() which is where the adjustment to the pattern cell/position takes place.
Comment 8 Robin Watts 2022-06-06 10:46:22 UTC
Created attachment 22660 [details]
reduced4.pdf

Even more reduced file.

A 'simple' path filled with a pattern.
Comment 9 Robin Watts 2022-06-06 14:07:58 UTC
The problem is indeed down to TilingType 3. We are operating within the spec. It's a badly formed file.

I toyed with the following patch:

diff --git a/base/gsptype1.c b/base/gsptype1.c
index 4dc86e8fc..06abe6705 100644
--- a/base/gsptype1.c
+++ b/base/gsptype1.c
@@ -278,15 +278,23 @@ gs_pattern1_make_pattern(gs_client_color * pcc,
                 gs_scale(saved, fabs(inst.size.x / inst.step_matrix.xx), 1);
                 inst.step_matrix.xx = (float)inst.size.x;
             } else {
-                float cx, ox, dx;
-                float n;
-
+                float cx, ox, dx, n;
+
+                /* We are about to adjust our matrices/bbox such that it
+                 * will become integer sized, and will tile based upon
+                 * those integer sizes. For cases where the transformation
+                 * is large, this small adjustment can have large effects
+                 * by the time we come to have one on screen. Before we
+                 * do anything else, we therefore adjust the transformation
+                 * using the accurate widths/heights so that our 0th tile
+                 * repeat has the smallest transformation possible.
+                 */
                 if (inst.step_matrix.tx >= 0)
                     n = floor(inst.step_matrix.tx/inst.step_matrix.xx);
                 else
                     n = -ceil(-inst.step_matrix.tx/inst.step_matrix.xx);
                 inst.step_matrix.tx -= n * inst.step_matrix.xx;
-                inst.saved->ctm.tx -= n * inst.step_matrix.xx;
+                saved->ctm.tx -= n * inst.step_matrix.xx;
                 bbox.p.x -= n*inst.step_matrix.xx;
                 bbox.q.x -= n*inst.step_matrix.xx;
                 if (inst.step_matrix.ty >= 0)
@@ -294,7 +302,7 @@ gs_pattern1_make_pattern(gs_client_color * pcc,
                 else
                     n = -ceil(-inst.step_matrix.ty/inst.step_matrix.yy);
                 inst.step_matrix.ty -= n * inst.step_matrix.yy;
-                inst.saved->ctm.ty -= n * inst.step_matrix.yy;
+                saved->ctm.ty -= n * inst.step_matrix.yy;
                 bbox.p.y -= n*inst.step_matrix.yy;
                 bbox.q.y -= n*inst.step_matrix.yy;


That "fixes" this bug, but it changes many other files, and possibly not all for the good.

An alternative idea would be to create a new command line option that forces all patterns to be interpreted as TilingType 2. We'd need more evidence to justify that I think.