Methodology

A reproducible look at the algorithms, libraries and trade-offs behind the editor — so you can decide whether the output is right for your use case.

Decode pipeline

The browser decodes JPG, PNG, WebP, BMP, AVIF and TIFF natively via createImageBitmap. HEIC / HEIF files (the default on modern iPhones) are not natively decoded by Chromium-based browsers, so we route them through heic2any, a WebAssembly port of libheif. The decoded bitmap is then drawn onto an offscreen canvas at its native resolution.

Crop & resize

The crop frame is implemented with react-easy-crop. When you drag or zoom, the component returns pixel coordinates inside the decoded bitmap. Those coordinates are passed to canvas.drawImage(src, sx, sy, sw, sh, 0, 0, dw, dh), which does the resampling. Browsers default to a high-quality bilinear or Lanczos-style filter for downscaling; we never apply our own nearest-neighbor or box filter on top.

Output dimensions are always exact integer pixels. For physical-size presets (e.g. 35×45 mm) we compute pixels as round(mm × DPI / 25.4) at the requested DPI (300 by default for print, 72 for screen).

Compression — binary search over quality

For JPEG and WebP outputs the encoder takes a quality parameter between 0 and 1. Lowering it reduces file size but introduces visible artifacts. To hit a target file size (50 KB, 100 KB, 200 KB, etc.) without unnecessary quality loss we run a binary search:

  1. Encode at quality 0.95 and 0.40 to bracket the search range.
  2. Encode at the midpoint quality. If the result fits the target, raise the lower bound; if it overshoots, lower the upper bound.
  3. Stop after 8 iterations or when two consecutive midpoints produce file sizes within 1.5 KB of the target.

If quality 0.40 still overshoots, we progressively scale the canvas down by 10% and rerun the search. PNG cannot trade quality for size, so for PNG output we only scale.

Background fill

For document photos that require a colored background (white, light gray, blue or yellow) the canvas is filled with the requested color first, then the cropped bitmap is drawn on top. This guarantees the background extends edge-to-edge with the exact RGB value the spec calls for. PNG outputs can also use a transparent background.

Optional background removal

When you click "Remove background", we load the @imgly/background-removal WebAssembly model on demand (about 6 MB, cached after first use). The model runs entirely in your browser via WebGL/WebGPU. No image data is sent to any service.

PDF export

The "Print sheet" feature uses jsPDF to assemble an A4 or US Letter page tiled with copies of your photo at the exact millimeter dimensions you selected. We embed a 300 DPI metadata hint so print shops produce the correct physical size, and we draw cut guides between copies to make trimming easier.

Numerical accuracy

All physical-size math uses double-precision floats, then rounds to the nearest integer pixel only at the very last step. For a 35×45 mm passport at 300 DPI that yields 413×531 px — the dimension most national authorities accept exactly. We never round to 400×500 or other "nicer" numbers.

What the editor will not do

  • No automatic face detection. Detecting faces requires either an AI model that we'd rather not load by default, or sending the image to a service. You position the crop manually — three seconds, fully private.
  • No silent enhancement. We never sharpen, denoise or color-correct your photo unless you explicitly enable an adjustment.
  • No EXIF tampering. The orientation tag is honored before encoding, but we strip personally identifying metadata (GPS, device, owner) from the output by default.

For a step-by-step walkthrough see How it works; for the editorial process behind country specs see Editorial Standards.