Ask Anvil

Answers to questions about automating PDFs, e-signatures, Webforms, and other paperwork problems.
E-signatures
Categories

Why does my drawn signature look blurry in the signed PDF, and how do I fix it?

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

The fastest way to build software for documents

Anvil Document SDK is a comprehensive toolbox for product teams launching document flows where PDF filling, signing, and complex conditional scenarios are necessary.
Explore Anvil
Anvil Webforms
Marketing Mode