-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discrepancy between PDF & PNG when translating an SVG that contains a linear gradient #19
Comments
Thanks for the detailed report and the test case. I'll try to look into, but I will likely have no time for that this week. |
Oh, I should not write fix in the commit message, as it would close the issue ... The start and end points need to be moved future away from the center. I tried different things, but that did not work. I had to disable this for now as it breaks other gradient SVG test cases. I assume as soon as the scaling is right the other test cases would be ok with that code. So this is WIP at the moment. If you can spare some time could you try your luck here? It's in PdfBoxGraphics2DPaintApplier.java:374 and currently disabled:
|
Thank you Emmeran. I will work on this today. |
Hi Emmeran. Thanks again for your work on this issue. I've pulled down your new code & re-enabled your updated logic by changing 'false' to 'true' on PdfBoxGraphics2DPaintApplier.java:374. I'm able to reproduce your results. When I translate long-gradient.svg to an SVG using your test harness, the PDF looks very close to the SVG as rendered in a web browser. Unfortunately, I don't believe that you've found the general solution to this issue. I processed some other SVGs using your updated code and the translation to PDF looks quite a bit different. I've checked in a new SVG named 'tall-gradient.svg' and pushed it up to a branch in order to demonstrate this Here's a screenshot of my results |
TBH I'm not surprised. I don't really understand what
should mean. Especially that "may render" seems like "sometimes", which makes not that much sense to me... I did only try&error, as I not really understand yet whats wrong here. I just found the draft SVG 2 spec, which may clear up that thing a bit. |
Hi Emmeran. I found this stack overflow post to be useful in clarifying the situation The basic approach I've used is to start with a special case where SVG linear gradient default layout matches PDF axial gradient layout. The special case is a perfect square. It doesn't make sense to have a gradient over a rectangle with a zero or negative width or height. So for my base case, I use a 1x1 square. Then I use the affine transform that we already have on the state object to warp the space of the box, scaling it up to a rectangle of arbitrary size. Warping the space after applying the gradient results in a painted rectangle that looks like the SVG gradient in objectBoundingBox mode rendered in a browser. I've isolated my code in a subroutine named
Where You can check the output of my code by running I expect that you'd probably want to refactor my code because the coding style is not in harmony with yours (especially in the way that I bolted on extra functionality to the existing test harness). But I think that the approach is sound, and I hope this code is useful at least as an example. Please note that my code is not a general purpose solution to the linear gradient layout problem. I tried running my code against the rest of the test docs in |
… paint transform. #19 If it is square than we are in UserSpaceOnUse mode, otherwise we are in ObjectBoundingBox mode. But we only check that if we are using Batik.
I've removed the EmulateObjectBoundingBox boolean and instead used the scaling factors of the transform matrix to detect object bounding box. This seems to work correctly, and also does not break the more complex SVGs in the test. Please verify that it works for all your cases, then I will release a new version. Thanks for your help with this issue! |
I will test this today. Thanks again for your work on this issue. |
Hi Emmeran, My colleague found a use case that I missed that introduces a regression. The problem is in the code that I submitted in #20. If an SVG had a gradient that was exactly vertical or horizontal in orientation, I created a rectangle of height or width of zero, which was later used as a clip path. This had undesirable results. I've created a pull request with an SVG that demonstrates this problem as well as a bugfix to resolve it: I tested again with the codebase that included #21. The output PDFs looked much improved. All of the PDFs produced by testGradientSVGEmulateObjectBoundingBox() looked perfect as far as I could tell. I did find one other regression in the test for Testing on master plus PR 21, the buttons in the interactive web statistics dashboard display as rectangles. Testing on the latest tagged release, graphics2d-0.24, those buttons are displayed with rounded corners. There is a similar problem with the grippies down in the bottom of the SVG. See attached screenshot. I'm not quite sure what is going on there, but I suspect that it has something to do with the r attributes in the rectangle
I suspect that the clipping box that gets injected for gradients interferes with the rounding defined in those attributes. I don't know how to resolve that yet. |
Issue-19-bugfix | regression with vertical or horizontal gradients #19
#19 But we also must ensure that we not do an empty clip bei accident after that. So there is a new flag to keep track if a path is on the content stream. This fixes the round boxes in the displayWebStats case.
The problem here is, that the But also just calling So to correctly fix that there is a new boolean flag in the Graphics2D adapter which tracks if we currently have a path on the content stream which has not been closed. And when we try to clip it first checks if there is a path and only clips in that case. Now that dashboard case also works for me. Please test again, thanks. |
Hi Emeran, As it happens I also thought about adding boolean flag in the Graphics2D adapter to help manage clipping. But I thought that you might be more amenable to accepting a code contribution from a new contributor if I could isolate all of my changes to a single method. I guess I should have explored all options. I've tested the most recent code in master. I can find no regressions in the translation of any of the SVGs in We would be interested in using this code as soon as a new version of pdfbox-graphics2d is released. |
@larrylynn-wf Nice that it works for you. I don't mind any contribution as long as it's sound. I've tried to released version 0.25, but sonatype currently has problems (see https://status.maven.org/incidents/t40ylgmsmbl2?u=2thbn6r7vdfk), so I'll retry later. I'll give you an update if publishing works again and the releasing worked. |
I could finally publish version 0.25, so you can use that now. Thanks again for the report and help with this issue. |
We have a preliminary build of our software integrated with pdfbox-graphics2d version 0.25. The results look great so far. Thanks again for your work on this issue, and for my part, I was happy to be of assistance. |
Greetings Rototor.
First, I wanted to write and say thank you for your work on this awesome library. We're getting great results using it to embed SVGs in PDFs.
We did notice something that looked a bit weird when we had SVGs representing a chart that had a linear background gradient. When the SVG contains a linear gradient, a gradient vector image is embedded in the PDF that has a different orientation than the original SVG as rendered in a browser. See attached screenshot.
When I first noticed the visual discrepancy between SVG input & PDF output, I thought that it might be a bug in pdfbox-graphics2d. After reading up on the SVG and PDF specifications, I no longer think it's a bug.
The SVG specification
https://www.w3.org/TR/SVG11/pservers.html#LinearGradients
says that
However, the PDF specification states, in the section for "Type 2 (Axial) Shadings"
https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf
So, I think that the root issue is a mismatch between the 2 specifications. In PDF, the gradient normal is always perpendicular to the gradient vector. In SVG, the gradient normal is sometimes perpendicular. Therefore, translating the SVG to a PDF gradient that has the gradient normal going perpendicular is technically correct according to my reading of the specification.
However, since pdfbox-graphics2d is intended as a bridge between SVGs and PDFBox, I think it's a reasonable feature request to ask for an option that allows us to make linear gradients look the same in a PDF as they do when the input SVG is rendered as a browser.
I've opened a pull request that can be used to demonstrate this issue:
#18
Running
mvn test
will translate that SVG to both a PDF and a PNG.Note that the orientation of the gradient in the PDF does not match the orientation of the gradient in the PNG. See attached screenshot.
The text was updated successfully, but these errors were encountered: