DEV Community

BellSal
BellSal

Posted on

Your canvas "A4 export" is not A4: DPI, print size, and the number nobody checks

When I added an "A4" preset to a browser-based collage tool, I thought the hard part was the layout maths. It wasn't. The hard part was that "A4" on a canvas is a shape, not a size — and if you don't say that out loud, your users find out at the print shop.

Here is what I got wrong, and the numbers that matter.

A canvas has no physical size

An HTML canvas is a pixel grid. It has width and height in pixels and nothing else. Paper has millimetres. The bridge between them is DPI, and the canvas has no opinion about it.

So when a preset says "A4", all it can honestly promise is the aspect ratio — 1:1.414, the ratio every ISO 216 paper size shares. What those pixels become on paper depends entirely on how many of them you exported.

My preset exports 1414 x 2000 px. That is exactly the A4 ratio. Now convert:

A4 = 210 x 297 mm = 8.27 x 11.69 inches

1414 px / 8.27 in = 171 DPI
2000 px / 11.69 in = 171 DPI
Enter fullscreen mode Exit fullscreen mode

171 DPI. Not 300. For a home or office printer that is genuinely fine — you will not see individual pixels at normal viewing distance. For a photo lab, it is under half the data they expect.

To hit the 300 DPI that print shops assume, the same page needs:

8.27 in x 300 = 2480 px
11.69 in x 300 = 3508 px
Enter fullscreen mode Exit fullscreen mode

2480 x 3508 is 3.1x more pixels than 1414 x 2000. That is the whole trade-off in one line.

Why not just export at 300 DPI then?

Because of memory, and because phones are where people actually use this.

A 2480 x 3508 canvas is 8.7 million pixels. The browser holds it as RGBA, 4 bytes per pixel, so the bitmap alone is about 35 MB before you have drawn anything into it. Now add the source photos: a 12-photo collage where each source is a 12-megapixel phone image is another 576 MB if you keep them all decoded at full size.

That is how you get the crash that only ever happens on someone else's Android phone.

The fix that made this survivable was downscaling every source image on import, before compositing:

const MAX_SOURCE_EDGE = 2400;

function fitSource(img) {
  const longest = Math.max(img.width, img.height);
  if (longest <= MAX_SOURCE_EDGE) return img;
  const scale = MAX_SOURCE_EDGE / longest;
  const c = document.createElement('canvas');
  c.width = Math.round(img.width * scale);
  c.height = Math.round(img.height * scale);
  c.getContext('2d').drawImage(img, 0, 0, c.width, c.height);
  return c;
}
Enter fullscreen mode Exit fullscreen mode

A source image never needs more pixels than the region it will occupy in the output. If a photo lands in a quarter of a 1414 x 2000 page, anything beyond ~1000 px on its long edge is decoded, held in memory, and then thrown away by the scaler. Capping the long edge at 2400 px costs nothing visible and removes most of the memory pressure.

Worth knowing: iOS Safari also caps total canvas area (historically around 16.7 million pixels on older devices). Exceed it and you don't get an exception — you get a blank canvas. Silent failure is the theme of this whole area.

The part that is not technical

None of the above is what users complain about. They complain because they expected "A4" to mean "this will print correctly", and nobody told them otherwise.

So the fix that mattered most was a sentence in the UI, not a line of code: say the export size in pixels, say roughly what DPI that is at A4, and say plainly that it suits a home printer rather than a photo lab. People are completely fine with a limitation they were told about in advance. They are not fine with discovering it after paying for prints.

Two more things worth surfacing while you are at it:

  • Printer margins. Most consumer printers cannot print to the edge and will shrink or crop your page to fit their unprintable margin — usually a few millimetres. A layout that looks perfectly centred on screen comes back visibly off-centre. Either design in a safe margin or warn about "borderless" mode.
  • Orientation. 1414 x 2000 is portrait. Users who want landscape A4 need 2000 x 1414, and if you only ship one, half of them will rotate the image in a photo editor afterwards and lose quality doing it.

The takeaway

If you export anything meant for paper from a canvas, do this arithmetic once and put the result in your interface:

DPI = pixel width / physical width in inches
Enter fullscreen mode Exit fullscreen mode

It takes ten seconds and it is the difference between a tool people trust and one they stop using after a bad print.

The tool this came from is freecollageimage.com — free, browser-only, nothing is uploaded. Full disclosure: it's mine, and the 171 DPI number above is its actual current export, not a hypothetical.

Top comments (0)