Closed LaurenzV closed 1 year ago
I've been playing with this branch and found a case where a vertical gradient is rendered upside down.
Here is the SVG (embedded and rendered by GitHub):
Here is a screenshot of the PDF that this branch produces (GitHub doesn't like PDF embedding):
On main, the gradient is oriented correctly
I should add, I've gone through converting all of the SVG's produced by the Vega-Altair Python library in the gallery at https://altair-viz.github.io/gallery/index.html, and the flipped gradient is the only issue I ran into. I'm really excited about how well this already works!
Hmm, that's weird... It seems to look correct in Apple Preview, but in the other ones it's indeed wrong. Will see if I can find the root cause of this.
Thanks for reporting, the bug should be fixed now!
Thanks for reporting, the bug should be fixed now!
Fix confirmed!
I assume this is ready to merge then?
Yep it is!
Wonderful! 🎉
This PR introduces a number of new changes/improvements to
svg2pdf
:Update to resvg 0.35 and fontdb 0.14
The library has been updated to
resvg
0.35.clap
andfontdb
have been bumped as well. As a result of the update of the former dependency, a couple of things had to be changed because there were quite a few breaking changes (one for example being the introduction of quad curves, which are not directly supported in PDF and thus now need to be converted by us. Another breaking change was bboxes do not include the stroke anymore, so I now just reused code from resvg to reintroduce that feature on our end).This now means that in order to use the newest version, we also need to update to
resvg
0.35 in Typst, which I think unfortunately will also require some minor but annoying changes. But I guess there is no rush.Update in logic how
usvg::Group
is dealt withPreviously, we would always create a new XObject whenever we encounter a
usvg::Group
in the tree, which bloated the PDFs by a lot, since a lot of unnecessary overhead was introduced by this. This has now been changed. By default, everything will be written into the main page content stream (or XObject content stream when calling theconvert_tree_into
method), and new XObject's are only generated when needed (e.g. for blend modes). This drastically reduces the file size in many cases. It fixes #35.This unfortunately requires us to keep track of the current transform in some locations because patterns will not be affected by transformations in the content stream, but I believe it is worth the trade-off.
Paths and fills are now rendered seperately
The reason for this is twofold.
Firstly, stroking + filling a path is rendered differently in different viewers. In Acrobat and Google Chrome, the fill is clipped of at the start of the stroke, while in other viewers it is clipped at the center of the stroke. The SVG spec requires them to be clipped at the center. I checked what Adobe Illustrator does, and by default they also always draw stroke and fills separately.
Secondly, there are a couple of cases (for example when applying a mask on a stroke or when we have stroke-and-fill instead of fill-and-stroke order) where we have to draw strokes and fills separately. In order to reduce the number of code paths that can be taken, I decided to simply draw them separately for every shape. The overhead introduced by this seems to be very minimal (although this obviously depends on the SVG) and completely outshadowed by the changes above.
Clip path improvements
Clip paths have been improved upon, and the cases where we fall back to using alpha masks have been reduced to the absolute minimum. This will also finally fix the following issue for all browsers.
Blend modes
Blend modes are now supported. Although apart from Adobe Acrobat, a lot of viewers don't seem to render them correctly.
Tests
resvg
does it in its test suite and I thought it would make sense here too. However, I don't think this makes sense because in our case, whenever we make updates to the logic ofsvg2pdf
, there end up being a lot of tests which need to be regenerated because of pixel differences. This is why I regenerated all tests to be in their original size, so that the overhead for updating the test files won't be as big anymore in the future, especially for integration tests.Other
Apart from that, I refactored some other parts of the program (like for example gradients) to make the code easier to follow.
Results
The results can be seen below. As I did before, I generated a Typst document containing all SVG test cases and rendered them into a PDF.
Current version: current.pdf
New version: new.pdf
Note in particular how the file size dropped from 14.5MB to just 6MB! And this is only because we have a lot of very small SVG files in there, the ones that you encounter normally are usually much larger and the overall gains even bigger.