quadscan

Manual corner correction

Quadscan.extract() performs only the perspective warp. It does not invoke the model, so the singleton stays uninitialized and nothing is downloaded.

Use this when corners come from:

  • a UI where the user dragged them after a detect pass,
  • a previous saved scan,
  • a different detector entirely.

Pattern

import { Quadscan, type CornerPointsInput } from 'quadscan';

const corners: CornerPointsInput = {
  topLeft: { x: 120, y: 80 },
  topRight: { x: 980, y: 100 },
  bottomRight: { x: 1000, y: 1280 },
  bottomLeft: { x: 100, y: 1260 },
};

const file = await fetch('/photo.jpg').then((r) => r.blob());
const result = await Quadscan.extract(file, corners, { output: 'canvas' });

console.log(result.output); // HTMLCanvasElement, perspective-warped

confidence on each corner is optional and defaults to 1.

Combining with detection

A common UX: auto-detect, then let the user fine-tune by dragging four handles. Detect once, treat the corners as mutable state, re-extract on every drag.

const q = new Quadscan();
const detect = await q.scan(canvas, { mode: 'detect' });
if (!detect.success) return;

let corners = detect.corners!; // mutable copy
function onDragEnd() {
  // re-warp without re-running the model
  q.extract(canvas, corners).then((r) => {
    render(r.output); // your renderer of choice
  });
}

See the manual-corners example for the full drag-handles widget.

Output sizing

maxOutputDimension caps the longer side of the warped canvas (default 2048). The aspect ratio is preserved and derived from the average of the opposite sides of the input quad. The warp doesn’t squash a landscape doc into a portrait result.