yWorks / svg2pdf.js

A javascript-only SVG to PDF conversion utility that runs in the browser. Brought to you by yWorks - the diagramming experts
MIT License
649 stars 98 forks source link

Linear gradient with repeated stops with `offset="0"` does not render #151

Open goransle opened 3 years ago

goransle commented 3 years ago

Describe the bug Linear gradient with repeated stops with offset="0" does not render.

To Reproduce See this playground.

Expected behavior I would have expected the PDF to render the same way as the SVG. This is in accordance to the following SVG spec: https://www.w3.org/TR/SVG2/pservers.html#StopNotes.

Desktop:

yGuy commented 3 years ago

I can confirm that this doesn't work. I guess the important part of the spec is the following. It also hints at the workaround or possible implementation in the conversion:

If two gradient stops have the same offset value, then the latter gradient stop controls the color value at the overlap point. In particular:

<stop offset="0" stop-color="white"/>
<stop offset=".2" stop-color="red"/>
<stop offset=".2" stop-color="blue"/>
<stop offset="1" stop-color="black"/>

will have approximately the same effect as:

<stop offset="0" stop-color="white"/>
<stop offset=".1999999999" stop-color="red"/>
<stop offset=".2" stop-color="blue"/>
<stop offset="1" stop-color="black"/>

which is a gradient that goes smoothly from white to red, then abruptly shifts from red to blue, and then goes smoothly from blue to black.

yGuy commented 3 years ago

Interestingly this seems to work with values which are not 0 and having two different colors both at 0 really doesn't make any sense. So I would suggest to also reconsider the implementation that actually produces two different colors both at offset 0 what would be the expected behavior in the case, after all?

goransle commented 3 years ago

@yGuy We could replace the second offset with a very low number, but I see now that there is also a difference in the gradient produced then: playground.

yGuy commented 3 years ago

You're right; both (at least Chrome) and the PDF are wrong and behave against the spec. Even with both offsets at exactly 0 you should not be seeing this thin red line in the SVG and the PDF seems to round up the value to about 0.05 But at least with this workaround the PDF isn't completely broken.

HackbrettXXX commented 3 years ago

jsPDF linearly samples the gradient colors, which is why very hard edges are washed out. As a fix we should probably implement the workaround @yGuy mentioned. When there are multiple stops at 0 or 1, we can ignore the "outer" stops.