Notes / 2 of 3

Ten passport specs,
one table.

Regulatory rules look like a design problem and are actually a data problem. The aspect-crop arithmetic almost everyone gets wrong, and the byte limit nobody plans for.

loner10 Nov 20266 mindata modelling

Ask five countries what a passport photo should be and you get five answers that look identical until you read the fine print. 35×45 mm. 2×2 inches. 33×48 mm. Head between 50% and 69% of the height. Background plain white, or off-white, but not cream.

The instinct is to build a form per country. That is the wrong shape. Every one of those rules reduces to a row in a table.

01The table

{ id:'us',  label:'US passport',   w:600, h:600 },  // 2×2 in  @ 300dpi
{ id:'sc',  label:'Schengen visa', w:413, h:531 },  // 35×45 mm @ 300dpi
{ id:'cn',  label:'China visa',    w:390, h:567 },  // 33×48 mm @ 300dpi
{ id:'ca',  label:'Canada',        w:591, h:827 }   // 50×70 mm @ 300dpi

Width, height, and a label. That is the whole domain model. The UI reads it, the cropper reads it, the export reads it. Adding a country is one line, not a new component.

02The number people get wrong

A user uploads a 1200×1600 photo and asks whether it is big enough. The honest answer is: big enough for what?

What matters is not the source size, it is the size of the region left after you crop to the target ratio. Get that wrong and you tell people their photo is fine when it is 30% short.

var ratio = spec.w / spec.h;

var usableW, usableH;
if (W / H > ratio) {          // source too wide — crop the sides
  usableH = H;
  usableW = Math.round(H * ratio);
} else {                       // source too tall — crop top and bottom
  usableW = W;
  usableH = Math.round(W / ratio);
}

var ok = usableW >= spec.w && usableH >= spec.h;

For a 1200×1600 source and a 413×531 target, the usable region is 1200 × 1543 — comfortably enough. For a 500×700 source it is 500 × 643 — also fine on width but only just. Two numbers that look similar produce very different verdicts, and only this arithmetic tells them apart.

Most "your photo was rejected" complaints are not about the photo. They are about a range check that was never written.

03The file-size limit nobody plans for

Governments publish pixel dimensions. What actually rejects uploads is the byte limit — often 240 KB, sometimes 100 KB, occasionally 20 KB. A correctly sized JPEG at quality 94 can easily be 800 KB.

You cannot pick one quality and hope. You have to search:

var q = 0.94;
(function encode(){
  canvas.toBlob(function(blob){
    if (blob.size / 1024 > limit && q > 0.32) {
      q -= 0.09;
      encode();          // async recursion, not a loop
      return;
    }
    save(blob);
  }, 'image/jpeg', q);
})();

Nine iterations at most, each one cheaper than the last. The alternative — a hidden quality slider — pushes a problem the user cannot evaluate onto the user.

04The parts that are not data

Two requirements refuse to fit a table cleanly:

A tool that overstates its certainty is worse than no tool. People submit documents based on what it says.

Worth keeping

  1. Regulatory rules are rows in a table, not screens in a flow.
  2. The number that decides pass or fail is the post-crop region, not the source dimensions.
  3. Byte limits require a search, not a constant.
  4. Where you cannot compute, guide — and say plainly that it is a guide.
PreviousBrowser-side image processingNextThe state broadcast trap