Blurry logo or QR code in your PDF? Use SVG or higher-resolution images
Measured: images print at their own pixels, canvases at 96 ppi, and SVG as sharp vectors with selectable text.
A logo that looks crisp on screen can look soft in the PDF, especially when someone zooms in or prints it. The cause is almost always resolution. We drew the same small graphic four ways and zoomed in on the PDF.

What we measured
| Drawn as | In the PDF |
|---|---|
| Inline SVG | Vector shapes and real text: sharp at any zoom, text selectable |
| PNG, 180×90 pixels, shown at 180×90 | Image at 96 ppi |
| PNG or JPEG, 540×270, shown at 180×90 | Image at 288 ppi, original file kept (a JPEG stays a JPEG) |
| Canvas, 180×90 | Image at 96 ppi |
| Canvas, 540×270 shown at 180×90 | Image at 288 ppi |
One CSS pixel is 1/96 of an inch, so an image with one pixel per CSS pixel prints at 96 pixels per inch (ppi). Print usually wants around 300 ppi.
Fixes
- Use SVG for logos, icons, signatures and QR codes. Inline
<svg>stays a vector. Most QR and barcode libraries can output SVG instead of canvas. - For photos and other bitmaps, supply about 3× the pixels and set the display size in HTML: a 600×300 image shown at
width="200" height="100"prints at 288 ppi. - For canvases, scale the backing store. The converter reports
devicePixelRatioas 1, so code that scales by it draws at 96 ppi. Set a larger canvas and scale the drawing context yourself:
const scale = 3;
canvas.width = 180 * scale; canvas.height = 90 * scale;
canvas.style.width = "180px"; canvas.style.height = "90px";
const ctx = canvas.getContext("2d");
ctx.scale(scale, scale); // then draw using 180×90 coordinatesFor Chart.js, the devicePixelRatio: 3 option does the same; see charts in HTML to PDF.
Mind the file size
Higher resolution means bigger files. A few logos at 3× cost very little, but dozens of large photos can push a PDF past the 20 MiB limit. Our photo case study has the numbers. Use JPEG for photos and SVG or PNG for flat graphics.
QR codes
Scanners need clean edges between modules. An SVG QR code with shape-rendering="crispEdges" printed perfectly sharp in our test, and keep a white margin of at least four modules around it.