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
667 stars 104 forks source link

Pattern inside SVG not influenced by SVG offset inside PDF, unexpected point of origin #212

Open DarSim2 opened 2 years ago

DarSim2 commented 2 years ago

I have a SVG containing a pattern and a rect which is filled with said pattern:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.dev/svgjs" width="200" height="200">
    <defs>
        <pattern x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse" id="SvgjsPattern1003">
            <rect width="10" height="10" fill="purple" x="0" y="0"></rect>
            <rect width="10" height="10" fill="pink" x="10" y="10"></rect>
        </pattern>
    </defs>
    <rect width="75" height="75" fill="url('#SvgjsPattern1003')"></rect>
</svg>

When I convert to PDF with a x and/or y offset then the pattern doesn't inherit the offset. It doesn't start at (0, 0) of the SVG inside the PDF but apparently the pattern starts at (0, 0) of the PDF.

const pdfDoc = new jsPDF({ orientation: 'l', unit: 'pt', format: 'a4' })
pdfDoc.svg(nested.node, {
                x: 17,
                y: 32,
            })
            .then(() => {
                pdfDoc.save('testStuffPDF')
            })

And when I print the PDF then the printer adds some margins of its own which offsets the pattern again so that the printed element filled with the pattern doesn't look the same as its counterpart on the screen.

I know that the pattern inside a SVG always starts at (0, 0) of the SVG itself. This is the behavior I would also expect to be seen in the PDF. Pattern should start at the origin of the SVG inside the PDF not the origin of the PDF.

pattern_no_offset.pdf pattern_with_offset.pdf

HackbrettXXX commented 2 years ago

Thanks for the bug report. I was able to reproduce it.

DarSim2 commented 2 years ago

Hi, I just wanted to ask, if there is any development in this matter?

Because this became kind of a pressing matter for me, so I forked svg2pdf and tried to analyze the issue with a collegue. We didn't manage to find a fix. Our current observations are the following, maybe this will help you:

  1. BoundingBox in pattern.ts is calculated correctly (for the pattern element)
  2. Our guess is that the rendered children of the pattern in their render() call do not take the offset of the pattern parent element into account
yGuy commented 2 years ago

Unfortunately, there was no progress, here, so far. We would have removed the "help wanted" tag if we were working on the task. HackbrettXXX is not available at the moment and won't be for the next couple of months, as far as I can tell. I am sorry to say, so we depend on the community to step in.

Is this a problem with the way we interpret the SVG or is this a problem with the way js2pdf writes the PDF? Have you been able to narrow down the issue?

What are the corresponding involved specs for the behavior?

DanielBretzigheimer commented 2 years ago

I have looked into the issue and I am trying to fix it. In my research, I have found some other issues:

  1. using a unit other than pt will scale the pattern elements wrong In the following sample the red rectange has the same size as the blue rectangles in the svg (20 x 20). With unit 'pt' this works correct, but when changed to e.g. 'mm' they scale differently. SVG: image PDF: image

  2. adding an offset to the pattern will result in differences between svg and pdf (see here) image PDF: image

I'll find these bugs and create a PR which hopefully resolves all these issues.

DanielBretzigheimer commented 2 years ago

After further investigation, we found a solution for the scaling problem in units besides pt. We had to apply the context.pdf.internal.scaleFactor to the TilingPattern and the child transform. This worked, but showed the next issue we couldn't solve.

The tiling pattern doesn't start at y = 0 and looks to be offset a little. We speculated that this could be from text baseline or something like that. If you have any idea how this could be fixed, please tell us. We will look further into the issue.

SVG: image

PDF: image

DarSim2 commented 2 years ago

I tried the fix from @DanielBretzigheimer 's PR, it is working 😄

DarSim2 commented 2 years ago

I found another related problem with the pattern in PDF, it also doesn't consider viewbox values of the svg. It just alsways shows the same part of the pattern as if there was no viewbox on the svg

Shiuyin commented 1 year ago

Is there any update to this? Without fixing this issue, it is not possible to use any types of pattern objects in combination with this lib.

yGuy commented 1 year ago

That's not true. For one, there have been improvements (check the commits above) and secondly "not possible to use any type of pattern" is wrong. Many patterns do work. Which one specifically does not work for you? Can you share a repro?

Shiuyin commented 1 year ago

Thanks for your answer.

  1. I know the commits above, i helped DanielBretzigheimer working on them, he is a colleague of mine.
  2. These commits have not been merged into the official lib.
  3. These commits still do not adress open issues with patterns as DarSim2 has pointed out (viewbox handling) and we were unable to fix them on our own when we tried.
  4. Example code is in the original issue, just add a viewbox to it.
yGuy commented 1 year ago

OK. So to summarize: there are still cases that don't work for you, but the feature does work for many other patterns. You helped try to solve the issue (thanks!) but you were unsuccessful and need help. That's what the tag at this issue says. So I guess the answer to your question is: no, there aren't any updates, sorry. If you can find someone who can fix it for you, we will be happy to accept a PR. If this is super important to you, you could open a bounty and have someone work on it.

Shiuyin commented 1 year ago

Correct. I hope to be able to look into it myself in a few weeks again.