Summary: | drawImage uses a too large area when in printing mode | ||
---|---|---|---|
Product: | poppler | Reporter: | Benjamin Berg <benjamin> |
Component: | cairo backend | Assignee: | poppler-bugs <poppler-bugs> |
Status: | RESOLVED FIXED | QA Contact: | |
Severity: | normal | ||
Priority: | medium | ||
Version: | unspecified | ||
Hardware: | Other | ||
OS: | All | ||
Whiteboard: | |||
i915 platform: | i915 features: | ||
Attachments: |
PDF file in question
script I used to rendre the document Script that reproduces the error without poppler patch that fixes pdf creation patch to use cairo_paint |
Created attachment 54629 [details]
script I used to rendre the document
Outch. I found the problem (after looking through the cairo trace, stepping trough cairo, and finally trying to reproduce the problem with a simple script ...). So, the trouble is, that the PDF will overflow cairo's 24.8 (1 sign bit) fixed point number representation. It contains the following command: 0 4058686.144 2037628.645 -4058684.387 re W n With the tranformation matrix at that point, this results in a rectangle between the points (in px): (-1753.3703124604863, 3439.9252751940003) (-9657653340.689249, -3435427201.820131) And some of these values are larger than 2^23. I guess I should investigate how those insane numbers could creep into the PDF (and fix the affected PDFs). A workaround in Poppler (or cairo?) might be to clip the rather large numbers to something more sane. Which might not be easy because of the transformation matrix. I'll attach the test script which reproduces the error. Created attachment 54813 [details]
Script that reproduces the error without poppler
Created attachment 54837 [details] [review] patch that fixes pdf creation OK. So it is one thing that PDFs with insane clip regions are not rendered correctly (and I guess one can consider that to be OK). Now the reason for the broken PDF however is also in poppler. The bug was introduced in commit d63293af (last two hunks), which causes a way to large rectangle to be used when drawing images in printing mode. As the history of the comments seems to confuse people, here a go at a self contained explanation.
Short version (which hopefully should be enough):
Commit d63293af6 (Carlos Garcia Campos, Turn EXTEND_PAD off when printing) did the following change:
- cairo_rectangle (cairo, 0., 0., 1., 1.);
+ if (printing)
+ cairo_rectangle (cairo, 0., 0., width, height);
+ else
+ cairo_rectangle (cairo, 0., 0., 1., 1.);
In the "printing" case, this results in a clip area that is very large (ie. dest_width * image_width, dest_height * image_height; where dest_width/dest_height is from the current transformation matrix).
So, just removing the special case will fix the problem. Another way to fix it would be to replace the "printing" case with a cairo_paint, as the extend mode is CAIRO_EXTEND_NONE for the "printing" case; this could be more in the spirit of the commit by Carlos.
----
Long version:
So as I understand it:
1. In a PDF an image will always be drawn in the rectangle (0, 0, 1, 1), and the size is specified by changing the transformation matrix.
2. Poppler transforms the patterns matrix, so that the image is mapped into this space. This happens in line 2765 and following:
> cairo_matrix_init_translate (&matrix, 0, height);
> cairo_matrix_scale (&matrix, image_width, -image_height);
> cairo_pattern_set_matrix (pattern, &matrix);
3. A draw_rectangle in the rectangle (0, 0, 1, 1) is done. (Line 2785)
Now, when poppler is in printing mode, the last point fails. Instead of drawing in the area (0, 0, 1, 1) it draws in the area (0, 0, image_width, image_height). This rectangle is then multiplied with the current transformation matrix (scaling it by ~595 and ~842 for a whole A4 page).
To be exact, look at the following output:
q
0 841.89 595 -841 re W n
q
0 4058686.144 2037628.645 -4058684.387 re W n
595.275678 0 0 840.133386 0 1.756407 cm
/a0 gs /x11 Do
Q
Q
The image has the size of 3423x4831 pixel. This is multiplied by the above matrix:
3423 * 595.275678 = 2037628.645794
4831 * 840.133386 = 4058684.387766
As one can see, this gives us the values from the way too large clip rectangle.
Once you have these huge numbers in a PDF, you can easily overflow cairo by rendering this at 300 DPI to an image surface. It means the clip region gets a size of:
4058684.387766 pt * 300px / 72pt = 16911184.949025 px
Which is much larger than 2^23.
Created attachment 55431 [details] [review] patch to use cairo_paint Here's a patch to use cairo_paint when printing instead of the clip/fill. (In reply to comment #6) > Created attachment 55431 [details] [review] [review] > patch to use cairo_paint > > Here's a patch to use cairo_paint when printing instead of the clip/fill. Please push it. Thanks!, and thanks Benjamin for the detailed explanation :-) Pushed. |
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.
Created attachment 54628 [details] PDF file in question OK, this is a weird bug, and I am kind of stuck trying to even figure out where it is (cairo/pixman/poppler). What happens is, that the attached PDF file will only render at certain zoom/dpi values. You can see this in evince happening, when you open it and zoom in to 400% the image will disappear. What you do not see there is, that the images will appear again if you render it at an even larger scale of eg. 900dpi. I am attaching the PDF in question, and a small script that I have been using to convert the PDF to TIFF images. (change the DPI in the script to eg. 100 or 900 to see the image appear). The easiest workaround seems to be to use pdftoppm instead of trying to render the PNG myself. This seems to work around it by not using the cairo backend.