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

Embed images with SVG #287

Open Leo-Nicolle opened 6 months ago

Leo-Nicolle commented 6 months ago

Describe the bug

tags with an href pointing to a SVG file are not displayed correctly What version are you using (exact version of and jspdf)? - jspdf: 2.5.1 - svg2pdf.js: 2.2.3 **To Reproduce** 1. Test SVG: ```svg ``` Code: ```js import { jsPDF } from "jspdf"; import "svg2pdf.js"; const svg = document.querySelector("svg"); const doc = new jsPDF({ format: "a4", unit: "pt" }); doc.svg(svg, { x: 0, y: 0, width: 128, height: 64 }).then((doc) => { doc.save("doc.pdf"); }); ``` 3. I get a square with the PNG image but not the SVG [Example Sandbox](https://codesandbox.io/p/sandbox/svg2pdf-embedded-images-fwt6zw?file=%2Fsrc%2Findex.mjs%3A9%2C28&layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522UNKNOWN%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522clw98tzzs00062v6gu4xda3zi%2522%252C%2522sizes%2522%253A%255B100%252C0%255D%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522EDITOR%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522EDITOR%2522%252C%2522id%2522%253A%2522clw98tzzs00022v6gwxwuy1l6%2522%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522direction%2522%253A%2522horizontal%2522%252C%2522id%2522%253A%2522SHELLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522SHELLS%2522%252C%2522id%2522%253A%2522clw98tzzs00032v6gbp53mj2d%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%257D%252C%257B%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522direction%2522%253A%2522vertical%2522%252C%2522id%2522%253A%2522DEVTOOLS%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522contentType%2522%253A%2522DEVTOOLS%2522%252C%2522id%2522%253A%2522clw98tzzs00052v6gmjjtwh22%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%255D%252C%2522sizes%2522%253A%255B76.22562330288818%252C23.77437669711182%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522clw98tzzs00022v6gwxwuy1l6%2522%253A%257B%2522id%2522%253A%2522clw98tzzs00022v6gwxwuy1l6%2522%252C%2522activeTabId%2522%253A%2522clw99adge004u2v6gk94sytq9%2522%252C%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clw98tzzr00012v6gz0xhsz6b%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252Fsrc%252Findex.html%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%252C%257B%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252Fsrc%252Findex.mjs%2522%252C%2522initialSelections%2522%253A%255B%257B%2522startLineNumber%2522%253A9%252C%2522startColumn%2522%253A28%252C%2522endLineNumber%2522%253A9%252C%2522endColumn%2522%253A28%257D%255D%252C%2522id%2522%253A%2522clw99adge004u2v6gk94sytq9%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522state%2522%253A%2522IDLE%2522%257D%255D%257D%252C%2522clw98tzzs00052v6gmjjtwh22%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522clw98tzzs00042v6gwp9sdpn2%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522UNASSIGNED_PORT%2522%252C%2522port%2522%253A0%252C%2522path%2522%253A%2522%252F%2522%257D%255D%252C%2522id%2522%253A%2522clw98tzzs00052v6gmjjtwh22%2522%252C%2522activeTabId%2522%253A%2522clw98tzzs00042v6gwp9sdpn2%2522%257D%252C%2522clw98tzzs00032v6gbp53mj2d%2522%253A%257B%2522tabs%2522%253A%255B%255D%252C%2522id%2522%253A%2522clw98tzzs00032v6gbp53mj2d%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showShells%2522%253Afalse%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D) **Expected behavior** The SVG image should be drawn **Screenshots** Input SVG: ![Screenshot from 2024-05-16 15-27-24](https://github.com/yWorks/svg2pdf.js/assets/7451806/8629539e-290c-4101-bbc0-2dae3909bade) Output PDF: ![Screenshot from 2024-05-16 15-27-08](https://github.com/yWorks/svg2pdf.js/assets/7451806/58fe4a61-c974-4101-9fb0-140204c4f17d) **Desktop (please complete the following information):** - OS: Ubuntu - Browser Chromium - Version 125.0.6422.26
HackbrettXXX commented 2 months ago

Thank you for the bug report. It appears the SVG image is part of the exported PDF but is at the wrong location. Could you provide an example with an image tag linking a much simpler SVG that still reproduces the issue?

Leo-Nicolle commented 2 months ago

Sure ! Here it is !

HackbrettXXX commented 2 months ago

Thanks. I could not reproduce the issue with the sandbox, though. There is a bug in your code:

const svg = document.querySelector("svg");

should be

const svg = document.querySelector("#toexport");

Otherwise, we're just exporting the first SVG. After I fixed it, the exported PDF looks fine.

Leo-Nicolle commented 2 months ago

Hi ! Sorry for the mistake, I might have rushed the second example a little. So I rewinded the tape, copy/pasted the cellphone SVG, and added a shape on the top left corner of it, and TADAA! Both SVG are actually exported, they are just not at the same scale as in the browser. So here is a (working + reproducing the bug) example

On the browser

The SVG to export scales down the second SVG so that it fits within the view Screenshot from 2024-09-03 13-49-54

On the exported PDF:

Both SVGs are rendered in their original scale, and cropped within the view. Screenshot from 2024-09-03 13-49-42

HackbrettXXX commented 2 months ago

Thank you. I can reproduce it now. It seems like this is an issue with the viewbox transformation being applied incorrectly. If I add a viewBox attribute to the referenced image, the result is correct. I suspect the fallback case here is wrong: https://github.com/yWorks/svg2pdf.js/blob/2682632cbd3dae0ac89b40cded663187ed61ef0e/src/nodes/svg.ts#L71-L83

I'm not sure what the expected behavior is if no viewBox attribute is provided. I couldn't find much on a quick scan through the SVG spec.

I'll accept a pull request for this issue. A workaround for now might be to always set the viewBox attribute.