A canvas has two sizes: the bitmap size set by its width and height attributes, and the display size set by CSS. If the bitmap is 400 by 150 and the screen has a device pixel ratio of 2, the browser stretches that bitmap to fill twice as many physical pixels, so strokes look soft. Worse for a signed document, toDataURL() serializes the bitmap, not what you see, so the PNG you stamp onto the PDF is already low resolution.
Fix: size the bitmap for the screen
Give the canvas a CSS size, then set the bitmap to that size multiplied by window.devicePixelRatio and scale the context to match. This is the approach MDN documents for blurry canvases on high-density screens.
const canvas = document.getElementById('sig');
const ctx = canvas.getContext('2d');
function sizeCanvas() {
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect(); // CSS size
canvas.width = Math.floor(rect.width * dpr); // bitmap size (also clears the canvas)
canvas.height = Math.floor(rect.height * dpr);
ctx.scale(dpr, dpr); // draw in CSS pixels from here on
ctx.lineWidth = 2;
ctx.lineCap = 'round';
}
sizeCanvas();
function point(e) {
const r = canvas.getBoundingClientRect();
return [e.clientX - r.left, e.clientY - r.top]; // CSS pixels, no extra ratio
}This assumes the canvas has an explicit CSS width and height, for example style="width:400px;height:150px". Without them, the measured size just echoes the bitmap attributes and nothing changes.
Gotchas
Coordinates change. After ctx.scale(dpr, dpr) you draw in CSS pixels, so the point() helper should return clientX minus the left edge and clientY minus the top edge. If your existing code also multiplies by canvas.width divided by the CSS width, remove that ratio or the ink will land in the wrong place at a ratio above 1.
Setting canvas.width or canvas.height clears the bitmap and resets the context to its defaults, including the transform and line settings. That is why lineWidth and lineCap are set after the resize, and why a window resize handler will wipe a signature unless you save and redraw it.
The extra pixels only help if the PDF step keeps them. When you place the PNG on the page, set its width and height in PDF units rather than letting a library shrink it to the bitmap's pixel size, and avoid re-encoding it as a low-quality JPEG.
Back to All Questions