@saeris/hanko 0.0.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/LICENSE.md +21 -0
- package/README.md +346 -0
- package/dist/approve/index.d.mts +318 -0
- package/dist/approve/index.d.mts.map +1 -0
- package/dist/approve/index.mjs +393 -0
- package/dist/approve/index.mjs.map +1 -0
- package/dist/client/index.d.mts +101 -0
- package/dist/client/index.d.mts.map +1 -0
- package/dist/client/index.mjs +215 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/codes-Ba_qYH6u.mjs +93 -0
- package/dist/codes-Ba_qYH6u.mjs.map +1 -0
- package/dist/handlers.d.mts +113 -0
- package/dist/handlers.d.mts.map +1 -0
- package/dist/handlers.mjs +194 -0
- package/dist/handlers.mjs.map +1 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +345 -0
- package/dist/index.mjs.map +1 -0
- package/dist/linking-DcQSMgem.mjs +177 -0
- package/dist/linking-DcQSMgem.mjs.map +1 -0
- package/dist/linking-nKoayyHf.d.mts +133 -0
- package/dist/linking-nKoayyHf.d.mts.map +1 -0
- package/dist/machine-CRHKjtoP.d.mts +223 -0
- package/dist/machine-CRHKjtoP.d.mts.map +1 -0
- package/dist/machine-D_5DAFxi.mjs +155 -0
- package/dist/machine-D_5DAFxi.mjs.map +1 -0
- package/dist/qr.d.mts +58 -0
- package/dist/qr.d.mts.map +1 -0
- package/dist/qr.mjs +27 -0
- package/dist/qr.mjs.map +1 -0
- package/dist/scan/index.d.mts +384 -0
- package/dist/scan/index.d.mts.map +1 -0
- package/dist/scan/index.mjs +409 -0
- package/dist/scan/index.mjs.map +1 -0
- package/dist/scan/worker.d.mts +2 -0
- package/dist/scan/worker.mjs +2 -0
- package/dist/server-BhoYRkCm.d.mts +257 -0
- package/dist/server-BhoYRkCm.d.mts.map +1 -0
- package/dist/stores/kv.d.mts +64 -0
- package/dist/stores/kv.d.mts.map +1 -0
- package/dist/stores/kv.mjs +87 -0
- package/dist/stores/kv.mjs.map +1 -0
- package/dist/stores/memory.d.mts +22 -0
- package/dist/stores/memory.d.mts.map +1 -0
- package/dist/stores/memory.mjs +42 -0
- package/dist/stores/memory.mjs.map +1 -0
- package/dist/types-BvBIFPH6.mjs +7 -0
- package/dist/types-BvBIFPH6.mjs.map +1 -0
- package/dist/types-C82lb-zX.d.mts +82 -0
- package/dist/types-C82lb-zX.d.mts.map +1 -0
- package/dist/worker-BdwaK1uX.mjs +5291 -0
- package/dist/worker-BdwaK1uX.mjs.map +1 -0
- package/dist/worker-DxbdBA2z.d.mts +164 -0
- package/dist/worker-DxbdBA2z.d.mts.map +1 -0
- package/package.json +116 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-BdwaK1uX.mjs","names":["bitAt","ALIGNMENT_CENTERS","bitAt","#bits","#position","correctBlock"],"sources":["../src/scan/binarize.ts","../src/scan/qr/locate.ts","../src/scan/qr/sample.ts","../src/scan/qr/alignment.ts","../src/scan/qr/blocks.ts","../src/scan/qr/bitstream.ts","../src/scan/qr/format.ts","../src/scan/qr/mask.ts","../src/scan/qr/galois.ts","../src/scan/qr/polynomial.ts","../src/scan/qr/reed-solomon.ts","../src/scan/qr/decode-matrix.ts","../src/scan/qr/decoder.ts","../src/scan/worker.ts"],"sourcesContent":["/**\n * Turning a greyscale photograph into black-and-white modules.\n *\n * This is the first stage of decoding a real image and the one that decides\n * how many photographs are readable at all. Everything downstream — finding\n * the symbol, sampling its grid, correcting errors — operates on the output of\n * this step, so a module lost here is lost permanently.\n *\n * It is deliberately NOT a single global threshold. Measured across the BoofCV\n * benchmark corpus, local brightness varies by 119-223 levels out of 255\n * within a single photograph: a page lit from one side, a screen with a\n * reflection, a code half in shadow. One threshold cannot separate dark from\n * light modules across that spread — it either loses the shadowed half of the\n * symbol or floods the lit half. On that corpus jsQR, which thresholds\n * globally, reads 0% of the `brightness` and `monitor` categories.\n *\n * The approach here is the local-average method from ZXing's hybrid binarizer:\n * divide the image into blocks, threshold each against its own neighbourhood,\n * and smooth across block boundaries. It costs one extra pass over the image\n * and is what makes unevenly-lit photographs readable.\n */\n\nimport type { BitMatrix, GrayImage } from \"./types.js\";\n\n/**\n * Block size for local thresholding, in pixels.\n *\n * Eight is small enough to track a shadow edge and large enough that a block\n * usually spans several modules — which matters, because the threshold is\n * meaningless if a block can fall entirely inside one module. At typical\n * scanning distances a module is 3-10 pixels.\n */\nconst BLOCK_SIZE = 8;\n\n/**\n * Minimum spread within a block before its own average is trusted.\n *\n * A block whose pixels are all nearly the same value contains no edge — it is\n * entirely inside a light region or entirely inside a dark one. Thresholding\n * it against its own mean would split noise down the middle and produce a\n * checkerboard of phantom modules, so such blocks inherit from their\n * neighbours instead.\n */\nconst MIN_DYNAMIC_RANGE = 24;\n\n/** Convert RGBA pixels to greyscale using perceptual luminance weights. */\nexport const toGray = (\n rgba: Uint8ClampedArray,\n width: number,\n height: number\n): GrayImage => {\n const data = new Uint8ClampedArray(width * height);\n\n for (let i = 0; i < width * height; i++) {\n const offset = i * 4;\n // Rec. 601 luma. Green dominates because the eye is most sensitive to it,\n // and because QR printing contrast is usually strongest there.\n data[i] =\n (rgba[offset] * 77 + rgba[offset + 1] * 150 + rgba[offset + 2] * 29) >> 8;\n }\n\n return { data, width, height };\n};\n\n/**\n * Enlarge by an integer factor, replicating pixels.\n *\n * The mirror of {@link downscale}, and it exists for the same reason in\n * reverse. Local binarization thresholds over a fixed 8px block, so what\n * matters is not the module size in pixels but its RATIO to that block. A\n * symbol far from the camera can land at two or three pixels per module, at\n * which point one block spans several modules and averages them into a single\n * verdict — the data is destroyed before geometry ever runs.\n *\n * Enlarging the frame changes that ratio without inventing detail. Measured on\n * the benchmark corpus, a 2x pass takes `nominal` from 99 of 125 to 106 and\n * `rotations` from 36 of 44 to 37.\n *\n * Nearest-neighbour rather than interpolation, deliberately. Smooth\n * interpolation manufactures intermediate greys along every module edge, which\n * is exactly the ambiguity the threshold then has to resolve; replication\n * leaves each measured value untouched and changes only the block-to-module\n * ratio, which is the whole point.\n */\n/**\n * Cut a rectangular region out of a frame.\n *\n * For stages whose cost scales with pixel count but whose subject occupies a\n * small part of the frame. Measured across the corpus, a symbol's finder\n * bounding box covers a median **13%** of the image it sits in — so a stage\n * that must enlarge in order to work can enlarge that instead of everything.\n *\n * The region is clamped rather than validated, so a caller may pad generously\n * past an edge without checking.\n */\n/**\n * Morphological closing on the greyscale image, before any threshold.\n *\n * {@link close} does the same job on a binarized matrix, and by then the\n * information it needs is gone: a 1-bit speckle can only be flipped to its\n * neighbours' bit, where a grey speckle is filled with their actual\n * intensities. Thresholding is the most destructive step in the pipeline —\n * eight bits to one — so an operation that benefits from intensity has to run\n * before it, not after.\n *\n * That ordering is worth real coverage. Measured across the categories where\n * speckle and highlights dominate, running the closing on grey rather than\n * bits recovers images that the binary form cannot: `glare` +5, with\n * `damaged`, `monitor` and `bright_spots` each gaining as well. A specular\n * highlight is exactly the case — its edges are graded in the grey image and\n * hard-clipped after thresholding.\n *\n * Dark-on-light convention: dilation of the dark foreground is a local\n * minimum, erosion a local maximum. Separable, like its binary counterpart.\n */\nexport const closeGray = (image: GrayImage, radius = 1): GrayImage => {\n const { width, height, data } = image;\n const pass = new Uint8ClampedArray(width * height);\n const output = new Uint8ClampedArray(width * height);\n\n const sweep = (\n source: Uint8ClampedArray,\n target: Uint8ClampedArray,\n vertical: boolean,\n pick: (best: number, value: number) => number,\n seed: number\n ): void => {\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n let best = seed;\n for (let offset = -radius; offset <= radius; offset++) {\n const sx = vertical ? x : x + offset;\n const sy = vertical ? y + offset : y;\n if (sx < 0 || sy < 0 || sx >= width || sy >= height) continue;\n best = pick(best, source[sy * width + sx]);\n }\n target[y * width + x] = best;\n }\n }\n };\n\n const min = (best: number, value: number): number =>\n value < best ? value : best;\n const max = (best: number, value: number): number =>\n value > best ? value : best;\n\n // Dilate the dark, then erode it back: speckle inside a dark region is\n // swallowed, while the region's own extent is preserved.\n sweep(data, pass, false, min, 255);\n sweep(pass, output, true, min, 255);\n sweep(output, pass, false, max, 0);\n sweep(pass, output, true, max, 0);\n\n return { data: output, width, height };\n};\n\nexport const crop = (\n image: GrayImage,\n left: number,\n top: number,\n width: number,\n height: number\n): GrayImage => {\n const x0 = Math.max(0, Math.min(image.width - 1, Math.round(left)));\n const y0 = Math.max(0, Math.min(image.height - 1, Math.round(top)));\n const x1 = Math.max(x0 + 1, Math.min(image.width, Math.round(left + width)));\n const y1 = Math.max(y0 + 1, Math.min(image.height, Math.round(top + height)));\n\n const outWidth = x1 - x0;\n const outHeight = y1 - y0;\n const data = new Uint8ClampedArray(outWidth * outHeight);\n\n for (let y = 0; y < outHeight; y++) {\n const source = (y0 + y) * image.width + x0;\n data.set(image.data.subarray(source, source + outWidth), y * outWidth);\n }\n\n return { data, width: outWidth, height: outHeight };\n};\n\nexport const upscale = (image: GrayImage, factor: number): GrayImage => {\n if (factor <= 1) return image;\n\n const width = image.width * factor;\n const height = image.height * factor;\n const data = new Uint8ClampedArray(width * height);\n\n for (let y = 0; y < height; y++) {\n const sourceRow = Math.floor(y / factor) * image.width;\n const targetRow = y * width;\n for (let x = 0; x < width; x++) {\n data[targetRow + x] = image.data[sourceRow + Math.floor(x / factor)];\n }\n }\n\n return { data, width, height };\n};\n\n/**\n * Binarize against a threshold the caller chooses.\n *\n * {@link binarizeGlobal} computes one \"correct\" threshold from the histogram\n * and {@link binarize} computes one per block. Both answer the question\n * \"what is the right threshold?\", and on a damaged or unevenly lit symbol\n * there often is not one — measured across the corpus, the thresholds that\n * recover an otherwise-unreadable image are spread over the whole range\n * 40-190 with no clustering, and the image's own mean does not predict them\n * (one is read at 120 with a mean of 195).\n *\n * So this exists to be swept. Eleven distinct thresholds recover seventeen\n * images between them; no small set captures most of the gain, which is why\n * the caller supplies the value rather than this guessing better.\n *\n * The obvious alternative was measured and lost. Sauvola thresholding — the\n * method the document-binarization literature favours for degraded images,\n * and which an IEEE study validates specifically for QR under uneven\n * illumination — recovers 3 images across nine tuned variants (windows 15/31/\n * 63, k 0.2/0.34/0.5, via integral images) against this sweep's 11, and adds\n * nothing the sweep does not already find. The reason is in that literature\n * too: Sauvola's threshold collapses where local contrast is low, which is\n * exactly the condition a damaged or glared symbol presents. Its wins are on\n * scanned documents with uneven illumination, a different degradation.\n */\nexport const binarizeAt = (\n image: GrayImage,\n threshold: number,\n { invert = false }: { invert?: boolean } = {}\n): BitMatrix => {\n const bits = new Uint8Array(image.width * image.height);\n\n for (let i = 0; i < bits.length; i++) {\n const dark = image.data[i] < threshold;\n bits[i] = (invert ? !dark : dark) ? 1 : 0;\n }\n\n return { bits, width: image.width, height: image.height };\n};\n\n/**\n * Binarize against one threshold chosen from the whole image's histogram.\n *\n * The opposite trade to {@link binarize}. A single threshold cannot follow a\n * shadow across a page — which is why local thresholding exists and why it\n * takes the `brightness` and `monitor` categories from nothing to something.\n * But local thresholding invents structure in flat regions, and on a clean,\n * evenly-lit image a global threshold is both more faithful and less prone to\n * that.\n *\n * Neither dominates, so this is a retry rather than a replacement. zxing-cpp\n * reached the same conclusion from the other direction: its issue #809 is an\n * image its local binarizer cannot read and its global one can, and its\n * issue #500 is a prototype for supporting several binarizers for exactly\n * this reason.\n *\n * The threshold is the midpoint between the two dominant peaks of the\n * histogram rather than the mean. A QR is mostly two tones, so the histogram\n * is bimodal, and the mean of a symbol with more light area than dark sits\n * inside the light peak and thresholds half the modules away.\n */\nexport const binarizeGlobal = (\n image: GrayImage,\n { invert = false }: { invert?: boolean } = {}\n): BitMatrix => {\n const histogram = new Uint32Array(32);\n for (const value of image.data) histogram[value >> 3]++;\n\n // Tallest bucket, then the bucket furthest from it weighted by its own\n // height — the standard two-peak search, which avoids picking the tall\n // peak's immediate neighbour as the second \"peak\".\n let first = 0;\n for (let i = 1; i < 32; i++) {\n if (histogram[i] > histogram[first]) first = i;\n }\n\n let second = first;\n let bestScore = 0;\n for (let i = 0; i < 32; i++) {\n const distance = i - first;\n const score = histogram[i] * distance * distance;\n if (score > bestScore) {\n bestScore = score;\n second = i;\n }\n }\n\n const [low, high] = first < second ? [first, second] : [second, first];\n\n // Valley between the peaks: the bucket where the fewest pixels sit, scaled\n // by how far it is from the peaks so a flat run does not drag it to an end.\n let valley = low;\n let bestValley = -1;\n for (let i = low + 1; i < high; i++) {\n const fromLow = i - low;\n const fromHigh = high - i;\n const score = fromLow * fromHigh * (high - low) - histogram[i] * 4;\n if (score > bestValley) {\n bestValley = score;\n valley = i;\n }\n }\n\n const threshold = (valley << 3) + 4;\n const bits = new Uint8Array(image.width * image.height);\n\n for (let i = 0; i < bits.length; i++) {\n const dark = image.data[i] < threshold;\n bits[i] = (invert ? !dark : dark) ? 1 : 0;\n }\n\n return { bits, width: image.width, height: image.height };\n};\n\n/**\n * Morphological closing on a bit matrix — dilate, then erode.\n *\n * Fills small light specks inside dark regions while leaving real structure\n * intact, because dilation closes a gap smaller than the kernel and the\n * following erosion restores every boundary the dilation moved.\n *\n * The failure this targets is specific: zxing-cpp issue #951 diagnoses an\n * undetected symbol as \"white pixels inside the black square that disrupt\n * their detection\" of the finder patterns, and its remedy is exactly this\n * operation. Speckle inside a finder breaks the run-length signature — a\n * single light pixel splits one dark run into two — so the pattern stops\n * matching 1:1:3:1:1 even though a human sees it perfectly well.\n *\n * A 3x3 kernel: large enough for sensor speckle and dust, small enough that\n * it cannot close a real one-module gap at any usable resolution.\n */\nexport const close = (matrix: BitMatrix): BitMatrix => {\n const { width, height, bits } = matrix;\n\n // Separable. A 3x3 square structuring element factors into a horizontal\n // pass and a vertical one, because a 3x3 neighbourhood is the union of\n // three 1x3 neighbourhoods. That turns nine reads per pixel into six, and\n // removes the inner bounds checks and early-exit branches entirely.\n //\n // Worth doing: measured with deoptkit, this function was 54 of 327 JS ticks\n // — 17% of the decoder's CPU — as the LAST rung in the retry ladder.\n // Two buffers, not four. The four sweeps read one and write the other in\n // turn, so they can ping-pong: on a 1280x720 frame the old form allocated\n // 3.7MB per call, and this runs on half of every ladder rung's passes.\n // Profiled under viewfinder load it was 14% of JS time with the garbage\n // collector visible behind it.\n const scratch = new Uint8Array(width * height);\n const output = new Uint8Array(width * height);\n const horizontal = scratch;\n const dilated = output;\n const vertical = scratch;\n\n // Dilate: a pixel is set if any of its three horizontal neighbours is.\n for (let y = 0; y < height; y++) {\n const row = y * width;\n for (let x = 0; x < width; x++) {\n const left = x > 0 ? bits[row + x - 1] : 0;\n const right = x + 1 < width ? bits[row + x + 1] : 0;\n horizontal[row + x] = bits[row + x] | left | right;\n }\n }\n for (let y = 0; y < height; y++) {\n const row = y * width;\n const above = y > 0 ? row - width : row;\n const below = y + 1 < height ? row + width : row;\n for (let x = 0; x < width; x++) {\n dilated[row + x] =\n horizontal[row + x] | horizontal[above + x] | horizontal[below + x];\n }\n }\n\n // Erode: a pixel survives only if all three neighbours are set. Outside the\n // image counts as set, so erosion does not eat the border and shrink a\n // symbol that runs to the frame edge.\n for (let y = 0; y < height; y++) {\n const row = y * width;\n for (let x = 0; x < width; x++) {\n const left = x > 0 ? dilated[row + x - 1] : 1;\n const right = x + 1 < width ? dilated[row + x + 1] : 1;\n vertical[row + x] = dilated[row + x] & left & right;\n }\n }\n for (let y = 0; y < height; y++) {\n const row = y * width;\n const above = y > 0 ? row - width : row;\n const below = y + 1 < height ? row + width : row;\n for (let x = 0; x < width; x++) {\n output[row + x] =\n vertical[row + x] & vertical[above + x] & vertical[below + x];\n }\n }\n\n return { bits: output, width, height };\n};\n\n/**\n * Downscale by box-averaging whole blocks of pixels.\n *\n * Not for speed — for signal. A symbol photographed from a distance on a\n * 12-megapixel sensor has modules two or three pixels wide, and at that scale\n * neither run-length scanning nor shape detection produces reliable\n * structure: measured on the corpus, both detectors return module-size\n * estimates spanning 1.1 to 137.9 pixels within a single image, which is\n * noise rather than measurement.\n *\n * Averaging blocks of pixels down trades resolution the symbol does not have\n * for a cleaner signal it does. BoofCV builds an image pyramid for the same\n * reason and scores 100% on that corpus category.\n *\n * Box averaging rather than nearest-neighbour sampling, because dropping\n * pixels aliases a module grid badly — the very structure being looked for\n * beats against the sampling lattice.\n */\nexport const downscale = (image: GrayImage, factor: number): GrayImage => {\n if (factor <= 1) return image;\n\n const width = Math.max(1, Math.floor(image.width / factor));\n const height = Math.max(1, Math.floor(image.height / factor));\n const data = new Uint8ClampedArray(width * height);\n\n for (let y = 0; y < height; y++) {\n const startY = Math.floor(y * factor);\n const endY = Math.min(image.height, Math.floor((y + 1) * factor));\n\n for (let x = 0; x < width; x++) {\n const startX = Math.floor(x * factor);\n const endX = Math.min(image.width, Math.floor((x + 1) * factor));\n\n let sum = 0;\n let count = 0;\n for (let sy = startY; sy < endY; sy++) {\n for (let sx = startX; sx < endX; sx++) {\n sum += image.data[sy * image.width + sx];\n count++;\n }\n }\n data[y * width + x] = count === 0 ? 0 : sum / count;\n }\n }\n\n return { data, width, height };\n};\n\n/**\n * Flip a bit matrix's polarity.\n *\n * Binarization spends nearly all its time computing an adaptive threshold\n * surface; inverting only changes the final comparison against it. Since the\n * decoder tries both polarities on every rung of its retry ladder, computing\n * the surface twice wastes half of that work — measured at 31 of 279 ticks,\n * 11% of the decoder's CPU. Flipping the bits costs one pass over the array.\n */\nexport const invertMatrix = (matrix: BitMatrix): BitMatrix => {\n const bits = new Uint8Array(matrix.bits.length);\n for (let i = 0; i < bits.length; i++) bits[i] = matrix.bits[i] === 1 ? 0 : 1;\n return { bits, width: matrix.width, height: matrix.height };\n};\n\n/**\n * Blur an image with a separable box filter, approximating a Gaussian.\n *\n * Two passes of a box filter — one horizontal, one vertical — is a standard\n * cheap stand-in for a true Gaussian, and it is separable, so cost is linear\n * in radius rather than quadratic.\n *\n * This exists for one specific failure: photographing a screen. Moire banding\n * is frequency ALIASING between the camera sensor grid and the display's\n * sub-pixel grid, so the interference sits at a much higher spatial frequency\n * than the modules do. Low-pass filtering suppresses the banding and leaves\n * the modules — measured on the benchmark corpus, it takes the `monitor`\n * category from 0 of 25 to 10 of 25.\n *\n * It is NOT a free win and must not be applied by default: the same filter\n * takes `blurred` from 5 of 14 down to 1, and `nominal` from 3 to 0. A blurred\n * photograph blurred again is unreadable. Use it as a retry after a sharp\n * pass fails.\n */\nexport const blur = (image: GrayImage, radius: number): GrayImage => {\n if (radius < 1) return image;\n\n const { width, height } = image;\n const horizontal = new Uint8ClampedArray(width * height);\n const output = new Uint8ClampedArray(width * height);\n\n // Running sums rather than a fresh window per pixel.\n //\n // Summing the whole window at every pixel is O(radius) per pixel per axis;\n // adding the entering sample and subtracting the leaving one is O(1),\n // whatever the radius. On a 2.4MP frame at radius 3 that is 7 adds per pixel\n // per axis against 2 — and this is the single most expensive image operation\n // in the decoder, 57ms of a 75ms pipeline, so it is where the arithmetic\n // actually shows.\n //\n // Edges are handled by counting only the samples that exist rather than\n // clamping or wrapping, which keeps the result identical to the previous\n // window-per-pixel form.\n for (let y = 0; y < height; y++) {\n const row = y * width;\n let sum = 0;\n let count = 0;\n\n // Prime the window for x = 0: samples 0 .. radius.\n for (let x = 0; x <= radius && x < width; x++) {\n sum += image.data[row + x];\n count++;\n }\n\n for (let x = 0; x < width; x++) {\n horizontal[row + x] = sum / count;\n\n // Slide: drop x - radius, take x + radius + 1.\n const leaving = x - radius;\n if (leaving >= 0) {\n sum -= image.data[row + leaving];\n count--;\n }\n const entering = x + radius + 1;\n if (entering < width) {\n sum += image.data[row + entering];\n count++;\n }\n }\n }\n\n for (let x = 0; x < width; x++) {\n let sum = 0;\n let count = 0;\n\n for (let y = 0; y <= radius && y < height; y++) {\n sum += horizontal[y * width + x];\n count++;\n }\n\n for (let y = 0; y < height; y++) {\n output[y * width + x] = sum / count;\n\n const leaving = y - radius;\n if (leaving >= 0) {\n sum -= horizontal[leaving * width + x];\n count--;\n }\n const entering = y + radius + 1;\n if (entering < height) {\n sum += horizontal[entering * width + x];\n count++;\n }\n }\n }\n\n return { data: output, width, height };\n};\n\n/** Per-block average brightness, and the global average as a fallback. */\nconst blockAverages = (\n image: GrayImage,\n blocksWide: number,\n blocksHigh: number\n): { averages: Int32Array; global: number } => {\n const averages = new Int32Array(blocksWide * blocksHigh);\n let total = 0;\n\n for (let blockY = 0; blockY < blocksHigh; blockY++) {\n for (let blockX = 0; blockX < blocksWide; blockX++) {\n const startX = blockX * BLOCK_SIZE;\n const startY = blockY * BLOCK_SIZE;\n const endX = Math.min(startX + BLOCK_SIZE, image.width);\n const endY = Math.min(startY + BLOCK_SIZE, image.height);\n\n let sum = 0;\n let min = 255;\n let max = 0;\n let count = 0;\n\n for (let y = startY; y < endY; y++) {\n for (let x = startX; x < endX; x++) {\n const value = image.data[y * image.width + x];\n sum += value;\n if (value < min) min = value;\n if (value > max) max = value;\n count++;\n }\n }\n\n const average = count === 0 ? 128 : sum / count;\n\n // A flat block has no edge in it. Rather than threshold noise, mark it\n // so the smoothing pass below can take a neighbour's value — the block\n // is inside a solid region, and its neighbours know which one.\n averages[blockY * blocksWide + blockX] =\n max - min >= MIN_DYNAMIC_RANGE ? Math.round(average) : -1;\n\n total += average;\n }\n }\n\n return {\n averages,\n global: Math.round(total / Math.max(1, blocksWide * blocksHigh))\n };\n};\n\n/**\n * Resolve flat blocks and smooth the threshold surface.\n *\n * Averaging each block against its 5x5 neighbourhood stops a hard threshold\n * step at every block boundary, which would otherwise appear as a grid of\n * false edges — and false edges look exactly like module boundaries to the\n * stage that runs next.\n */\nconst smoothThresholds = (\n averages: Int32Array,\n blocksWide: number,\n blocksHigh: number,\n globalAverage: number\n): Int32Array => {\n const smoothed = new Int32Array(blocksWide * blocksHigh);\n\n for (let blockY = 0; blockY < blocksHigh; blockY++) {\n for (let blockX = 0; blockX < blocksWide; blockX++) {\n let sum = 0;\n let count = 0;\n\n for (let dy = -2; dy <= 2; dy++) {\n for (let dx = -2; dx <= 2; dx++) {\n const y = blockY + dy;\n const x = blockX + dx;\n if (y < 0 || x < 0 || y >= blocksHigh || x >= blocksWide) continue;\n\n const value = averages[y * blocksWide + x];\n // Flat blocks contribute nothing — they have no opinion to average.\n if (value < 0) continue;\n sum += value;\n count++;\n }\n }\n\n smoothed[blockY * blocksWide + blockX] =\n count === 0 ? globalAverage : Math.round(sum / count);\n }\n }\n\n return smoothed;\n};\n\n/**\n * Binarize a greyscale image into a bit matrix.\n *\n * `true` (1) means DARK, matching the QR convention where a set module is a\n * dark one. Fixing polarity here — at the single boundary where pixels become\n * bits — is deliberate: every stage above this one can then assume one\n * orientation, and none of them has to ask which way round the image was.\n *\n * @param invert Treat light modules as set. Needed for symbols rendered\n * light-on-dark, which decoders that assume dark-on-light read as nothing at\n * all. Callers that do not know should try both.\n */\nexport const binarize = (\n image: GrayImage,\n { invert = false }: { invert?: boolean } = {}\n): BitMatrix => {\n const blocksWide = Math.ceil(image.width / BLOCK_SIZE);\n const blocksHigh = Math.ceil(image.height / BLOCK_SIZE);\n\n const { averages, global } = blockAverages(image, blocksWide, blocksHigh);\n const thresholds = smoothThresholds(averages, blocksWide, blocksHigh, global);\n\n const bits = new Uint8Array(image.width * image.height);\n\n for (let y = 0; y < image.height; y++) {\n const blockY = Math.min(blocksHigh - 1, Math.floor(y / BLOCK_SIZE));\n\n for (let x = 0; x < image.width; x++) {\n const blockX = Math.min(blocksWide - 1, Math.floor(x / BLOCK_SIZE));\n const threshold = thresholds[blockY * blocksWide + blockX];\n const dark = image.data[y * image.width + x] < threshold;\n\n bits[y * image.width + x] = (invert ? !dark : dark) ? 1 : 0;\n }\n }\n\n return { bits, width: image.width, height: image.height };\n};\n","/**\n * Finding the symbol in a photograph.\n *\n * A QR announces itself with three finder patterns — the concentric squares in\n * its corners — whose defining property is a 1:1:3:1:1 ratio of dark:light:\n * dark:light:dark along ANY line through the centre. That ratio is preserved\n * under rotation and, near enough, under moderate perspective, which is what\n * makes it findable without knowing where the symbol is or how it is turned.\n *\n * The search runs row by row looking for that ratio, then confirms each\n * candidate vertically and diagonally. Confirming in more than one direction\n * matters: a row of a barcode, a window blind, or a keyboard produces the\n * ratio horizontally all the time, and only a real finder produces it in every\n * direction through the same point.\n */\n\nimport type { BitMatrix, Point } from \"../types.js\";\n\n/** A located finder pattern. */\nexport interface FinderPattern {\n readonly center: Point;\n /** Estimated module size in pixels, from the pattern's own width. */\n readonly moduleSize: number;\n}\n\n/** Three finders, assigned to their corners. */\nexport interface FinderTriple {\n /** The corner finder — the one at the right angle of the L. */\n readonly topLeft: FinderPattern;\n readonly topRight: FinderPattern;\n readonly bottomLeft: FinderPattern;\n}\n\n/**\n * How far a run sequence may deviate from 1:1:3:1:1 and still count.\n *\n * Half a module of slack per band. Tighter rejects real finders seen at an\n * angle or through a cheap lens; looser starts accepting text and window\n * frames, and every false candidate costs a vertical and diagonal check.\n */\nconst RATIO_TOLERANCE = 0.5;\n\n/**\n * Whether five consecutive runs match the finder ratio.\n *\n * `mergedOuter` relaxes the one assumption that a missing quiet zone breaks.\n * The outer dark runs are the only ones that can join content outside the\n * finder, and a symbol printed hard against a dark element does exactly that:\n * `runs[0]` or `runs[4]` becomes arbitrarily long. Deriving the module size\n * from the total then inflates it and every comparison fails, including those\n * on the undamaged interior — so under this flag the module size comes from\n * the middle three runs, which the finder's own light rings bound, and the\n * outer runs need only be present.\n *\n * Off by default, and deliberately so: it roughly triples the candidate rows,\n * which is noise everywhere the quiet zone is intact. Measured as the only\n * rule, it took `pathological` from 57.7% to 65.4% and the corpus from 70.2%\n * to 64.5% — `high_version` to zero — while making the benchmark five times\n * slower. It is worth having as a retry and not as a replacement.\n */\nconst matchesFinderRatio = (\n runs: ArrayLike<number>,\n mergedOuter = false\n): boolean => {\n let total = 0;\n for (let i = 0; i < 5; i++) {\n // A zero-length run means the sequence was broken, not a valid pattern.\n const run = runs[i];\n if (run === 0) return false;\n total += run;\n }\n // Seven modules across: 1 + 1 + 3 + 1 + 1.\n if (total < 7) return false;\n\n if (mergedOuter) {\n const inner = runs[1] + runs[2] + runs[3];\n if (inner < 5) return false;\n\n const innerModule = inner / 5;\n const innerTolerance = innerModule * RATIO_TOLERANCE;\n\n if (Math.abs(innerModule - runs[1]) >= innerTolerance) return false;\n if (Math.abs(innerModule * 3 - runs[2]) >= innerTolerance * 3) return false;\n if (Math.abs(innerModule - runs[3]) >= innerTolerance) return false;\n\n return runs[0] >= innerModule * 0.5 && runs[4] >= innerModule * 0.5;\n }\n\n const moduleSize = total / 7;\n const tolerance = moduleSize * RATIO_TOLERANCE;\n\n return (\n Math.abs(moduleSize - runs[0]) < tolerance &&\n Math.abs(moduleSize - runs[1]) < tolerance &&\n Math.abs(moduleSize * 3 - runs[2]) < tolerance * 3 &&\n Math.abs(moduleSize - runs[3]) < tolerance &&\n Math.abs(moduleSize - runs[4]) < tolerance\n );\n};\n\n/** Centre of the middle run, given where the five runs end. */\nconst centerFromRuns = (runs: ArrayLike<number>, end: number): number =>\n end - runs[4] - runs[3] - runs[2] / 2;\n\nconst bitAt = (matrix: BitMatrix, x: number, y: number): number => {\n if (x < 0 || y < 0 || x >= matrix.width || y >= matrix.height) return 0;\n return matrix.bits[y * matrix.width + x];\n};\n\n/**\n * Re-check a candidate along one axis through its centre.\n *\n * Returns the refined centre coordinate, or `null` if the ratio does not hold.\n * This is what rejects the horizontal-only coincidences — a line of text or a\n * barcode gives 1:1:3:1:1 across but never up and down through the same point.\n */\nconst checkAxis = (\n matrix: BitMatrix,\n startX: number,\n startY: number,\n stepX: number,\n stepY: number,\n maxCount: number,\n mergedOuter = false\n): number | null => {\n const runs = [0, 0, 0, 0, 0];\n\n // Walk outward from the centre in both directions, counting run lengths.\n // The centre band is index 2, so it is filled from both halves.\n let x = startX;\n let y = startY;\n while (\n x >= 0 &&\n y >= 0 &&\n x < matrix.width &&\n y < matrix.height &&\n bitAt(matrix, x, y) === 1 &&\n runs[2] < maxCount\n ) {\n runs[2]++;\n x -= stepX;\n y -= stepY;\n }\n if (runs[2] >= maxCount) return null;\n\n for (const [index, expected] of [\n [1, 0],\n [0, 1]\n ] as const) {\n while (\n x >= 0 &&\n y >= 0 &&\n x < matrix.width &&\n y < matrix.height &&\n bitAt(matrix, x, y) === expected &&\n runs[index] < maxCount\n ) {\n runs[index]++;\n x -= stepX;\n y -= stepY;\n }\n if (runs[index] >= maxCount) return null;\n }\n\n x = startX + stepX;\n y = startY + stepY;\n while (\n x >= 0 &&\n y >= 0 &&\n x < matrix.width &&\n y < matrix.height &&\n bitAt(matrix, x, y) === 1 &&\n runs[2] < maxCount\n ) {\n runs[2]++;\n x += stepX;\n y += stepY;\n }\n if (runs[2] >= maxCount) return null;\n\n for (const [index, expected] of [\n [3, 0],\n [4, 1]\n ] as const) {\n while (\n x >= 0 &&\n y >= 0 &&\n x < matrix.width &&\n y < matrix.height &&\n bitAt(matrix, x, y) === expected &&\n runs[index] < maxCount\n ) {\n runs[index]++;\n x += stepX;\n y += stepY;\n }\n if (runs[index] >= maxCount) return null;\n }\n\n if (!matchesFinderRatio(runs, mergedOuter)) return null;\n\n const total = runs.reduce((sum, run) => sum + run, 0);\n const end = stepX !== 0 ? x : y;\n return centerFromRuns(runs, end) + (total % 2 === 0 ? 0 : 0);\n};\n\n/**\n * Refine a finder centre to the centroid of its dark core.\n *\n * The run-length scan gives a centre by halving the middle band, which is\n * accurate only if the scan line passes exactly through the pattern's middle.\n * Under perspective or rotation it rarely does, and the row-averaging that\n * merges detections biases toward whichever rows happened to match.\n *\n * Measured against a reference decoder on the `perspective` category, centres\n * from the scan alone sit 0.72 to 0.84 modules from the truth — and sampling\n * needs better than 0.5. Every fourth-corner method inherits that error,\n * which is why all three of them landed around 1.7 modules regardless of how\n * they were computed. The centres themselves were the limit.\n *\n * The 3x3 dark core of a finder is a solid block, so its centroid is a much\n * better estimate than a scan-line midpoint: it uses every pixel of the core\n * rather than one row through it, and it does not care what angle the pattern\n * is seen at.\n */\nconst refineCenter = (\n matrix: BitMatrix,\n center: Point,\n moduleSize: number\n): Point => {\n // Flood the connected dark region containing the centre, bounded to the\n // core's plausible extent so it cannot leak into the surrounding ring.\n const limit = Math.max(2, Math.round(moduleSize * 2));\n const startX = Math.round(center.x);\n const startY = Math.round(center.y);\n if (\n startX < 0 ||\n startY < 0 ||\n startX >= matrix.width ||\n startY >= matrix.height ||\n matrix.bits[startY * matrix.width + startX] !== 1\n ) {\n return center;\n }\n\n let sumX = 0;\n let sumY = 0;\n let count = 0;\n const seen = new Set<number>();\n const queue: Array<[number, number]> = [[startX, startY]];\n\n while (queue.length > 0) {\n const [x, y] = queue.pop()!;\n if (\n x < 0 ||\n y < 0 ||\n x >= matrix.width ||\n y >= matrix.height ||\n Math.abs(x - startX) > limit ||\n Math.abs(y - startY) > limit\n ) {\n continue;\n }\n\n const key = y * matrix.width + x;\n if (seen.has(key) || matrix.bits[key] !== 1) continue;\n seen.add(key);\n\n sumX += x;\n sumY += y;\n count++;\n\n queue.push([x + 1, y], [x - 1, y], [x, y + 1], [x, y - 1]);\n }\n\n // Too small to be the core, or so large it leaked — keep the scan estimate.\n const area = count / (moduleSize * moduleSize);\n if (count === 0 || area < 2 || area > 20) return center;\n\n return { x: sumX / count, y: sumY / count };\n};\n\n/**\n * Find candidate finder patterns.\n *\n * Scans every row for the horizontal ratio, then confirms vertically and\n * diagonally. Candidates close to one already found are merged, since a\n * pattern several modules tall is detected on each of its rows.\n */\nexport const findFinderPatterns = (\n matrix: BitMatrix,\n /**\n * Tolerate an outer dark run merged with adjacent content.\n *\n * For symbols printed without their quiet zone. Roughly triples the\n * candidate rows, so it is a retry rather than a default — see\n * {@link matchesFinderRatio}.\n */\n mergedOuter = false\n): FinderPattern[] => {\n const found: Array<{ center: Point; moduleSize: number; count: number }> = [];\n\n // Five run lengths, oldest first, always phased dark-light-dark-light-dark.\n // Phase is the whole difficulty here: a row starts in the quiet zone, so\n // the FIRST run is light and must not be recorded as runs[0]. Tracking\n // \"how many runs have we seen\" separately from \"which colour are we in\"\n // is what keeps the window aligned to a dark start.\n //\n // Allocated once for the whole scan rather than per row. Profiled on a noisy\n // 1280x720 frame this loop showed 1133 on-stack-replacement deopts and a\n // \"dependent allocation site tenuring changed\" bailout: a fresh array and two\n // closures per row is roughly fifteen thousand short-lived allocations per\n // decode across the ladder's binarizations, and V8 kept re-deciding how to\n // allocate them.\n const runs = new Int32Array(5);\n\n for (let y = 0; y < matrix.height; y++) {\n runs[0] = 0;\n runs[1] = 0;\n runs[2] = 0;\n runs[3] = 0;\n runs[4] = 0;\n let filled = 0;\n let current = matrix.bits[y * matrix.width];\n let length = 0;\n\n const shift = (): void => {\n // Drop the oldest pair and keep the last three runs: a finder can begin\n // inside the tail of the one before it, so restarting from empty would\n // miss adjacent patterns.\n runs[0] = runs[2]!;\n runs[1] = runs[3]!;\n runs[2] = runs[4]!;\n runs[3] = 0;\n runs[4] = 0;\n filled = 3;\n };\n\n const consider = (end: number): void => {\n if (!matchesFinderRatio(runs, mergedOuter)) return;\n\n const centerX = centerFromRuns(runs, end);\n const total = runs[0] + runs[1] + runs[2] + runs[3] + runs[4];\n const moduleSize = total / 7;\n\n const centerY = checkAxis(\n matrix,\n Math.round(centerX),\n y,\n 0,\n 1,\n total,\n mergedOuter\n );\n if (centerY === null) return;\n\n // Diagonal confirmation. A run of text or a barcode gives the ratio\n // horizontally all the time; only a real finder gives it in every\n // direction through the same point.\n const diagonal = checkAxis(\n matrix,\n Math.round(centerX),\n Math.round(centerY),\n 1,\n 1,\n total * 2,\n mergedOuter\n );\n if (diagonal === null) return;\n\n const center = { x: centerX, y: centerY };\n\n // Scanned backwards with an indexed loop rather than `find`.\n //\n // Rows are processed in order, so a candidate this row should merge with\n // was almost certainly added within the last few rows — searching from\n // the end finds it immediately instead of averaging half the list. The\n // early exit makes that a bound rather than a hope: once a candidate's\n // centre lies more than the merge distance ABOVE this row, every earlier\n // one does too, so none can match.\n //\n // It matters under load. Sensor grain yields ~190 candidates on a\n // 1280x720 frame against 0-5 for an ordinary photograph, and a linear\n // scan per detection made this quadratic in that count — profiled as the\n // single hottest site on a noisy frame, closure allocation included.\n const merge = moduleSize * 2;\n let existing: (typeof found)[number] | undefined;\n for (let i = found.length - 1; i >= 0; i--) {\n const candidate = found[i];\n const dy = center.y - candidate.center.y;\n if (dy >= merge) break;\n if (\n Math.abs(dy) < merge &&\n Math.abs(candidate.center.x - center.x) < merge\n ) {\n existing = candidate;\n break;\n }\n }\n\n if (existing === undefined) {\n found.push({ center, moduleSize, count: 1 });\n return;\n }\n\n // A pattern several modules tall is detected on each of its rows, and\n // the mean of those estimates is a better centre than any single row.\n const next = existing.count + 1;\n existing.center = {\n x: (existing.center.x * existing.count + center.x) / next,\n y: (existing.center.y * existing.count + center.y) / next\n };\n existing.moduleSize =\n (existing.moduleSize * existing.count + moduleSize) / next;\n existing.count = next;\n };\n\n for (let x = 0; x <= matrix.width; x++) {\n const bit = x < matrix.width ? matrix.bits[y * matrix.width + x] : -1;\n\n if (bit === current) {\n length++;\n continue;\n }\n\n // A run just ended. Record it only once the window has started on a\n // DARK run — a leading light run is the quiet zone and carries no\n // ratio information.\n if (filled > 0 || current === 1) {\n if (filled < 5) {\n runs[filled] = length;\n filled++;\n }\n\n if (filled === 5) {\n consider(x);\n shift();\n runs[filled] = 0;\n }\n }\n\n current = bit;\n length = 1;\n }\n }\n\n return found.map(({ center, moduleSize }) => ({\n center: refineCenter(matrix, center, moduleSize),\n moduleSize\n }));\n};\n\n/**\n * Find finder patterns as nested SHAPES rather than as run-length ratios.\n *\n * The 1:1:3:1:1 scan needs several clean pixels per band. In a 12-megapixel\n * photograph where the symbol occupies a small part of the frame, a module is\n * two or three pixels wide and JPEG artefacts destroy the ratio — measured on\n * the corpus, the `close` category is exactly this case, and the run-length\n * scan finds three patterns in only half of them.\n *\n * A finder is also a shape: a dark square ring, a light ring inside it, and a\n * dark core. That structure survives at scales where the ratio does not,\n * because it depends on connectivity rather than on measuring band widths.\n * BoofCV takes this approach — it detects the pattern the way AR-marker\n * trackers do rather than the way the QR specification describes — and scores\n * 100% on this corpus category where run-length scanning manages 28.6%.\n *\n * Complementary rather than better: on `perspective` images this finds three\n * patterns in one image of eight where the run-length scan finds all eight,\n * because a foreshortened finder stops being square. Both are run, and their\n * candidates pooled.\n */\nexport const findFinderBlobs = (matrix: BitMatrix): FinderPattern[] => {\n const { width, height, bits } = matrix;\n const seen = new Uint8Array(width * height);\n const found: FinderPattern[] = [];\n\n const at = (x: number, y: number): number =>\n x < 0 || y < 0 || x >= width || y >= height ? 0 : bits[y * width + x];\n\n // A blob larger than this is not a finder pattern but a dark region of the\n // scene, and flooding it wastes the whole budget.\n const maxArea = Math.max(4096, Math.floor((width * height) / 16));\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const start = y * width + x;\n if (seen[start] === 1 || bits[start] !== 1) continue;\n\n let area = 0;\n let minX = x;\n let maxX = x;\n let minY = y;\n let maxY = y;\n const stack = [start];\n seen[start] = 1;\n\n // Unrolled, with the neighbour offsets written out.\n //\n // Profiled under viewfinder load — a symbol present, a budget enforced,\n // frame after frame — this is the hottest function in the decoder at 22%\n // of JS time, where it does not reach the top three for a still or an\n // empty frame. The inner loop ran a division and a modulo per popped\n // pixel to recover coordinates from an index, and allocated a\n // four-element array of pairs to iterate the neighbours; on a blob of\n // tens of thousands of pixels that is the whole cost.\n while (stack.length > 0) {\n const index = stack.pop()!;\n const cy = (index / width) | 0;\n const cx = index - cy * width;\n area++;\n\n if (cx < minX) minX = cx;\n if (cx > maxX) maxX = cx;\n if (cy < minY) minY = cy;\n if (cy > maxY) maxY = cy;\n if (area > maxArea) break;\n\n if (cx + 1 < width) {\n const next = index + 1;\n if (seen[next] === 0 && bits[next] === 1) {\n seen[next] = 1;\n stack.push(next);\n }\n }\n if (cx > 0) {\n const next = index - 1;\n if (seen[next] === 0 && bits[next] === 1) {\n seen[next] = 1;\n stack.push(next);\n }\n }\n if (cy + 1 < height) {\n const next = index + width;\n if (seen[next] === 0 && bits[next] === 1) {\n seen[next] = 1;\n stack.push(next);\n }\n }\n if (cy > 0) {\n const next = index - width;\n if (seen[next] === 0 && bits[next] === 1) {\n seen[next] = 1;\n stack.push(next);\n }\n }\n }\n\n const blobWidth = maxX - minX + 1;\n const blobHeight = maxY - minY + 1;\n if (area < 20 || blobWidth < 7 || blobHeight < 7 || area > maxArea) {\n continue;\n }\n\n // Roughly square. Loose, because perspective makes a real finder\n // rectangular — but not so loose that any dark streak qualifies.\n if (\n Math.max(blobWidth, blobHeight) / Math.min(blobWidth, blobHeight) >\n 1.5\n ) {\n continue;\n }\n\n // The outer ring is a RING: its blob should not fill its bounding box,\n // because the light separator breaks it away from the core.\n if (area / (blobWidth * blobHeight) > 0.75) continue;\n\n const centerX = Math.round(minX + blobWidth / 2);\n const centerY = Math.round(minY + blobHeight / 2);\n const moduleSize = blobWidth / 7;\n\n // The nesting itself: dark core, light at 1.5 modules out in every\n // direction. This is what separates a finder from any other square.\n if (at(centerX, centerY) !== 1) continue;\n const gap = Math.round(moduleSize * 1.5);\n if (\n at(centerX + gap, centerY) !== 0 ||\n at(centerX - gap, centerY) !== 0 ||\n at(centerX, centerY + gap) !== 0 ||\n at(centerX, centerY - gap) !== 0\n ) {\n continue;\n }\n\n found.push({ center: { x: centerX, y: centerY }, moduleSize });\n }\n }\n\n return found;\n};\n\n/**\n * Score how much clear space surrounds a candidate.\n *\n * A real finder sits at a CORNER of the symbol, so two of its four outward\n * directions lead into the quiet zone — four modules of light the standard\n * requires — while the other two lead into data. A false positive thrown up\n * by the data region has data on all four sides.\n *\n * This matters most exactly where it is hardest to do without: a version 40\n * symbol carries 3706 codewords of dense pattern, which produce the\n * 1:1:3:1:1 signature by chance 7 to 13 times per image. Measured against\n * known-correct finder positions, every real finder scores 1.00 while false\n * positives score 0.50 to 0.80.\n *\n * The idea is from the QR detection patent literature, which notes that the\n * mandatory four-module quiet zone \"can be exploited to enlarge potential 3/3\n * code regions for internal false-positive check purposes\".\n */\nconst clearanceScore = (\n matrix: BitMatrix,\n center: Point,\n moduleSize: number\n): number => {\n const at = (x: number, y: number): number =>\n x < 0 || y < 0 || x >= matrix.width || y >= matrix.height\n ? 0\n : matrix.bits[y * matrix.width + x];\n\n const directions = [\n [1, 0],\n [-1, 0],\n [0, 1],\n [0, -1]\n ] as const;\n\n const lightness: number[] = [];\n for (const [dx, dy] of directions) {\n let light = 0;\n let total = 0;\n // Sampled from 5 to 9 modules out: past the finder's own 7-module width,\n // into either the quiet zone or the first data modules.\n for (let distance = 5; distance <= 9; distance++) {\n const x = Math.round(center.x + dx * moduleSize * distance);\n const y = Math.round(center.y + dy * moduleSize * distance);\n if (at(x, y) === 0) light++;\n total++;\n }\n lightness.push(total === 0 ? 0 : light / total);\n }\n\n // The two clearest directions. A corner finder has two facing outward, so\n // requiring all four would reject every real finder.\n lightness.sort((a, b) => b - a);\n return ((lightness[0] ?? 0) + (lightness[1] ?? 0)) / 2;\n};\n\n/**\n * Drop candidates that have no clear space around them.\n *\n * Returns the original list when filtering would leave fewer than three, so a\n * symbol photographed without its full quiet zone — against a dark table\n * edge, say — is never made undecodable by this check.\n */\nexport const withClearance = (\n matrix: BitMatrix,\n patterns: readonly FinderPattern[]\n): FinderPattern[] => {\n const clear = patterns.filter(\n (pattern) =>\n clearanceScore(matrix, pattern.center, pattern.moduleSize) >= 0.95\n );\n return clear.length >= 3 ? clear : [...patterns];\n};\n\n/**\n * Choose the three candidates most likely to be one symbol's finders.\n *\n * Taking the first three found is wrong far more often than it looks. Measured\n * across the benchmark corpus, the `rotations`, `high_version` and\n * `brightness` categories return MORE than three candidates on essentially\n * every image — alignment patterns, texture, and print artefacts all produce\n * the 1:1:3:1:1 signature somewhere — so an arbitrary three discards the\n * right answer and the symbol is lost despite having been found.\n *\n * Scored on the two properties three real finders always have: their module\n * sizes agree, and they sit at the corners of a right isosceles triangle. Both\n * hold under rotation and moderate perspective, which is what makes them\n * usable as a selection criterion rather than a validation one.\n */\nexport const selectBestTriple = (\n patterns: readonly FinderPattern[]\n): FinderPattern[] | null => {\n if (patterns.length < 3) return null;\n if (patterns.length === 3) return [...patterns];\n\n // Beyond a handful of candidates the combinations grow cubically, so the\n // search is capped. Candidates are already merged by proximity, so a large\n // count means genuine clutter rather than duplicates of one pattern.\n const pool = patterns.slice(0, 12);\n let best: { score: number; triple: FinderPattern[] } | null = null;\n\n for (let i = 0; i < pool.length - 2; i++) {\n for (let j = i + 1; j < pool.length - 1; j++) {\n for (let k = j + 1; k < pool.length; k++) {\n const triple = [pool[i], pool[j], pool[k]];\n const score = scoreTriple(triple);\n if (score === null) continue;\n if (best === null || score < best.score) best = { score, triple };\n }\n }\n }\n\n return best?.triple ?? null;\n};\n\n/**\n * How unlike three real finders a candidate triple is. Lower is better.\n *\n * Returns `null` for triples that cannot be a symbol at all, which prunes most\n * combinations before the geometry is examined.\n */\nconst scoreTriple = (triple: readonly FinderPattern[]): number | null => {\n const [a, b, c] = triple as [FinderPattern, FinderPattern, FinderPattern];\n\n // Three finders of one symbol are the same size. A candidate that is twice\n // its neighbours is an alignment pattern or unrelated texture.\n const sizes = [a.moduleSize, b.moduleSize, c.moduleSize];\n const meanSize = (sizes[0] + sizes[1] + sizes[2]) / 3;\n if (meanSize <= 0) return null;\n\n const sizeSpread = Math.max(...sizes) / Math.min(...sizes) - 1;\n if (sizeSpread > 1.5) return null;\n\n // The three sit at the corners of a right isosceles triangle: two equal\n // legs and a hypotenuse of sqrt(2) times their length.\n const sides = [\n Math.hypot(a.center.x - b.center.x, a.center.y - b.center.y),\n Math.hypot(b.center.x - c.center.x, b.center.y - c.center.y),\n Math.hypot(a.center.x - c.center.x, a.center.y - c.center.y)\n ].sort((first, second) => first - second);\n\n const [leg1, leg2, hypotenuse] = sides as [number, number, number];\n if (leg1 <= 0) return null;\n\n // Legs far enough apart in length are not a QR at any angle.\n const legRatio = leg2 / leg1;\n if (legRatio > 2.2) return null;\n\n const expectedHypotenuse = ((leg1 + leg2) / 2) * Math.SQRT2;\n const hypotenuseError =\n Math.abs(hypotenuse - expectedHypotenuse) / expectedHypotenuse;\n if (hypotenuseError > 0.5) return null;\n\n // Separation must be plausible for the module size — the legs span\n // (size - 7) modules, so 14 to 170 covers versions 1 to 40 with slack.\n const modulesApart = leg1 / meanSize;\n if (modulesApart < 10 || modulesApart > 200) return null;\n\n return sizeSpread + (legRatio - 1) + hypotenuseError;\n};\n\n/** Squared distance, for comparisons that never need the square root. */\nconst distanceSquared = (a: Point, b: Point): number =>\n (a.x - b.x) ** 2 + (a.y - b.y) ** 2;\n\n/**\n * Assign three finders to their corners.\n *\n * The top-left finder is the one at the right angle of the L the three form —\n * identified as the corner opposite the longest side, which is the hypotenuse.\n * That works at any rotation, which a coordinate comparison would not: a\n * symbol photographed upside down has its \"top\" left finder at the bottom of\n * the image.\n *\n * Top-right and bottom-left are then distinguished by the sign of the cross\n * product, which says which side of the diagonal each falls on.\n */\nexport const orientFinders = (\n patterns: readonly FinderPattern[]\n): FinderTriple | null => {\n if (patterns.length !== 3) return null;\n\n const [a, b, c] = patterns as [FinderPattern, FinderPattern, FinderPattern];\n const sides = [\n { corner: c, length: distanceSquared(a.center, b.center) },\n { corner: a, length: distanceSquared(b.center, c.center) },\n { corner: b, length: distanceSquared(a.center, c.center) }\n ];\n\n // The corner opposite the longest side is the right angle of the L.\n const hypotenuse = sides.reduce((longest, side) =>\n side.length > longest.length ? side : longest\n );\n const topLeft = hypotenuse.corner;\n const others = patterns.filter((pattern) => pattern !== topLeft);\n if (others.length !== 2) return null;\n\n const [first, second] = others as [FinderPattern, FinderPattern];\n\n // Cross product of the two arms. Its sign says whether `first` is clockwise\n // or anticlockwise from `second` about the corner, which is exactly the\n // top-right / bottom-left distinction — and it holds under any rotation.\n const cross =\n (first.center.x - topLeft.center.x) * (second.center.y - topLeft.center.y) -\n (first.center.y - topLeft.center.y) * (second.center.x - topLeft.center.x);\n\n return cross < 0\n ? { topLeft, topRight: second, bottomLeft: first }\n : { topLeft, topRight: first, bottomLeft: second };\n};\n\n/**\n * The four corners of a finder pattern's outer square.\n *\n * A finder gives more than a centre. Its outer ring is a square of known size\n * — 7 modules on a side — so locating its corners yields four measured\n * correspondences instead of one, and three finders yield twelve. That is\n * what turns fitting the sampling grid from an exactly-determined problem\n * with a guessed fourth corner into an overdetermined one where least squares\n * can average out the noise in any single measurement.\n *\n * The gain is large. Measured on the benchmark corpus with a single flat\n * sampling pass and no retry ladder, a twelve-point fit reads `perspective`\n * 18 of 26 against four points' 4, `nominal` 60 of 109 against 38, and\n * `glare` 9 of 31 against 3.\n *\n * The seed matters and is easy to get wrong: flooding from the finder's\n * CENTRE fills only its 3x3 dark core, which stops at the white separator\n * ring and describes a square 2 modules across rather than 7. The outer ring\n * is a separate dark region, so this seeds on the ring itself.\n */\nexport const finderOutline = (\n matrix: BitMatrix,\n finder: FinderPattern\n): Point[] | null => {\n const { width, height } = matrix;\n const cx = Math.round(finder.center.x);\n const cy = Math.round(finder.center.y);\n const module = finder.moduleSize;\n\n // Three modules out lands on the outer ring in every direction; the first\n // dark hit is the ring, whichever way the symbol is rotated.\n let seed: readonly [number, number] | null = null;\n for (const [dx, dy] of [\n [3, 0],\n [-3, 0],\n [0, 3],\n [0, -3],\n [3, 3],\n [-3, -3],\n [3, -3],\n [-3, 3]\n ] as const) {\n const x = Math.round(cx + dx * module);\n const y = Math.round(cy + dy * module);\n if (x < 0 || y < 0 || x >= width || y >= height) continue;\n if (matrix.bits[y * width + x] === 1) {\n seed = [x, y];\n break;\n }\n }\n if (seed === null) return null;\n\n // Bounded flood fill. The bound keeps a finder that touches surrounding\n // dark content from swallowing the whole image.\n const limit = Math.ceil(module * 8);\n const seen = new Uint8Array(width * height);\n const stack: Array<readonly [number, number]> = [seed];\n seen[seed[1] * width + seed[0]] = 1;\n\n const points: Array<readonly [number, number]> = [];\n let visited = 0;\n\n while (stack.length > 0) {\n const current = stack.pop();\n if (current === undefined) break;\n const [x, y] = current;\n\n points.push(current);\n visited++;\n if (visited > limit * limit * 6) break;\n if (Math.abs(x - cx) > limit || Math.abs(y - cy) > limit) continue;\n\n for (const [dx, dy] of [\n [1, 0],\n [-1, 0],\n [0, 1],\n [0, -1]\n ] as const) {\n const nx = x + dx;\n const ny = y + dy;\n if (nx < 0 || ny < 0 || nx >= width || ny >= height) continue;\n if (seen[ny * width + nx] === 1) continue;\n if (matrix.bits[ny * width + nx] !== 1) continue;\n seen[ny * width + nx] = 1;\n stack.push([nx, ny]);\n }\n }\n\n if (points.length < 12) return null;\n return points.map(([x, y]) => ({ x, y }));\n};\n\n/**\n * Pick the four extreme points of an outline along a pair of axes.\n *\n * Ordered by the SYMBOL's axes rather than the image's, because a rotated\n * symbol's top-left corner is not the point nearest the image origin — using\n * image axes silently pairs each corner with the wrong module coordinate and\n * fits a transform to nonsense.\n *\n * Returns them in symbol order: origin, along-u, diagonal, along-v.\n */\nexport const cornersAlongAxes = (\n outline: readonly Point[],\n u: Point,\n v: Point\n): [Point, Point, Point, Point] => {\n const extreme = (score: (point: Point) => number): Point => {\n let best = outline[0];\n let bestScore = -Infinity;\n for (const point of outline) {\n const value = score(point);\n if (value > bestScore) {\n bestScore = value;\n best = point;\n }\n }\n return best;\n };\n\n const alongU = (p: Point): number => p.x * u.x + p.y * u.y;\n const alongV = (p: Point): number => p.x * v.x + p.y * v.y;\n\n return [\n extreme((p) => -alongU(p) - alongV(p)),\n extreme((p) => alongU(p) - alongV(p)),\n extreme((p) => alongU(p) + alongV(p)),\n extreme((p) => -alongU(p) + alongV(p))\n ];\n};\n","/**\n * Turning a located symbol into a clean module grid.\n *\n * A QR photographed off a table or a screen is never a square: it is a\n * quadrilateral, because the camera was not perpendicular to it. Sampling that\n * on a regular grid reads the wrong module wherever the distortion accumulates\n * — and it accumulates most at the far corner, which is where the data is\n * densest.\n *\n * So the four corners are mapped to a unit square with a projective transform,\n * and the grid is sampled through it. That is the difference between reading a\n * code held at a comfortable angle and only reading codes held flat.\n */\n\nimport type { BitMatrix, GrayImage, Point } from \"../types.js\";\nimport {\n cornersAlongAxes,\n finderOutline,\n type FinderTriple\n} from \"./locate.js\";\n\n/**\n * A projective (homography) transform between two quadrilaterals.\n *\n * Affine is not enough. An affine transform preserves parallel lines, and\n * perspective does not — the far edge of a tilted square is genuinely shorter\n * than the near one. Only a projective transform models that, which is why\n * this carries the two extra terms an affine matrix lacks.\n */\nexport interface Transform {\n readonly a11: number;\n readonly a12: number;\n readonly a13: number;\n readonly a21: number;\n readonly a22: number;\n readonly a23: number;\n readonly a31: number;\n readonly a32: number;\n readonly a33: number;\n}\n\n/** Map a point through a transform, dividing out the homogeneous coordinate. */\n/**\n * Where the sensor stops recording and starts clipping.\n *\n * Not 255 and 0 exactly: JPEG compression and the greyscale conversion move\n * clipped pixels by a few counts either way, so a strict test would miss most\n * of a blown-out region. 250 and 5 catch the shoulder without reaching into\n * ordinary highlights and shadows, which routinely sit in the 230s.\n */\nconst SATURATED_HIGH = 250;\nconst SATURATED_LOW = 5;\n\nexport const applyTransform = (\n transform: Transform,\n x: number,\n y: number\n): Point => {\n const denominator = transform.a13 * x + transform.a23 * y + transform.a33;\n\n // A zero denominator means the point maps to infinity — a degenerate\n // transform, which happens when the four source points are collinear.\n if (denominator === 0) return { x: 0, y: 0 };\n\n return {\n x: (transform.a11 * x + transform.a21 * y + transform.a31) / denominator,\n y: (transform.a12 * x + transform.a22 * y + transform.a32) / denominator\n };\n};\n\n/**\n * Build the transform taking the unit square to an arbitrary quadrilateral.\n *\n * The standard construction: solve for how much the quadrilateral deviates\n * from a parallelogram, which is exactly what the two projective terms encode.\n */\nconst squareToQuadrilateral = (\n p0: Point,\n p1: Point,\n p2: Point,\n p3: Point\n): Transform => {\n const dx3 = p0.x - p1.x + p2.x - p3.x;\n const dy3 = p0.y - p1.y + p2.y - p3.y;\n\n // No deviation means the shape is a parallelogram, so the transform is\n // affine and the projective terms vanish.\n if (dx3 === 0 && dy3 === 0) {\n return {\n a11: p1.x - p0.x,\n a12: p1.y - p0.y,\n a13: 0,\n a21: p2.x - p1.x,\n a22: p2.y - p1.y,\n a23: 0,\n a31: p0.x,\n a32: p0.y,\n a33: 1\n };\n }\n\n const dx1 = p1.x - p2.x;\n const dx2 = p3.x - p2.x;\n const dy1 = p1.y - p2.y;\n const dy2 = p3.y - p2.y;\n const denominator = dx1 * dy2 - dx2 * dy1;\n\n if (denominator === 0) {\n // Degenerate quadrilateral — the points are collinear. Identity keeps the\n // caller from producing NaNs; the sample will simply fail to decode.\n return {\n a11: 1,\n a12: 0,\n a13: 0,\n a21: 0,\n a22: 1,\n a23: 0,\n a31: 0,\n a32: 0,\n a33: 1\n };\n }\n\n const a13 = (dx3 * dy2 - dx2 * dy3) / denominator;\n const a23 = (dx1 * dy3 - dx3 * dy1) / denominator;\n\n return {\n a11: p1.x - p0.x + a13 * p1.x,\n a12: p1.y - p0.y + a13 * p1.y,\n a13,\n a21: p3.x - p0.x + a23 * p3.x,\n a22: p3.y - p0.y + a23 * p3.y,\n a23,\n a31: p0.x,\n a32: p0.y,\n a33: 1\n };\n};\n\n/**\n * The transform from module coordinates to image coordinates.\n *\n * Built from three finder centres plus an estimated fourth corner. The three\n * finders are at fixed module positions in every QR — (3.5, 3.5), (size-3.5,\n * 3.5) and (3.5, size-3.5) — so they pin three corners exactly.\n */\nexport const transformForSymbol = (\n finders: FinderTriple,\n size: number,\n bottomRight: Point\n): Transform => {\n const offset = 3.5;\n const far = size - 3.5;\n\n // The unit square here spans FINDER CENTRES, not the symbol's outer edge:\n // its corners are module coordinates (3.5, 3.5) to (size - 3.5, size - 3.5).\n // `sampleGrid` has to map module indices into that range rather than\n // treating (0, 0) as the corner of the symbol — getting this wrong offsets\n // every sample by 3.5 modules and reads a plausible grid of nonsense.\n void offset;\n void far;\n\n return squareToQuadrilateral(\n finders.topLeft.center,\n finders.topRight.center,\n bottomRight,\n finders.bottomLeft.center\n );\n};\n\n/**\n * Fit a transform to more correspondences than it strictly needs.\n *\n * {@link transformForSymbol} solves exactly: four source points, four\n * destination points, one answer. That is fine when all four are measured,\n * and this symbol only ever has three — the fourth corner has no finder and\n * is estimated, so a guess is baked into every sample the grid takes.\n *\n * Measuring each finder's outer square instead gives four points per finder\n * and twelve in total, which over-determines an eight-parameter homography.\n * Least squares then averages the noise across all twelve rather than\n * propagating one bad estimate through everything, and no corner has to be\n * invented.\n *\n * Solved by the Direct Linear Transform: each correspondence contributes two\n * rows, and the resulting system is reduced through its normal equations.\n * Eight unknowns makes that an 8x8 solve, which is small enough that the\n * numerical cost of normal equations does not matter and their simplicity\n * does.\n *\n * Returns `null` when the system is singular — collinear points, or a\n * degenerate outline.\n */\nexport const fitTransform = (\n correspondences: ReadonlyArray<{\n /** Position in the unit square that spans finder centres. */\n readonly source: Point;\n /** Where that lands in the image. */\n readonly target: Point;\n }>\n): Transform | null => {\n if (correspondences.length < 4) return null;\n\n // Normal equations: an 8x8 system with a right-hand column.\n const normal = Array.from({ length: 8 }, () => new Float64Array(9));\n\n const accumulate = (row: readonly number[]): void => {\n for (let i = 0; i < 8; i++) {\n for (let j = 0; j < 8; j++) normal[i][j] += row[i] * row[j];\n normal[i][8] += row[i] * row[8];\n }\n };\n\n for (const { source, target } of correspondences) {\n accumulate([\n source.x,\n source.y,\n 1,\n 0,\n 0,\n 0,\n -source.x * target.x,\n -source.y * target.x,\n target.x\n ]);\n accumulate([\n 0,\n 0,\n 0,\n source.x,\n source.y,\n 1,\n -source.x * target.y,\n -source.y * target.y,\n target.y\n ]);\n }\n\n // Gauss-Jordan with partial pivoting.\n for (let column = 0; column < 8; column++) {\n let pivot = column;\n for (let row = column + 1; row < 8; row++) {\n if (Math.abs(normal[row][column]) > Math.abs(normal[pivot][column])) {\n pivot = row;\n }\n }\n if (Math.abs(normal[pivot][column]) < 1e-12) return null;\n\n const swap = normal[column];\n normal[column] = normal[pivot];\n normal[pivot] = swap;\n\n for (let row = 0; row < 8; row++) {\n if (row === column) continue;\n const factor = normal[row][column] / normal[column][column];\n for (let j = column; j < 9; j++) {\n normal[row][j] -= factor * normal[column][j];\n }\n }\n }\n\n const h = Array.from({ length: 8 }, (_, i) => normal[i][8] / normal[i][i]);\n if (h.some((value) => !Number.isFinite(value))) return null;\n\n // Transposed relative to the textbook layout, matching `applyTransform`:\n // x' = (a11*x + a21*y + a31) / (a13*x + a23*y + a33).\n return {\n a11: h[0],\n a21: h[1],\n a31: h[2],\n a12: h[3],\n a22: h[4],\n a32: h[5],\n a13: h[6],\n a23: h[7],\n a33: 1\n };\n};\n\n/**\n * Build a transform from the finders' measured outer squares.\n *\n * Each finder's outer ring is 7 modules on a side at a known symbol position,\n * so its four corners are four correspondences. Three finders give twelve,\n * which {@link fitTransform} solves in the least-squares sense — no estimated\n * fourth corner enters the fit at all.\n *\n * Returns `null` if any finder's outline cannot be traced, so the caller can\n * fall back to the three-centre transform.\n */\nexport const transformFromOutlines = (\n matrix: BitMatrix,\n finders: FinderTriple,\n size: number\n): Transform | null => {\n const span = size - 7;\n\n // Symbol axes, for ordering each outline's corners. Image axes would pair\n // corners with the wrong module coordinates on a rotated symbol.\n const across = {\n x: finders.topRight.center.x - finders.topLeft.center.x,\n y: finders.topRight.center.y - finders.topLeft.center.y\n };\n const down = {\n x: finders.bottomLeft.center.x - finders.topLeft.center.x,\n y: finders.bottomLeft.center.y - finders.topLeft.center.y\n };\n\n const acrossLength = Math.hypot(across.x, across.y);\n const downLength = Math.hypot(down.x, down.y);\n if (acrossLength === 0 || downLength === 0) return null;\n\n const u = { x: across.x / acrossLength, y: across.y / acrossLength };\n const v = { x: down.x / downLength, y: down.y / downLength };\n\n const correspondences: Array<{ source: Point; target: Point }> = [];\n\n // Module coordinate of each finder's top-left corner.\n const placements = [\n { finder: finders.topLeft, x: 0, y: 0 },\n { finder: finders.topRight, x: size - 7, y: 0 },\n { finder: finders.bottomLeft, x: 0, y: size - 7 }\n ];\n\n for (const { finder, x, y } of placements) {\n const outline = finderOutline(matrix, finder);\n if (outline === null) return null;\n\n const corners = cornersAlongAxes(outline, u, v);\n const modules = [\n { x, y },\n { x: x + 7, y },\n { x: x + 7, y: y + 7 },\n { x, y: y + 7 }\n ];\n\n for (const [index, module] of modules.entries()) {\n correspondences.push({\n // Rebased onto the same unit square `sampleGrid` samples in, whose\n // corners are module (3.5, 3.5) and (size - 3.5, size - 3.5).\n source: {\n x: (module.x - 3.5) / span,\n y: (module.y - 3.5) / span\n },\n target: corners[index]\n });\n }\n }\n\n return fitTransform(correspondences);\n};\n\n/**\n * Measure the symbol's size by counting timing-pattern transitions.\n *\n * {@link estimateSize} divides the finder span by the module size, which\n * multiplies any error in the module size by the module count. Under strong\n * foreshortening the finder's own run lengths are inflated — the near arm\n * measures wider than the far one — so the quotient lands on the wrong\n * multiple of four, or outside the legal range entirely. Measured on the\n * corpus, `estimateSize` returns null on 7 of the 22 remaining `perspective`\n * failures.\n *\n * The timing pattern answers the question directly. It alternates once per\n * module across the whole symbol, so COUNTING its transitions gives the module\n * count with no division and no dependence on any measured width — a\n * compressed timing pattern still alternates exactly as many times.\n *\n * The scan line has to be found rather than assumed: its offset from the\n * finder centres is itself measured in module widths, which is the quantity in\n * doubt. So several offsets are swept and the one whose runs are most uniform\n * wins — the timing pattern is the one line in a symbol whose runs are all a\n * single module long, which no row of data matches.\n *\n * Worth noting for anyone re-deriving this: measured BEFORE the twelve-point\n * outline fit existed, this technique converted nothing, because every image\n * it fixed then failed later anyway. It is worth 8 images now. A fix aimed at\n * a constraint that is not yet binding measures as worthless even when it is\n * correct.\n */\nexport const sizeFromTimingPattern = (\n matrix: BitMatrix,\n finders: FinderTriple\n): number | null => {\n const { topLeft, topRight, bottomLeft } = finders;\n\n const down = {\n x: bottomLeft.center.x - topLeft.center.x,\n y: bottomLeft.center.y - topLeft.center.y\n };\n const downLength = Math.hypot(down.x, down.y);\n if (downLength === 0) return null;\n\n const unitX = down.x / downLength;\n const unitY = down.y / downLength;\n const module = (topLeft.moduleSize + topRight.moduleSize) / 2;\n if (module <= 0) return null;\n\n let best: { runs: number; deviation: number } | null = null;\n\n // The timing row sits 2.5 modules below the finder centres in principle.\n // Swept rather than assumed, because that offset is measured in the very\n // module width this function exists to avoid trusting.\n for (let offset = 1.2; offset <= 4; offset += 0.15) {\n const shiftX = unitX * module * offset;\n const shiftY = unitY * module * offset;\n\n const runs = runLengthsAlong(\n matrix,\n topLeft.center.x + shiftX,\n topLeft.center.y + shiftY,\n topRight.center.x + shiftX,\n topRight.center.y + shiftY\n );\n if (runs === null || runs.length < 12) continue;\n\n // Ignore the ends, which straddle the finders rather than the timing row.\n const interior = runs.slice(2, -2);\n if (interior.length < 8) continue;\n\n const mean =\n interior.reduce((total, run) => total + run, 0) / interior.length;\n if (mean <= 0) continue;\n\n const variance =\n interior.reduce((total, run) => total + (run - mean) ** 2, 0) /\n interior.length;\n const deviation = Math.sqrt(variance) / mean;\n\n if (best === null || deviation < best.deviation) {\n best = { runs: runs.length, deviation };\n }\n }\n\n if (best === null) return null;\n\n // The scan spans finder centre to finder centre: the run count covers the\n // modules between them, and the finders themselves add the rest.\n const estimate = best.runs + 11;\n const snapped = Math.round((estimate - 17) / 4) * 4 + 17;\n return snapped >= 21 && snapped <= 177 ? snapped : null;\n};\n\n/** Lengths of the constant-colour runs along a line, or null if it leaves the image. */\nconst runLengthsAlong = (\n matrix: BitMatrix,\n fromX: number,\n fromY: number,\n toX: number,\n toY: number\n): number[] | null => {\n const steps = Math.round(Math.hypot(toX - fromX, toY - fromY));\n if (steps < 10) return null;\n\n const runs: number[] = [];\n let previous: number | null = null;\n let length = 0;\n\n for (let i = 0; i <= steps; i++) {\n const x = Math.round(fromX + ((toX - fromX) * i) / steps);\n const y = Math.round(fromY + ((toY - fromY) * i) / steps);\n if (x < 0 || y < 0 || x >= matrix.width || y >= matrix.height) return null;\n\n const value = matrix.bits[y * matrix.width + x];\n if (previous === null) {\n previous = value;\n length = 1;\n continue;\n }\n\n if (value === previous) {\n length++;\n } else {\n runs.push(length);\n previous = value;\n length = 1;\n }\n }\n\n runs.push(length);\n return runs;\n};\n\n/**\n * Estimate the fourth corner, which has no finder pattern.\n *\n * Larger symbols carry an alignment pattern near it, and using that is more\n * accurate. Without one, the corner is where the two arms of the L would meet\n * if the symbol were a parallelogram — good enough for small symbols, where\n * accumulated perspective error stays under half a module.\n */\nexport const estimateBottomRight = (finders: FinderTriple): Point => ({\n x:\n finders.topRight.center.x +\n finders.bottomLeft.center.x -\n finders.topLeft.center.x,\n y:\n finders.topRight.center.y +\n finders.bottomLeft.center.y -\n finders.topLeft.center.y\n});\n\n/**\n * Estimate the symbol's size in modules.\n *\n * Derived from the distance between finder centres divided by the module size,\n * then snapped to the nearest legal dimension. Snapping is essential: sizes\n * are always 4n+17, and an off-by-one estimate misaligns every sampled module.\n */\nexport const estimateSize = (finders: FinderTriple): number | null => {\n // Derived from each arm of the finder triangle separately, then the smaller\n // estimate taken.\n //\n // A QR is square, so both arms span the same number of modules — but under\n // perspective they do not span the same number of PIXELS, and the finders on\n // the far arm are foreshortened, which shrinks their measured module size.\n // Since size is distance divided by module size, that inflates the estimate,\n // and only ever upward.\n //\n // Measured on a corpus sequence shot at progressively steeper angles, the\n // averaged estimate climbed 25, 29, 33, 37, 41, 45, 49 against a true 25,\n // while the less-foreshortened arm read 25 throughout. Taking the minimum is\n // right nine times in twelve where averaging was right four.\n const alongTop = Math.hypot(\n finders.topRight.center.x - finders.topLeft.center.x,\n finders.topRight.center.y - finders.topLeft.center.y\n );\n const alongLeft = Math.hypot(\n finders.bottomLeft.center.x - finders.topLeft.center.x,\n finders.bottomLeft.center.y - finders.topLeft.center.y\n );\n\n // Rotation widens run-length measurements: a horizontal scan crosses a\n // rotated finder diagonally, so its runs read 1/cos(angle) too long — 1.41x\n // at 45 degrees. The finders supply the angle, since the top arm's tilt off\n // axis IS the rotation the scan suffered.\n const angle = Math.atan2(\n finders.topRight.center.y - finders.topLeft.center.y,\n finders.topRight.center.x - finders.topLeft.center.x\n );\n const folded = Math.abs(\n ((angle % (Math.PI / 2)) + Math.PI / 2) % (Math.PI / 2)\n );\n const widening =\n 1 / Math.max(Math.cos(folded), Math.cos(Math.PI / 2 - folded));\n\n const moduleAlongTop =\n (finders.topLeft.moduleSize + finders.topRight.moduleSize) / 2 / widening;\n const moduleAlongLeft =\n (finders.topLeft.moduleSize + finders.bottomLeft.moduleSize) / 2 / widening;\n if (moduleAlongTop <= 0 || moduleAlongLeft <= 0) return null;\n\n // The finder centres sit 3.5 modules inside each edge, so an arm spans\n // (size - 7) modules.\n const estimate = Math.min(\n alongTop / moduleAlongTop + 7,\n alongLeft / moduleAlongLeft + 7\n );\n const snapped = Math.round((estimate - 17) / 4) * 4 + 17;\n\n return snapped >= 21 && snapped <= 177 ? snapped : null;\n};\n\n/**\n * Resample the image so the symbol is square and its modules uniform.\n *\n * A projective transform already corrects perspective during sampling, so\n * this is not about geometry — it is about what the BINARIZER sees. In an\n * oblique photograph a module at the far edge is a fraction of the size it is\n * near the camera, and one block size cannot suit both. Measured on the\n * `perspective` category, images that fail have a mean leg ratio of 1.58 and\n * modules down to 2.4 pixels at the far edge, against 1.14 and 7.5 for those\n * that decode.\n *\n * Rectifying first makes every module the same size, so binarization,\n * finder detection and everything downstream run on an image whose scale is\n * uniform. This is the automatic form of Lightroom's Guided Upright: that\n * tool needs a person to draw the guides because nothing in a photograph\n * says what was straight, while a QR tells us — its three finder centres sit\n * at module coordinates the specification fixes.\n *\n * Sampled bilinearly rather than nearest-neighbour, because the point is to\n * recover the far edge: replicating nearest pixels would upsample without\n * adding anything.\n */\nexport const rectifySymbol = (\n image: GrayImage,\n finders: FinderTriple,\n size: number,\n pixelsPerModule = 8\n): GrayImage => {\n const topLeft = finders.topLeft.center;\n const topRight = finders.topRight.center;\n const bottomLeft = finders.bottomLeft.center;\n\n // The fourth corner only frames the output here; any error in it is\n // corrected by re-detecting on the rectified image.\n const bottomRight = {\n x: topRight.x + bottomLeft.x - topLeft.x,\n y: topRight.y + bottomLeft.y - topLeft.y\n };\n\n const span = size - 7;\n // Half a finder plus a four-module quiet zone, so the output contains the\n // whole symbol with the margin detection expects.\n const padding = 7.5;\n const width = Math.round((span + padding * 2) * pixelsPerModule);\n const data = new Uint8ClampedArray(width * width).fill(255);\n\n for (let y = 0; y < width; y++) {\n for (let x = 0; x < width; x++) {\n const u = (x / pixelsPerModule - padding) / span;\n const v = (y / pixelsPerModule - padding) / span;\n\n const sx =\n (1 - u) * (1 - v) * topLeft.x +\n u * (1 - v) * topRight.x +\n u * v * bottomRight.x +\n (1 - u) * v * bottomLeft.x;\n const sy =\n (1 - u) * (1 - v) * topLeft.y +\n u * (1 - v) * topRight.y +\n u * v * bottomRight.y +\n (1 - u) * v * bottomLeft.y;\n\n const x0 = Math.floor(sx);\n const y0 = Math.floor(sy);\n if (x0 < 0 || y0 < 0 || x0 + 1 >= image.width || y0 + 1 >= image.height) {\n continue;\n }\n\n const fx = sx - x0;\n const fy = sy - y0;\n const at = (px: number, py: number): number =>\n image.data[py * image.width + px];\n\n data[y * width + x] =\n (1 - fx) * (1 - fy) * at(x0, y0) +\n fx * (1 - fy) * at(x0 + 1, y0) +\n (1 - fx) * fy * at(x0, y0 + 1) +\n fx * fy * at(x0 + 1, y0 + 1);\n }\n }\n\n return { data, width, height: width };\n};\n\n/**\n * Score how well a transform explains the symbol it claims to describe.\n *\n * A QR contains structures whose positions are fixed by the standard: three\n * finder patterns, two timing lines, and a grid of alignment patterns. If a\n * transform is right, sampling those positions finds those structures. If it\n * is slightly wrong, they blur or vanish — and the score falls off smoothly,\n * which is what makes it usable as a search signal rather than a pass/fail\n * check.\n *\n * Crucially this needs NO ground truth. It asks only whether the symbol is\n * self-consistent under the proposed geometry, so it can drive a search on a\n * live camera frame.\n *\n * Adapted from quirc's `fitness_all`, which is the same idea implemented in\n * about 2700 lines of C for embedded use.\n */\nexport const scoreTransform = (\n image: BitMatrix,\n transform: Transform,\n size: number,\n alignmentCenters: readonly number[]\n): number => {\n const span = size - 7;\n\n /**\n * Sample one module at nine points across its interior.\n *\n * A single centre sample is a coin flip when the transform is half a module\n * out. Nine samples at 0.3/0.5/0.7 of the module's width turn that into a\n * gradient: a slightly-wrong transform scores lower rather than randomly,\n * and that gradient is what a search can follow.\n */\n // Hoisted out of the loop: these are read nine times per call and this\n // function is the hottest in the decoder — 46% of all CPU time, measured\n // with deoptkit.\n const { bits, width, height } = image;\n const { a11, a12, a13, a21, a22, a23, a31, a32, a33 } = transform;\n\n /**\n * One sample at a fractional module offset, inlined.\n *\n * Takes normalised coordinates rather than module ones, so the caller can\n * hoist the `(m - 3.5) / span` conversion: `cell` samples three distinct x\n * offsets against three y offsets, so computing them per sample does nine\n * divisions where six suffice.\n */\n const sampleAt = (u: number, v: number): number => {\n const w = a13 * u + a23 * v + a33;\n if (w === 0) return 0;\n\n // `| 0` after adding 0.5 rather than Math.round: rounding was one of two\n // eager deopts here (\"minus zero\"), and the coordinates are always\n // positive inside the guard below.\n const px = ((a11 * u + a21 * v + a31) / w + 0.5) | 0;\n const py = ((a12 * u + a22 * v + a32) / w + 0.5) | 0;\n\n if (px < 0 || py < 0 || px >= width || py >= height) return 0;\n return bits[py * width + px] === 1 ? 1 : -1;\n };\n\n const cell = (x: number, y: number): number => {\n // Unrolled, with the coordinate conversion hoisted. The array-literal\n // form allocated two arrays and ran two iterator protocols per call —\n // `Symbol.iterator`, `next`, `done`, `value` — and this runs hundreds of\n // times per scored transform, with 1875 transforms scored per image.\n //\n // Nine samples rather than five: five measured identical accuracy on the\n // corpus for 8% less time, which is not worth deviating from the sampling\n // quirc proved. The 8% is itself informative — cutting the sampler's work\n // by 44% barely moved total time, so the constraint is how many attempts\n // the ladder makes, not what each sample costs.\n const x3 = (x + 0.3 - 3.5) / span;\n const x5 = (x + 0.5 - 3.5) / span;\n const x7 = (x + 0.7 - 3.5) / span;\n const y3 = (y + 0.3 - 3.5) / span;\n const y5 = (y + 0.5 - 3.5) / span;\n const y7 = (y + 0.7 - 3.5) / span;\n\n return (\n sampleAt(x3, y3) +\n sampleAt(x5, y3) +\n sampleAt(x7, y3) +\n sampleAt(x3, y5) +\n sampleAt(x5, y5) +\n sampleAt(x7, y5) +\n sampleAt(x3, y7) +\n sampleAt(x5, y7) +\n sampleAt(x7, y7)\n );\n };\n\n /** The square ring `radius` modules out from a centre. */\n const ring = (cx: number, cy: number, radius: number): number => {\n let score = 0;\n for (let i = 0; i < radius * 2; i++) {\n score += cell(cx - radius + i, cy - radius);\n score += cell(cx - radius, cy + radius - i);\n score += cell(cx + radius, cy - radius + i);\n score += cell(cx + radius - i, cy + radius);\n }\n return score;\n };\n\n // A finder is dark centre, dark ring, LIGHT ring, dark ring — so the middle\n // ring is subtracted. Signs encode the structure being looked for.\n const finder = (x: number, y: number): number =>\n cell(x + 3, y + 3) +\n ring(x + 3, y + 3, 1) -\n ring(x + 3, y + 3, 2) +\n ring(x + 3, y + 3, 3);\n\n // An alignment pattern is dark centre, light ring, dark ring.\n const alignment = (cx: number, cy: number): number =>\n cell(cx, cy) - ring(cx, cy, 1) + ring(cx, cy, 2);\n\n let score = 0;\n\n // Timing patterns alternate, so the expected value flips each module.\n for (let i = 0; i < size - 14; i++) {\n const expected = (i & 1) === 1 ? 1 : -1;\n score += cell(i + 7, 6) * expected;\n score += cell(6, i + 7) * expected;\n }\n\n score += finder(0, 0);\n score += finder(size - 7, 0);\n score += finder(0, size - 7);\n\n // Alignment patterns, skipping the row and column that overlap finders.\n for (let i = 1; i + 1 < alignmentCenters.length; i++) {\n score += alignment(6, alignmentCenters[i]);\n score += alignment(alignmentCenters[i], 6);\n }\n for (let i = 1; i < alignmentCenters.length; i++) {\n for (let j = 1; j < alignmentCenters.length; j++) {\n score += alignment(alignmentCenters[i], alignmentCenters[j]);\n }\n }\n\n return score;\n};\n\n/**\n * Nudge a transform toward a better fit, keeping only improvements.\n *\n * Coordinate descent over the transform's eight free parameters, halving the\n * step each pass. Cheap, derivative-free, and it cannot make things worse\n * because a step is reverted unless it scores higher.\n *\n * This is what closes the loop that measurement kept pointing at: on the\n * corpus, symbols repeatedly located correctly to within a module still\n * failed to decode, and no single corner estimate fixed them. Rather than\n * compute a better corner, this searches for one — the score says which\n * direction is better without knowing the answer.\n *\n * From quirc's `jiggle_perspective`.\n */\nexport const refineTransform = (\n image: BitMatrix,\n transform: Transform,\n size: number,\n alignmentCenters: readonly number[]\n): Transform => {\n const keys = [\n `a11`,\n `a12`,\n `a13`,\n `a21`,\n `a22`,\n `a23`,\n `a31`,\n `a32`\n ] as const;\n\n // Coefficients in a typed array rather than an object mutated by string\n // key. The object form made every read and write a dictionary-mode named\n // access on the decoder's hottest path — `scoreTransform` accounts for 40%\n // of CPU on a noisy frame — and V8 reported \"insufficient type feedback for\n // generic named access\" against it. Indexed access on a Float64Array is\n // monomorphic and allocates nothing.\n const values = new Float64Array(8);\n for (let i = 0; i < 8; i++) values[i] = transform[keys[i]];\n\n const asTransform = (): Transform => ({\n a11: values[0],\n a12: values[1],\n a13: values[2],\n a21: values[3],\n a22: values[4],\n a23: values[5],\n a31: values[6],\n a32: values[7],\n a33: transform.a33\n });\n\n let best = scoreTransform(image, transform, size, alignmentCenters);\n\n // Two percent of each parameter's own magnitude, so the step suits both the\n // large translation terms and the small projective ones.\n const steps = new Float64Array(8);\n for (let i = 0; i < 8; i++) steps[i] = Math.abs(values[i]) * 0.02;\n\n for (let pass = 0; pass < 5; pass++) {\n for (let index = 0; index < 8; index++) {\n for (const direction of [1, -1]) {\n const previous = values[index];\n values[index] = previous + steps[index] * direction;\n\n const score = scoreTransform(\n image,\n asTransform(),\n size,\n alignmentCenters\n );\n\n if (score > best) {\n best = score;\n } else {\n values[index] = previous;\n }\n }\n }\n\n for (let i = 0; i < 8; i++) steps[i] *= 0.5;\n }\n\n return asTransform();\n};\n\n/**\n * Search for the fourth corner by fitness rather than computing it.\n *\n * Every attempt to derive this corner from geometry has fallen short: the\n * parallelogram assumption ignores perspective, edge-following measured no\n * better, and the alignment pattern is often missing on the symbols that need\n * it most. Meanwhile supplying a known-good corner takes the `perspective`\n * category from 2 of 23 images to 7, so the information IS recoverable — it\n * just is not derivable.\n *\n * So it is searched for. {@link scoreTransform} can rank a candidate without\n * knowing the answer, which turns this into an optimisation rather than a\n * derivation.\n *\n * The step size matters more than the range. The corner error has a median of\n * 1.6 modules on that category, so a coarse grid straddles the answer and\n * never lands on it: a two-module step recovered nothing, and a half-module\n * step recovered all five. That is why this searches finely over a modest\n * range rather than coarsely over a wide one.\n */\nexport const searchCorner = (\n image: BitMatrix,\n finders: FinderTriple,\n size: number,\n moduleSize: number,\n alignmentCenters: readonly number[],\n estimate: Point,\n /**\n * Abandon the search when this returns true.\n *\n * Scoring 625 transforms is the single longest uninterrupted stretch in the\n * decoder, and a budget checked only BETWEEN stages cannot bound it —\n * measured, a 40ms budget produced a 209ms block and a 400ms budget a 603ms\n * one. A budget that does not bound latency is not a budget.\n */\n exhausted?: () => boolean\n): Transform[] => {\n const scored: Array<{ score: number; transform: Transform }> = [];\n\n for (let dy = -6; dy <= 6; dy += 0.5) {\n // Checked per row rather than per candidate: 25 checks instead of 625,\n // bounding the overrun to one row's work — under a millisecond.\n if (exhausted?.() === true) break;\n\n for (let dx = -6; dx <= 6; dx += 0.5) {\n const corner = {\n x: estimate.x + dx * moduleSize,\n y: estimate.y + dy * moduleSize\n };\n const transform = transformForSymbol(finders, size, corner);\n scored.push({\n score: scoreTransform(image, transform, size, alignmentCenters),\n transform\n });\n }\n }\n\n scored.sort((a, b) => b.score - a.score);\n\n // The best few, not the single best. The score is a good ranking and not a\n // perfect one — it prefers the corner that decodes on six images in eight,\n // which is worth several decode attempts but not blind trust.\n return scored.slice(0, 8).map((entry) => entry.transform);\n};\n\n/**\n * Sample using local transforms fitted per region — piecewise sampling.\n *\n * A single homography models a FLAT quadrilateral. A photographed QR is\n * usually on paper, and paper is never flat: it bows, curls, or lies over\n * something. Measured on a version 40 symbol whose four corners were verified\n * exact, the interior alignment patterns sit up to **1.09 modules** away from\n * where the homography predicts them, growing toward the middle and\n * vanishing at the edges. Anything past half a module samples the wrong\n * module, which is why such a symbol can have three perfect finder patterns,\n * a timing pattern scoring 1.00, and still decode to nothing.\n *\n * Alignment patterns are the fix, and not merely as a fourth corner: they are\n * a grid of known reference points spread across the whole symbol. Locating\n * them measures the warp directly, and each cell of that grid gets its own\n * transform fitted to its own four corners — so the model is piecewise\n * planar rather than globally planar, which a bowed page actually is.\n */\nexport const samplePiecewise = (\n image: BitMatrix,\n size: number,\n /** Measured image positions of alignment centres, indexed [row][column]. */\n anchors: ReadonlyArray<ReadonlyArray<Point | null>>,\n /** Module coordinates those anchors correspond to. */\n positions: readonly number[],\n fallback: Transform\n): BitMatrix | null => {\n const bits = new Uint8Array(size * size);\n\n /**\n * Which anchor cell governs a module coordinate.\n *\n * Coordinates outside the anchor span — the border strip before the first\n * alignment pattern and after the last — are CLAMPED to the nearest cell\n * rather than dropped to the global transform. On a version 40 symbol that\n * strip is 13% of all modules, and handing that many to the warped global\n * transform is more error than Reed-Solomon can absorb even when every\n * interior module is right. A bow is locally smooth, so extending the\n * neighbouring cell outward approximates it far better than a plane fitted\n * across the whole symbol.\n */\n const cellFor = (m: number): number => {\n for (let i = 0; i < positions.length - 1; i++) {\n if (m >= positions[i] && m <= positions[i + 1]) return i;\n }\n return m < positions[0] ? 0 : positions.length - 2;\n };\n\n /** The transform governing the cell containing this module coordinate. */\n const localTransform = (mx: number, my: number): Transform => {\n const col = cellFor(mx);\n const row = cellFor(my);\n\n const topLeft = anchors[row]?.[col];\n const topRight = anchors[row]?.[col + 1];\n const bottomLeft = anchors[row + 1]?.[col];\n const bottomRight = anchors[row + 1]?.[col + 1];\n\n // A cell with a missing corner — damaged or glared-out alignment pattern\n // — falls back to the global transform rather than guessing.\n if (!topLeft || !topRight || !bottomLeft || !bottomRight) return fallback;\n\n return squareToQuadrilateral(topLeft, topRight, bottomRight, bottomLeft);\n };\n\n /**\n * The four measured corners of the cell containing a module, if all exist.\n *\n * Used for bilinear interpolation, which is the correct primitive for a\n * NON-PLANAR quadrilateral. A homography maps a square to a planar quad —\n * and the whole reason for sampling piecewise is that the surface is\n * curved, so each cell is slightly non-planar by construction. Texture\n * mapping draws exactly this distinction: bilinear patches handle\n * non-planar quads, perspective mapping handles planar ones.\n */\n const cellCorners = (\n mx: number,\n my: number\n ): { p0: Point; p1: Point; p2: Point; p3: Point } | null => {\n const col = cellFor(mx);\n const row = cellFor(my);\n\n const p0 = anchors[row]?.[col];\n const p1 = anchors[row]?.[col + 1];\n const p2 = anchors[row + 1]?.[col + 1];\n const p3 = anchors[row + 1]?.[col];\n if (!p0 || !p1 || !p2 || !p3) return null;\n\n return { p0, p1, p2, p3 };\n };\n\n for (let y = 0; y < size; y++) {\n for (let x = 0; x < size; x++) {\n const transform = localTransform(x, y);\n let source: Point;\n\n if (transform === fallback) {\n const span = size - 7;\n source = applyTransform(\n transform,\n (x + 0.5 - 3.5) / span,\n (y + 0.5 - 3.5) / span\n );\n } else {\n // Within a cell, coordinates are relative to that cell's own corners.\n // Outside the anchor span the ratio falls below 0 or above 1, which\n // extrapolates the nearest cell's transform rather than clamping the\n // sample — exactly what the border strip needs.\n const col = cellFor(x);\n const row = cellFor(y);\n const x0 = positions[col];\n const x1 = positions[col + 1];\n const y0 = positions[row];\n const y1 = positions[row + 1];\n\n const u = (x + 0.5 - x0) / (x1 - x0);\n const v = (y + 0.5 - y0) / (y1 - y0);\n const corners = cellCorners(x, y);\n\n // Bilinear where all four corners were measured, homography\n // otherwise. Inside the cell the two differ by up to 0.39 modules at\n // the warps measured here — under the half-module threshold on its\n // own, but the errors compound with everything else.\n source =\n corners === null\n ? applyTransform(transform, u, v)\n : {\n x:\n (1 - u) * (1 - v) * corners.p0.x +\n u * (1 - v) * corners.p1.x +\n u * v * corners.p2.x +\n (1 - u) * v * corners.p3.x,\n y:\n (1 - u) * (1 - v) * corners.p0.y +\n u * (1 - v) * corners.p1.y +\n u * v * corners.p2.y +\n (1 - u) * v * corners.p3.y\n };\n }\n\n const sx = Math.round(source.x);\n const sy = Math.round(source.y);\n if (sx < 0 || sy < 0 || sx >= image.width || sy >= image.height) {\n return null;\n }\n\n bits[y * size + x] = image.bits[sy * image.width + sx]!;\n }\n }\n\n return { bits, width: size, height: size };\n};\n\n/**\n * Sample the symbol into a clean module grid.\n *\n * Each module is read at its centre, mapped through the transform. Reading\n * centres rather than averaging whole cells is deliberate: at the distances a\n * phone actually scans from, a module is a handful of pixels, and averaging\n * pulls in its neighbours' ink.\n */\n/**\n * Which modules the image cannot answer for.\n *\n * Returns a mask the same shape as the sampled grid, where 1 marks a module\n * whose value was guessed rather than read. Reed-Solomon corrects twice as\n * many codewords when it is told where the damage is, so this is worth real\n * capacity — measured on a version 3 symbol at ecM, a blob covering 15% of the\n * area decodes 0% of the time as errors and 100% as erasures.\n *\n * Two things make a module unanswerable, and they are different failures:\n *\n * - **Saturation.** A pixel at the top or bottom of the range has been\n * clipped by the sensor, so its true value is not merely uncertain but\n * absent. Measured across the benchmark corpus, `glare` and `bright_spots`\n * average 1.1-1.2% of pixels at or above 250 while `nominal` and `damaged`\n * average 0.00% — so this fires on the categories it is meant for and\n * essentially never on ordinary photographs, which is what makes it safe to\n * run always.\n * - **Falling outside the frame.** `sampleGrid` reads these as light, because\n * a symbol's surroundings are its quiet zone. That is the right guess, but\n * it is still a guess, and saying so costs nothing.\n *\n * Deliberately NOT flagged: low local contrast. It is the obvious third\n * signal and it is not measured here, because a module in a large flat region\n * of a correctly-read symbol also has no local contrast — the check would fire\n * on healthy images, and erasures spent on undamaged modules are capacity\n * taken away from the damage that matters.\n */\nexport const unreadableModules = (\n image: GrayImage,\n transform: Transform,\n size: number\n): Uint8Array => {\n const span = size - 7;\n const mask = new Uint8Array(size * size);\n\n for (let y = 0; y < size; y++) {\n for (let x = 0; x < size; x++) {\n const source = applyTransform(\n transform,\n (x + 0.5 - 3.5) / span,\n (y + 0.5 - 3.5) / span\n );\n\n const sx = Math.round(source.x);\n const sy = Math.round(source.y);\n\n if (sx < 0 || sy < 0 || sx >= image.width || sy >= image.height) {\n mask[y * size + x] = 1;\n continue;\n }\n\n const value = image.data[sy * image.width + sx];\n if (value >= SATURATED_HIGH || value <= SATURATED_LOW) {\n mask[y * size + x] = 1;\n }\n }\n }\n\n return mask;\n};\n\nexport const sampleGrid = (\n image: BitMatrix,\n transform: Transform,\n size: number\n): BitMatrix | null => {\n const bits = new Uint8Array(size * size);\n\n // The transform's unit square spans finder CENTRES — module (3.5, 3.5) to\n // (size - 3.5, size - 3.5) — so a module index has to be mapped into that\n // range. Dividing by `size` instead treats the unit square as the symbol's\n // outer edge, which shifts every sample by 3.5 modules: the finders still\n // land, the grid still fills, and the result decodes to nothing.\n const span = size - 7;\n\n for (let y = 0; y < size; y++) {\n for (let x = 0; x < size; x++) {\n // +0.5 samples the module's centre; -3.5 rebases onto the finder centre.\n const source = applyTransform(\n transform,\n (x + 0.5 - 3.5) / span,\n (y + 0.5 - 3.5) / span\n );\n\n const sx = Math.round(source.x);\n const sy = Math.round(source.y);\n\n // Out of frame reads as LIGHT rather than abandoning the grid.\n //\n // Rejecting the whole symbol on one stray sample is too blunt: under\n // perspective the corner estimate is imprecise, so a grid that is 95%\n // correct gets discarded because a quiet-zone module maps a pixel or\n // two past the edge. Reed-Solomon exists to absorb a handful of wrong\n // modules, and pre-empting it throws away symbols it would have\n // recovered. The perspective literature makes the same point from the\n // other direction, padding detected corners \"to account for minor\n // inaccuracies in corner detection\".\n //\n // Light is the right default because everything outside a symbol is its\n // quiet zone, which the standard requires to be light.\n const outside =\n sx < 0 || sy < 0 || sx >= image.width || sy >= image.height;\n if (outside) {\n bits[y * size + x] = 0;\n continue;\n }\n\n bits[y * size + x] = image.bits[sy * image.width + sx]!;\n }\n }\n\n return { bits, width: size, height: size };\n};\n","/**\n * Locating the alignment pattern, to pin the fourth corner.\n *\n * Three finder patterns fix three corners of a symbol. The fourth is\n * estimated, and for a small QR that estimate is fine: assume the shape is a\n * parallelogram and the error stays under half a module.\n *\n * For a large one it is not fine. A version 25 symbol is 117 modules across,\n * so a perspective error of one percent at the far corner is more than a\n * module of drift by the time the grid reaches it — every module in that\n * region samples its neighbour. Measured on the benchmark corpus, the\n * `high_version` category reaches the decode stage on 17 of 20 images and\n * fails every one: located correctly, sampled wrongly.\n *\n * Which is exactly what alignment patterns exist for. Every version from 2\n * upward carries at least one, and the one nearest the bottom-right corner\n * sits at a known module position — so finding it converts an estimate into a\n * measurement.\n */\n\nimport type { BitMatrix, Point } from \"../types.js\";\nimport type { FinderTriple } from \"./locate.js\";\nimport { applyTransform, type Transform } from \"./sample.js\";\n\n/**\n * Alignment-pattern centre coordinates by version, from ISO/IEC 18004 Annex E.\n *\n * The same table `mask.ts` uses to reserve them. Duplicated deliberately\n * rather than shared: that one describes which modules to SKIP when reading\n * data, this one describes where to LOOK in an image, and merging them would\n * couple the image pipeline to the bitstream layer for the sake of one array.\n */\nconst ALIGNMENT_CENTERS: ReadonlyArray<readonly number[]> = [\n [],\n [],\n [6, 18],\n [6, 22],\n [6, 26],\n [6, 30],\n [6, 34],\n [6, 22, 38],\n [6, 24, 42],\n [6, 26, 46],\n [6, 28, 50],\n [6, 30, 54],\n [6, 32, 58],\n [6, 34, 62],\n [6, 26, 46, 66],\n [6, 26, 48, 70],\n [6, 26, 50, 74],\n [6, 30, 54, 78],\n [6, 30, 56, 82],\n [6, 30, 58, 86],\n [6, 34, 62, 90],\n [6, 28, 50, 72, 94],\n [6, 26, 50, 74, 98],\n [6, 30, 54, 78, 102],\n [6, 28, 54, 80, 106],\n [6, 32, 58, 84, 110],\n [6, 30, 58, 86, 114],\n [6, 34, 62, 90, 118],\n [6, 26, 50, 74, 98, 122],\n [6, 30, 54, 78, 102, 126],\n [6, 26, 52, 78, 104, 130],\n [6, 30, 56, 82, 108, 134],\n [6, 34, 60, 86, 112, 138],\n [6, 30, 58, 86, 114, 142],\n [6, 34, 62, 90, 118, 146],\n [6, 30, 54, 78, 102, 126, 150],\n [6, 24, 50, 76, 102, 128, 154],\n [6, 28, 54, 80, 106, 132, 158],\n [6, 32, 58, 84, 110, 136, 162],\n [6, 26, 54, 82, 110, 138, 166],\n [6, 30, 58, 86, 114, 142, 170]\n];\n\n/** Every alignment centre coordinate for a version. */\nexport const alignmentCentersFor = (version: number): readonly number[] =>\n ALIGNMENT_CENTERS[version] ?? [];\n\n/**\n * The module coordinate of the alignment pattern nearest the far corner.\n *\n * Returns `null` for version 1, which has none — and for which the\n * parallelogram estimate is accurate enough anyway.\n */\nexport const bottomRightAlignmentPosition = (\n version: number\n): number | null => {\n const centers = ALIGNMENT_CENTERS[version];\n if (centers === undefined || centers.length === 0) return null;\n\n // The last coordinate is nearest the bottom-right corner. Both axes use the\n // same value, since the pattern grid is symmetric.\n return centers[centers.length - 1] ?? null;\n};\n\nconst bitAt = (matrix: BitMatrix, x: number, y: number): number => {\n if (x < 0 || y < 0 || x >= matrix.width || y >= matrix.height) return 0;\n return matrix.bits[y * matrix.width + x];\n};\n\n/**\n * Whether a point sits at the centre of a 5x5 alignment pattern.\n *\n * The pattern is a dark 5x5 square with a light 3x3 inside and a single dark\n * module at the centre — so a scan through it reads dark, light, dark. Rather\n * than match run lengths, this checks that ring structure directly, which\n * survives the blur and rounding that a small pattern suffers most.\n */\nconst looksLikeAlignment = (\n matrix: BitMatrix,\n x: number,\n y: number,\n moduleSize: number\n): boolean => {\n const step = Math.max(1, Math.round(moduleSize));\n\n // Centre must be dark.\n if (bitAt(matrix, x, y) !== 1) return false;\n\n // The ring one module out must be light on all four sides.\n const light =\n bitAt(matrix, x - step, y) === 0 &&\n bitAt(matrix, x + step, y) === 0 &&\n bitAt(matrix, x, y - step) === 0 &&\n bitAt(matrix, x, y + step) === 0;\n if (!light) return false;\n\n // The ring two modules out must be dark on all four sides.\n return (\n bitAt(matrix, x - step * 2, y) === 1 &&\n bitAt(matrix, x + step * 2, y) === 1 &&\n bitAt(matrix, x, y - step * 2) === 1 &&\n bitAt(matrix, x, y + step * 2) === 1\n );\n};\n\n/**\n * Search for the alignment pattern near where the transform predicts it.\n *\n * Searched in a spiral outward from the estimate, so the nearest match wins:\n * a large symbol may carry several alignment patterns, and locking onto a\n * distant one would be worse than not finding any.\n *\n * Returns `null` when nothing matches, which is a normal outcome — the pattern\n * may be damaged, glared out, or outside the frame. The caller falls back to\n * the parallelogram estimate.\n */\nexport const findAlignmentPattern = (\n matrix: BitMatrix,\n estimate: Point,\n moduleSize: number,\n /** How many modules out to search. Wider when the estimate is less trusted. */\n searchModules = 4\n): Point | null => {\n // Scaled to how wrong the prediction can be, not to the pattern's own size.\n //\n // The prediction comes from a transform whose fourth corner is a guess, so\n // its error grows with the symbol: on a version 40 image measured here, the\n // corner estimate was 65px out and the true alignment pattern sat 87px from\n // the prediction, while a radius of moduleSize * 4 searched only 27px. The\n // search was tightest exactly where the estimate was worst, so the pattern\n // that would have FIXED the estimate was never found.\n //\n // Bounded rather than unlimited: past a few modules a \"match\" is more\n // likely to be unrelated texture than the pattern being looked for.\n const radius = Math.max(8, Math.round(moduleSize * searchModules));\n\n for (let ring = 0; ring <= radius; ring++) {\n for (let dy = -ring; dy <= ring; dy++) {\n for (let dx = -ring; dx <= ring; dx++) {\n // Only the perimeter of each ring — the interior was covered already.\n if (ring > 0 && Math.abs(dx) !== ring && Math.abs(dy) !== ring) {\n continue;\n }\n\n const x = Math.round(estimate.x) + dx;\n const y = Math.round(estimate.y) + dy;\n\n if (looksLikeAlignment(matrix, x, y, moduleSize)) return { x, y };\n }\n }\n }\n\n return null;\n};\n\n/**\n * Locate every alignment pattern, giving a measured grid of reference points.\n *\n * Returns a row-major grid the same shape as the version's alignment\n * coordinates, with `null` wherever a pattern could not be found — damaged,\n * glared out, or (at three corners) overlapping a finder and therefore absent\n * by design.\n *\n * This is what makes piecewise sampling possible: rather than one fourth\n * corner, it measures where the symbol actually is at points spread across its\n * whole area, which is the only way to see a warp that a single plane cannot\n * model.\n */\nexport const locateAlignmentGrid = (\n matrix: BitMatrix,\n transform: Transform,\n size: number,\n version: number,\n moduleSize: number\n): {\n anchors: Array<Array<Point | null>>;\n positions: readonly number[];\n} | null => {\n const centers = ALIGNMENT_CENTERS[version];\n if (centers === undefined || centers.length < 2) return null;\n\n const span = size - 7;\n const anchors: Array<Array<Point | null>> = [];\n\n for (const cy of centers) {\n const row: Array<Point | null> = [];\n for (const cx of centers) {\n // The three finder corners have no alignment pattern. Their positions\n // are known exactly from the finders themselves, so they are supplied\n // by the caller rather than searched for here.\n const nearFinder =\n (cx <= 8 && cy <= 8) ||\n (cx <= 8 && cy >= size - 9) ||\n (cx >= size - 9 && cy <= 8);\n\n const predicted = applyTransform(\n transform,\n (cx - 3.5) / span,\n (cy - 3.5) / span\n );\n\n row.push(\n nearFinder\n ? predicted\n : findAlignmentPattern(matrix, predicted, moduleSize)\n );\n }\n anchors.push(row);\n }\n\n interpolateMissing(anchors);\n return { anchors, positions: centers };\n};\n\n/**\n * Fill anchors that could not be located, from the ones that could.\n *\n * A missing anchor otherwise drops its whole cell back to the global\n * transform, which is the flat one piecewise sampling exists to replace — so\n * one glared-out or damaged alignment pattern loses a region far larger than\n * itself. jsQR's own issue #197 names this directly when proposing the same\n * technique: break the symbol into several transforms, \"interpolating over\n * the ones that cannot be found\".\n *\n * Interpolation is linear from the nearest located anchors in the same row,\n * then the same column. That is a good approximation because the warp being\n * corrected is smooth by nature — paper bends, it does not crease randomly —\n * and any estimate on the measured surface beats reverting to a plane.\n */\nconst interpolateMissing = (anchors: Array<Array<Point | null>>): void => {\n const rows = anchors.length;\n const columns = anchors[0]?.length ?? 0;\n\n /** Nearest located neighbours along one axis, with their distances. */\n const neighbours = (\n at: (index: number) => Point | null,\n length: number,\n index: number\n ): {\n before?: { point: Point; gap: number };\n after?: { point: Point; gap: number };\n } => {\n const result: {\n before?: { point: Point; gap: number };\n after?: { point: Point; gap: number };\n } = {};\n\n for (let i = index - 1; i >= 0; i--) {\n const point = at(i);\n if (point !== null) {\n result.before = { point, gap: index - i };\n break;\n }\n }\n for (let i = index + 1; i < length; i++) {\n const point = at(i);\n if (point !== null) {\n result.after = { point, gap: i - index };\n break;\n }\n }\n return result;\n };\n\n for (let row = 0; row < rows; row++) {\n for (let column = 0; column < columns; column++) {\n if (anchors[row][column] !== null) continue;\n\n const horizontal = neighbours(\n (i) => anchors[row][i] ?? null,\n columns,\n column\n );\n const vertical = neighbours(\n (i) => anchors[i]?.[column] ?? null,\n rows,\n row\n );\n\n // Prefer an axis with anchors on BOTH sides — that interpolates rather\n // than extrapolates, and extrapolation compounds error away from the\n // measured points.\n const pair =\n horizontal.before && horizontal.after\n ? horizontal\n : vertical.before && vertical.after\n ? vertical\n : null;\n\n if (pair?.before && pair.after) {\n const total = pair.before.gap + pair.after.gap;\n const weight = pair.before.gap / total;\n anchors[row][column] = {\n x:\n pair.before.point.x +\n (pair.after.point.x - pair.before.point.x) * weight,\n y:\n pair.before.point.y +\n (pair.after.point.y - pair.before.point.y) * weight\n };\n }\n }\n }\n};\n\n/**\n * Estimate the fourth corner by following the symbol's own edges.\n *\n * The parallelogram assumption — that the far corner sits where the two arms\n * of the L would meet — ignores perspective entirely, and perspective is\n * precisely what makes the far corner move. Measured against a reference\n * decoder, correcting this one point takes `perspective` from 2 of 23 images\n * to 7, `glare` from 2 of 17 to 7, and `curved` from 18 of 36 to 27. It is\n * the single largest error in the pipeline.\n *\n * The symbol's outer boundary is a hard edge against the quiet zone, so it\n * can be measured rather than assumed: walk outward along the top edge from\n * the top-right finder and along the left edge from the bottom-left finder,\n * find where the dark modules stop, and intersect the two lines. That\n * intersection is the fourth corner, and it follows the real perspective\n * because it is derived from the real edges.\n */\nexport const estimateCornerFromEdges = (\n matrix: BitMatrix,\n finders: FinderTriple,\n moduleSize: number,\n fallback: Point\n): Point => {\n const { topLeft, topRight, bottomLeft } = finders;\n\n // Direction vectors along the two arms of the L.\n const alongTop = {\n x: topRight.center.x - topLeft.center.x,\n y: topRight.center.y - topLeft.center.y\n };\n const alongLeft = {\n x: bottomLeft.center.x - topLeft.center.x,\n y: bottomLeft.center.y - topLeft.center.y\n };\n\n /**\n * Walk from `start` in direction `step` until the symbol ends.\n *\n * \"Ends\" means a run of light longer than a module can be — inside the\n * symbol, light runs are bounded by the module grid, so a longer one is the\n * quiet zone. Counting a run rather than stopping at the first light pixel\n * is what makes this survive a symbol whose last column happens to be light.\n */\n const walkToEdge = (start: Point, step: Point): Point | null => {\n const length = Math.hypot(step.x, step.y);\n if (length === 0) return null;\n\n const unit = { x: step.x / length, y: step.y / length };\n const limit = Math.round(length * 1.6);\n const quietRun = Math.max(3, Math.round(moduleSize * 2.5));\n\n let light = 0;\n let lastDark: Point | null = null;\n\n for (let i = 0; i < limit; i++) {\n const x = Math.round(start.x + unit.x * i);\n const y = Math.round(start.y + unit.y * i);\n if (x < 0 || y < 0 || x >= matrix.width || y >= matrix.height) break;\n\n if (matrix.bits[y * matrix.width + x] === 1) {\n light = 0;\n lastDark = { x, y };\n } else if (++light > quietRun) {\n break;\n }\n }\n\n return lastDark;\n };\n\n // From each far finder, walk along the edge that continues away from the\n // top-left one. Those two walks end at the two ends of the far corner.\n const rightEdge = walkToEdge(topRight.center, alongLeft);\n const bottomEdge = walkToEdge(bottomLeft.center, alongTop);\n if (rightEdge === null || bottomEdge === null) return fallback;\n\n // Intersect the line through topRight along alongLeft with the line through\n // bottomLeft along alongTop.\n const denominator = alongLeft.x * alongTop.y - alongLeft.y * alongTop.x;\n if (Math.abs(denominator) < 1e-6) return fallback;\n\n const dx = bottomEdge.x - rightEdge.x;\n const dy = bottomEdge.y - rightEdge.y;\n const t = (dx * alongTop.y - dy * alongTop.x) / denominator;\n\n const corner = {\n x: rightEdge.x + alongLeft.x * t,\n y: rightEdge.y + alongLeft.y * t\n };\n\n // Sanity: the corner must lie beyond both far finders and within a\n // plausible distance. A wild intersection is worse than the parallelogram.\n const span = Math.hypot(alongTop.x, alongTop.y);\n const drift = Math.hypot(corner.x - fallback.x, corner.y - fallback.y);\n return Number.isFinite(corner.x) &&\n Number.isFinite(corner.y) &&\n drift < span * 0.4\n ? corner\n : fallback;\n};\n\n/**\n * Refine the fourth corner using the alignment pattern, when one can be found.\n *\n * The alignment centre sits at module `(position, position)`, not at the\n * symbol's corner, so its measured location has to be extrapolated outward to\n * where the corner actually is. Doing that in the transform's own coordinate\n * space keeps the perspective it already models.\n */\nexport const refineBottomRight = (\n matrix: BitMatrix,\n transform: Transform,\n finders: FinderTriple,\n size: number,\n version: number,\n fallback: Point\n): Point => {\n const position = bottomRightAlignmentPosition(version);\n if (position === null) return fallback;\n\n const span = size - 7;\n // Where the current (estimated) transform thinks the pattern is.\n const predicted = applyTransform(\n transform,\n (position - 3.5) / span,\n (position - 3.5) / span\n );\n\n const moduleSize =\n (finders.topLeft.moduleSize +\n finders.topRight.moduleSize +\n finders.bottomLeft.moduleSize) /\n 3;\n\n // Scaled to the symbol, because that is what scales the error. The corner\n // guess assumes a parallelogram, and its error grows with how far the far\n // corner is from the three measured ones — negligible on a version 2\n // symbol, 65px on the version 40 measured here. A fixed wide radius would\n // instead find false matches on small symbols whose estimate was already\n // good, which measurably costs more than it recovers.\n const found = findAlignmentPattern(\n matrix,\n predicted,\n moduleSize,\n Math.max(4, size / 12)\n );\n if (found === null) return fallback;\n\n // Extrapolate from the alignment centre out to the symbol corner, along the\n // line from the top-left finder. The corner is at module (size-3.5), the\n // alignment at (position), so the ratio is fixed by the version.\n const fromCorner = size - 3.5 - position;\n const scale = (size - 3.5 - 3.5) / (position - 3.5);\n\n // A degenerate ratio means the version table and the size disagree; trust\n // the fallback rather than producing a wild corner.\n if (!Number.isFinite(scale) || scale <= 0) return fallback;\n void fromCorner;\n\n return {\n x: finders.topLeft.center.x + (found.x - finders.topLeft.center.x) * scale,\n y: finders.topLeft.center.y + (found.y - finders.topLeft.center.y) * scale\n };\n};\n","/**\n * Block structure and de-interleaving.\n *\n * A QR does not store its codewords in reading order. They are split into\n * blocks, each independently protected by Reed-Solomon, and then *interleaved*\n * — one codeword from each block in turn — before being written into the\n * symbol.\n *\n * That is a deliberate defence against the failure QRs actually suffer:\n * physical damage is contiguous. A scratch, a fold, or a thumb takes out a\n * run of adjacent modules. Without interleaving that run lands entirely inside\n * one block and exceeds its correction capacity, losing the symbol. With it,\n * the same damage is spread thinly across every block, and each one repairs\n * its own small share.\n *\n * Undoing that is this module's job: read the interleaved stream, hand each\n * block back its own codewords, and let Reed-Solomon repair them separately.\n */\n\nimport type { ErrorCorrectionLevel } from \"./format.js\";\n\n/**\n * How one version and EC level splits into blocks.\n *\n * QR block layouts are not uniform: most versions use two GROUPS with\n * different data-codeword counts, because the data region rarely divides\n * evenly. Modelling only one group works for a handful of versions and\n * silently mis-splits the rest.\n */\nexport interface BlockStructure {\n /** Error-correction codewords per block. Identical across both groups. */\n readonly errorCodewordsPerBlock: number;\n /** Blocks in the first group, and how many data codewords each holds. */\n readonly group1: { readonly blocks: number; readonly dataCodewords: number };\n /** The second group, absent when the split is even. */\n readonly group2?: { readonly blocks: number; readonly dataCodewords: number };\n}\n\n/**\n * Block layouts, from ISO/IEC 18004 Table 13-22.\n *\n * Indexed by version then EC level. Each entry is\n * `[ecPerBlock, group1Blocks, group1Data, group2Blocks, group2Data]`, with the\n * group-2 pair omitted when there is only one group.\n *\n * This is the largest table in the decoder and there is no way to derive it —\n * the values are the result of design decisions recorded in the standard, not\n * of a formula. It is therefore verified in tests against an independent\n * invariant: the codewords a layout describes must sum to exactly the symbol's\n * capacity, which catches any transcription error.\n */\nconst BLOCK_TABLE: Readonly<\n Record<number, Readonly<Record<ErrorCorrectionLevel, readonly number[]>>>\n> = {\n 1: { L: [7, 1, 19], M: [10, 1, 16], Q: [13, 1, 13], H: [17, 1, 9] },\n 2: { L: [10, 1, 34], M: [16, 1, 28], Q: [22, 1, 22], H: [28, 1, 16] },\n 3: { L: [15, 1, 55], M: [26, 1, 44], Q: [18, 2, 17], H: [22, 2, 13] },\n 4: { L: [20, 1, 80], M: [18, 2, 32], Q: [26, 2, 24], H: [16, 4, 9] },\n 5: {\n L: [26, 1, 108],\n M: [24, 2, 43],\n Q: [18, 2, 15, 2, 16],\n H: [22, 2, 11, 2, 12]\n },\n 6: { L: [18, 2, 68], M: [16, 4, 27], Q: [24, 4, 19], H: [28, 4, 15] },\n 7: {\n L: [20, 2, 78],\n M: [18, 4, 31],\n Q: [18, 2, 14, 4, 15],\n H: [26, 4, 13, 1, 14]\n },\n 8: {\n L: [24, 2, 97],\n M: [22, 2, 38, 2, 39],\n Q: [22, 4, 18, 2, 19],\n H: [26, 4, 14, 2, 15]\n },\n 9: {\n L: [30, 2, 116],\n M: [22, 3, 36, 2, 37],\n Q: [20, 4, 16, 4, 17],\n H: [24, 4, 12, 4, 13]\n },\n 10: {\n L: [18, 2, 68, 2, 69],\n M: [26, 4, 43, 1, 44],\n Q: [24, 6, 19, 2, 20],\n H: [28, 6, 15, 2, 16]\n },\n 11: {\n L: [20, 4, 81],\n M: [30, 1, 50, 4, 51],\n Q: [28, 4, 22, 4, 23],\n H: [24, 3, 12, 8, 13]\n },\n 12: {\n L: [24, 2, 92, 2, 93],\n M: [22, 6, 36, 2, 37],\n Q: [26, 4, 20, 6, 21],\n H: [28, 7, 14, 4, 15]\n },\n 13: {\n L: [26, 4, 107],\n M: [22, 8, 37, 1, 38],\n Q: [24, 8, 20, 4, 21],\n H: [22, 12, 11, 4, 12]\n },\n 14: {\n L: [30, 3, 115, 1, 116],\n M: [24, 4, 40, 5, 41],\n Q: [20, 11, 16, 5, 17],\n H: [24, 11, 12, 5, 13]\n },\n 15: {\n L: [22, 5, 87, 1, 88],\n M: [24, 5, 41, 5, 42],\n Q: [30, 5, 24, 7, 25],\n H: [24, 11, 12, 7, 13]\n },\n 16: {\n L: [24, 5, 98, 1, 99],\n M: [28, 7, 45, 3, 46],\n Q: [24, 15, 19, 2, 20],\n H: [30, 3, 15, 13, 16]\n },\n 17: {\n L: [28, 1, 107, 5, 108],\n M: [28, 10, 46, 1, 47],\n Q: [28, 1, 22, 15, 23],\n H: [28, 2, 14, 17, 15]\n },\n 18: {\n L: [30, 5, 120, 1, 121],\n M: [26, 9, 43, 4, 44],\n Q: [28, 17, 22, 1, 23],\n H: [28, 2, 14, 19, 15]\n },\n 19: {\n L: [28, 3, 113, 4, 114],\n M: [26, 3, 44, 11, 45],\n Q: [26, 17, 21, 4, 22],\n H: [26, 9, 13, 16, 14]\n },\n 20: {\n L: [28, 3, 107, 5, 108],\n M: [26, 3, 41, 13, 42],\n Q: [30, 15, 24, 5, 25],\n H: [28, 15, 15, 10, 16]\n },\n 21: {\n L: [28, 4, 116, 4, 117],\n M: [26, 17, 42],\n Q: [28, 17, 22, 6, 23],\n H: [30, 19, 16, 6, 17]\n },\n 22: {\n L: [28, 2, 111, 7, 112],\n M: [28, 17, 46],\n Q: [30, 7, 24, 16, 25],\n H: [24, 34, 13]\n },\n 23: {\n L: [30, 4, 121, 5, 122],\n M: [28, 4, 47, 14, 48],\n Q: [30, 11, 24, 14, 25],\n H: [30, 16, 15, 14, 16]\n },\n 24: {\n L: [30, 6, 117, 4, 118],\n M: [28, 6, 45, 14, 46],\n Q: [30, 11, 24, 16, 25],\n H: [30, 30, 16, 2, 17]\n },\n 25: {\n L: [26, 8, 106, 4, 107],\n M: [28, 8, 47, 13, 48],\n Q: [30, 7, 24, 22, 25],\n H: [30, 22, 15, 13, 16]\n },\n 26: {\n L: [28, 10, 114, 2, 115],\n M: [28, 19, 46, 4, 47],\n Q: [28, 28, 22, 6, 23],\n H: [30, 33, 16, 4, 17]\n },\n 27: {\n L: [30, 8, 122, 4, 123],\n M: [28, 22, 45, 3, 46],\n Q: [30, 8, 23, 26, 24],\n H: [30, 12, 15, 28, 16]\n },\n 28: {\n L: [30, 3, 117, 10, 118],\n M: [28, 3, 45, 23, 46],\n Q: [30, 4, 24, 31, 25],\n H: [30, 11, 15, 31, 16]\n },\n 29: {\n L: [30, 7, 116, 7, 117],\n M: [28, 21, 45, 7, 46],\n Q: [30, 1, 23, 37, 24],\n H: [30, 19, 15, 26, 16]\n },\n 30: {\n L: [30, 5, 115, 10, 116],\n M: [28, 19, 47, 10, 48],\n Q: [30, 15, 24, 25, 25],\n H: [30, 23, 15, 25, 16]\n },\n 31: {\n L: [30, 13, 115, 3, 116],\n M: [28, 2, 46, 29, 47],\n Q: [30, 42, 24, 1, 25],\n H: [30, 23, 15, 28, 16]\n },\n 32: {\n L: [30, 17, 115],\n M: [28, 10, 46, 23, 47],\n Q: [30, 10, 24, 35, 25],\n H: [30, 19, 15, 35, 16]\n },\n 33: {\n L: [30, 17, 115, 1, 116],\n M: [28, 14, 46, 21, 47],\n Q: [30, 29, 24, 19, 25],\n H: [30, 11, 15, 46, 16]\n },\n 34: {\n L: [30, 13, 115, 6, 116],\n M: [28, 14, 46, 23, 47],\n Q: [30, 44, 24, 7, 25],\n H: [30, 59, 16, 1, 17]\n },\n 35: {\n L: [30, 12, 121, 7, 122],\n M: [28, 12, 47, 26, 48],\n Q: [30, 39, 24, 14, 25],\n H: [30, 22, 15, 41, 16]\n },\n 36: {\n L: [30, 6, 121, 14, 122],\n M: [28, 6, 47, 34, 48],\n Q: [30, 46, 24, 10, 25],\n H: [30, 2, 15, 64, 16]\n },\n 37: {\n L: [30, 17, 122, 4, 123],\n M: [28, 29, 46, 14, 47],\n Q: [30, 49, 24, 10, 25],\n H: [30, 24, 15, 46, 16]\n },\n 38: {\n L: [30, 4, 122, 18, 123],\n M: [28, 13, 46, 32, 47],\n Q: [30, 48, 24, 14, 25],\n H: [30, 42, 15, 32, 16]\n },\n 39: {\n L: [30, 20, 117, 4, 118],\n M: [28, 40, 47, 7, 48],\n Q: [30, 43, 24, 22, 25],\n H: [30, 10, 15, 67, 16]\n },\n 40: {\n L: [30, 19, 118, 6, 119],\n M: [28, 18, 47, 31, 48],\n Q: [30, 34, 24, 34, 25],\n H: [30, 20, 15, 61, 16]\n }\n};\n\n/** The block layout for a version and error-correction level. */\nexport const blockStructure = (\n version: number,\n level: ErrorCorrectionLevel\n): BlockStructure | null => {\n const entry = BLOCK_TABLE[version]?.[level];\n if (entry === undefined) return null;\n\n const [errorCodewordsPerBlock, blocks1, data1, blocks2, data2] = entry as [\n number,\n number,\n number,\n number?,\n number?\n ];\n\n return {\n errorCodewordsPerBlock,\n group1: { blocks: blocks1, dataCodewords: data1 },\n ...(blocks2 !== undefined && data2 !== undefined\n ? { group2: { blocks: blocks2, dataCodewords: data2 } }\n : {})\n };\n};\n\n/** Every block's data-codeword count, group 1 followed by group 2. */\nconst blockSizes = (structure: BlockStructure): number[] => [\n ...Array.from<number>({ length: structure.group1.blocks }).fill(\n structure.group1.dataCodewords\n ),\n ...Array.from<number>({ length: structure.group2?.blocks ?? 0 }).fill(\n structure.group2?.dataCodewords ?? 0\n )\n];\n\n/** Total codewords a layout accounts for, data and error correction together. */\nexport const totalCodewords = (structure: BlockStructure): number => {\n const sizes = blockSizes(structure);\n const data = sizes.reduce((sum, size) => sum + size, 0);\n return data + sizes.length * structure.errorCodewordsPerBlock;\n};\n\n/**\n * Undo the interleaving, returning each block's codewords.\n *\n * Data codewords come first, one per block in rotation. Blocks in group 1 are\n * shorter, so once their supply is exhausted the rotation continues over the\n * longer group-2 blocks only — skipping a block that has already been filled\n * rather than reading a codeword it does not own. Error-correction codewords\n * follow, interleaved the same way but with every block the same length.\n */\nexport const deinterleave = (\n codewords: readonly number[],\n structure: BlockStructure\n): Array<{ data: number[]; error: number[] }> => {\n const sizes = blockSizes(structure);\n const blocks = sizes.map(() => ({\n data: [] as number[],\n error: [] as number[]\n }));\n\n const longest = Math.max(...sizes);\n let index = 0;\n\n for (let position = 0; position < longest; position++) {\n for (const [block, size] of sizes.entries()) {\n // Group-1 blocks run out first. Skipping them here — rather than\n // reading and discarding — is what keeps the remaining blocks aligned\n // with the stream.\n if (position >= size) continue;\n blocks[block].data.push(codewords[index++]);\n }\n }\n\n for (\n let position = 0;\n position < structure.errorCodewordsPerBlock;\n position++\n ) {\n for (const block of blocks) {\n block.error.push(codewords[index++]);\n }\n }\n\n return blocks;\n};\n\n/**\n * Where each interleaved codeword ends up, as `[block, position]`.\n *\n * The inverse of what {@link deinterleave} does to the values, for callers\n * that need to follow a codeword rather than read it — which erasure decoding\n * does: damage is contiguous in the IMAGE, and interleaving is precisely what\n * scatters it across blocks so no single block absorbs all of it. Turning an\n * image region into per-block erasure positions means replaying that\n * scattering.\n *\n * `position` indexes a block's data codewords, then continues into its error\n * codewords, matching the layout `decode` expects.\n */\nexport const interleaveMap = (\n structure: BlockStructure\n): Array<readonly [number, number]> => {\n const sizes = blockSizes(structure);\n const map: Array<readonly [number, number]> = [];\n\n const longest = Math.max(...sizes);\n for (let position = 0; position < longest; position++) {\n for (const [block, size] of sizes.entries()) {\n if (position >= size) continue;\n map.push([block, position]);\n }\n }\n\n for (\n let position = 0;\n position < structure.errorCodewordsPerBlock;\n position++\n ) {\n for (const [block, size] of sizes.entries()) {\n map.push([block, size + position]);\n }\n }\n\n return map;\n};\n\n/** Pack a bit array into bytes, most significant bit first. */\nexport const bitsToCodewords = (bits: Uint8Array): number[] => {\n const codewords: number[] = [];\n\n for (let i = 0; i + 8 <= bits.length; i += 8) {\n let byte = 0;\n for (let j = 0; j < 8; j++) byte = (byte << 1) | bits[i + j];\n codewords.push(byte);\n }\n\n // Trailing bits that do not fill a byte are the symbol's remainder bits —\n // padding by construction, and deliberately dropped rather than zero-padded\n // into a phantom codeword.\n return codewords;\n};\n","/**\n * Reading the decoded bitstream back into text.\n *\n * By this point the codewords have been de-interleaved and repaired, so what\n * remains is a plain bit sequence in the format ISO/IEC 18004 §7.4 describes:\n * a mode indicator, a character count whose WIDTH depends on both the mode and\n * the symbol version, then the payload, repeating until a terminator or the\n * bits run out.\n *\n * Scope note: numeric, alphanumeric, and byte modes are supported. Kanji and\n * ECI are not, and that is deliberate — they are a large share of what makes\n * general-purpose decoders big, and nothing that encodes a URL for a sign-in\n * screen uses them. An unsupported mode returns `null` rather than throwing,\n * because a camera pointed at the world sees all sorts of symbols and an\n * unreadable one is a non-event.\n */\n\n/** Mode indicators, from ISO/IEC 18004 Table 2. */\nconst MODE = {\n terminator: 0x0,\n numeric: 0x1,\n alphanumeric: 0x2,\n byte: 0x4,\n kanji: 0x8,\n eci: 0x7,\n structuredAppend: 0x3,\n fnc1First: 0x5,\n fnc1Second: 0x9\n} as const;\n\n/**\n * The alphanumeric character set, in code order.\n *\n * Note it is uppercase-only and includes nine punctuation characters — a\n * deliberately small set, which is why alphanumeric mode packs two characters\n * into 11 bits.\n */\nconst ALPHANUMERIC = `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:`;\n\n/**\n * Character-count field widths, by mode and version range.\n *\n * The width changes at versions 10 and 27 because larger symbols can hold more\n * characters than a short field could express. Using one width everywhere is a\n * classic decoder bug: it works perfectly for small QRs and silently\n * misreads every large one, because the count is read with the wrong number of\n * bits and everything after it shifts.\n */\nconst countBits = (mode: number, version: number): number => {\n const tier = version <= 9 ? 0 : version <= 26 ? 1 : 2;\n\n switch (mode) {\n case MODE.numeric:\n return [10, 12, 14][tier];\n case MODE.alphanumeric:\n return [9, 11, 13][tier];\n case MODE.byte:\n return [8, 16, 16][tier];\n case MODE.kanji:\n return [8, 10, 12][tier];\n default:\n return 0;\n }\n};\n\n/** A cursor over a bit array that knows when it has run out. */\nclass BitReader {\n #bits: Uint8Array;\n #position = 0;\n\n constructor(bits: Uint8Array) {\n this.#bits = bits;\n }\n\n get remaining(): number {\n return this.#bits.length - this.#position;\n }\n\n /**\n * Read `count` bits as an unsigned integer, most significant first.\n *\n * Returns `null` rather than a short read when the stream runs out. A\n * truncated field silently treated as a small number is how a corrupted\n * symbol turns into confident garbage instead of a clean failure.\n */\n read(count: number): number | null {\n if (count > this.remaining) return null;\n\n let value = 0;\n for (let i = 0; i < count; i++) {\n value = (value << 1) | this.#bits[this.#position + i];\n }\n this.#position += count;\n return value;\n }\n}\n\n/** Read `count` digits packed three-to-ten-bits. */\nconst readNumeric = (reader: BitReader, count: number): string | null => {\n let out = ``;\n let left = count;\n\n while (left >= 3) {\n const triple = reader.read(10);\n // 10 bits can express up to 1023, but only 000-999 are legal. A larger\n // value means the stream is not what it claims to be.\n if (triple === null || triple > 999) return null;\n out += String(triple).padStart(3, `0`);\n left -= 3;\n }\n\n if (left === 2) {\n const pair = reader.read(7);\n if (pair === null || pair > 99) return null;\n out += String(pair).padStart(2, `0`);\n } else if (left === 1) {\n const single = reader.read(4);\n if (single === null || single > 9) return null;\n out += String(single);\n }\n\n return out;\n};\n\n/** Read `count` characters packed two-to-eleven-bits. */\nconst readAlphanumeric = (reader: BitReader, count: number): string | null => {\n let out = ``;\n let left = count;\n\n while (left >= 2) {\n const pair = reader.read(11);\n // 45 * 45 - 1 is the largest legal pair; beyond that the stream is wrong.\n if (pair === null || pair > 44 * 45 + 44) return null;\n out += ALPHANUMERIC[Math.floor(pair / 45)] + ALPHANUMERIC[pair % 45];\n left -= 2;\n }\n\n if (left === 1) {\n const single = reader.read(6);\n if (single === null || single > 44) return null;\n out += ALPHANUMERIC[single];\n }\n\n return out;\n};\n\n/**\n * Read `count` bytes and decode them as text.\n *\n * The spec's default is ISO-8859-1, but in practice almost everything encodes\n * UTF-8 without declaring it, so UTF-8 is tried first and Latin-1 is the\n * fallback. Doing it the other way round would mis-decode most real-world QRs\n * containing non-ASCII text — silently, into mojibake rather than an error.\n */\nconst readBytes = (reader: BitReader, count: number): string | null => {\n const bytes = new Uint8Array(count);\n\n for (let i = 0; i < count; i++) {\n const byte = reader.read(8);\n if (byte === null) return null;\n bytes[i] = byte;\n }\n\n try {\n return new TextDecoder(`utf-8`, { fatal: true }).decode(bytes);\n } catch {\n // Not valid UTF-8. Latin-1 maps every byte to a character, so it always\n // succeeds — which is exactly why it cannot be tried first.\n return new TextDecoder(`iso-8859-1`).decode(bytes);\n }\n};\n\n/**\n * Decode a bitstream into text.\n *\n * Returns `null` for anything it cannot read — a truncated stream, an\n * unsupported mode, or a segment whose values are out of range. Callers treat\n * that as \"this frame had no readable code\", which is the honest reading: a\n * partial decode is not a partial success.\n */\nexport const readBitstream = (\n bits: Uint8Array,\n version: number\n): string | null => {\n const reader = new BitReader(bits);\n let out = ``;\n\n for (;;) {\n // Fewer than 4 bits left cannot hold a mode indicator. That is the normal\n // way a stream ends when the terminator was omitted, which is legal.\n if (reader.remaining < 4) break;\n\n const mode = reader.read(4);\n if (mode === null || mode === MODE.terminator) break;\n\n if (\n mode === MODE.kanji ||\n mode === MODE.eci ||\n mode === MODE.structuredAppend ||\n mode === MODE.fnc1First ||\n mode === MODE.fnc1Second\n ) {\n // Out of scope by design. Returning null rather than throwing keeps an\n // unreadable symbol a non-event for a camera pointed at the world.\n return null;\n }\n\n const count = reader.read(countBits(mode, version));\n if (count === null) return null;\n\n const segment =\n mode === MODE.numeric\n ? readNumeric(reader, count)\n : mode === MODE.alphanumeric\n ? readAlphanumeric(reader, count)\n : mode === MODE.byte\n ? readBytes(reader, count)\n : null;\n\n if (segment === null) return null;\n out += segment;\n }\n\n // An empty result means the stream held no segments at all. That is a\n // failed decode, not an empty string — a QR always encodes something.\n return out.length > 0 ? out : null;\n};\n","/**\n * Format and version information.\n *\n * These are the two small fields a decoder must read *before* it can read\n * anything else: format info says which error-correction level and mask were\n * used, version info says how big the symbol is. Everything downstream depends\n * on getting them right, so both carry their own error correction —\n * independent of the Reed-Solomon protecting the payload.\n *\n * That correction is BCH, not Reed-Solomon. The distinction matters\n * practically: these fields are tiny and fixed-size, so rather than run a\n * decoder, we compare against every legal value and take the closest. Fifteen\n * bits with 32 candidates makes exhaustive comparison both simpler and faster\n * than the algebra — and it cannot fail in a way that returns a wrong-but-\n * plausible answer, which for a field that determines how to read everything\n * else is the failure that matters.\n */\n\nimport type { BitMatrix } from \"../types.js\";\n\n/** Error-correction level, in the order the format field encodes them. */\nexport type ErrorCorrectionLevel = `L` | `M` | `Q` | `H`;\n\n/** What the format field carries. */\nexport interface FormatInfo {\n readonly errorCorrectionLevel: ErrorCorrectionLevel;\n /** Which of the eight mask patterns was applied to the data modules. */\n readonly mask: number;\n}\n\n/**\n * The 32 legal format values, pre-computed.\n *\n * Index is the raw 5-bit format (EC level in the high 2 bits, mask in the low\n * 3); the value is the full 15-bit sequence after BCH encoding and XOR with\n * the fixed mask pattern 0x5412.\n *\n * From ISO/IEC 18004 Annex C. Written out rather than generated because the\n * table IS the specification here — generating it would mean reimplementing\n * the BCH encoder just to reproduce 32 constants that never change, and any\n * bug in that generator would be invisible.\n */\nconst FORMAT_SEQUENCES = [\n 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, 0x77c4,\n 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, 0x1689, 0x13be,\n 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b, 0x355f, 0x3068, 0x3f31,\n 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed\n] as const;\n\n/**\n * The 34 legal version values for versions 7 and above.\n *\n * Versions 1-6 carry no version block at all — their size is inferred from\n * the module count, which is why `readVersion` takes the matrix dimension as\n * its starting point rather than trusting this field alone.\n *\n * From ISO/IEC 18004 Annex D.\n */\nconst VERSION_SEQUENCES = [\n 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d,\n 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9,\n 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75,\n 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64,\n 0x27541, 0x28c69\n] as const;\n\n/** Error-correction levels in the order the format field encodes them. */\nconst EC_LEVELS: readonly ErrorCorrectionLevel[] = [`M`, `L`, `H`, `Q`];\n\n/** How many bits differ between two values. */\nconst hammingDistance = (a: number, b: number): number => {\n let difference = a ^ b;\n let count = 0;\n while (difference !== 0) {\n count += difference & 1;\n difference >>>= 1;\n }\n return count;\n};\n\n/**\n * Find the closest legal value, or `null` if nothing is close enough.\n *\n * `maxDistance` is the correction capability of the BCH code. Accepting a\n * worse match would mean guessing, and a wrong format value does not produce a\n * slightly-wrong decode — it produces a completely different (and confidently\n * wrong) reading of every module in the symbol.\n */\nconst closestMatch = (\n received: number,\n candidates: readonly number[],\n maxDistance: number\n): { index: number; distance: number } | null => {\n let best: { index: number; distance: number } | null = null;\n\n for (const [index, candidate] of candidates.entries()) {\n const distance = hammingDistance(received, candidate);\n if (distance === 0) return { index, distance };\n if (best === null || distance < best.distance) best = { index, distance };\n }\n\n if (best === null || best.distance > maxDistance) return null;\n return best;\n};\n\n/**\n * Decode a 15-bit format sequence.\n *\n * The BCH code here corrects up to 3 bit errors, so anything further away is\n * rejected rather than guessed at.\n */\nexport const decodeFormat = (raw: number): FormatInfo | null => {\n const match = closestMatch(raw & 0x7fff, FORMAT_SEQUENCES, 3);\n if (match === null) return null;\n\n return {\n errorCorrectionLevel: EC_LEVELS[(match.index >> 3) & 0x3],\n mask: match.index & 0x7\n };\n};\n\n/**\n * Decode an 18-bit version sequence, returning the version number.\n *\n * Corrects up to 3 bit errors, same as format. Returns `null` rather than a\n * guess: reading the wrong version means sampling the wrong grid size, which\n * fails in confusing ways much later.\n */\nexport const decodeVersion = (raw: number): number | null => {\n const match = closestMatch(raw & 0x3ffff, VERSION_SEQUENCES, 3);\n // The table starts at version 7 — versions 1-6 have no version block.\n return match === null ? null : match.index + 7;\n};\n\n/** Read a module as a bit. Out-of-range reads are treated as light. */\nconst bitAt = (matrix: BitMatrix, x: number, y: number): number => {\n if (x < 0 || y < 0 || x >= matrix.width || y >= matrix.height) return 0;\n return matrix.bits[y * matrix.width + x];\n};\n\n/**\n * Read the format information out of a matrix.\n *\n * It is stored twice, in two different places, precisely so that damage to one\n * copy is survivable. The primary copy wraps the top-left finder; the backup\n * runs along the bottom-left and top-right edges.\n *\n * Both are tried, primary first. Reading only one would throw away the\n * redundancy the format was designed with — and the backup exists because the\n * top-left corner is exactly where a thumb, a logo, or a fold tends to land.\n */\nexport const readFormat = (matrix: BitMatrix): FormatInfo | null => {\n const size = matrix.width;\n\n // Primary: around the top-left finder pattern. The skips at 6 avoid the\n // timing pattern, which runs through row and column 6.\n let primary = 0;\n for (let x = 0; x <= 5; x++) primary = (primary << 1) | bitAt(matrix, x, 8);\n primary = (primary << 1) | bitAt(matrix, 7, 8);\n primary = (primary << 1) | bitAt(matrix, 8, 8);\n primary = (primary << 1) | bitAt(matrix, 8, 7);\n for (let y = 5; y >= 0; y--) primary = (primary << 1) | bitAt(matrix, 8, y);\n\n const fromPrimary = decodeFormat(primary);\n if (fromPrimary !== null) return fromPrimary;\n\n // Backup: bottom-left going up, then top-right going right.\n let backup = 0;\n for (let y = size - 1; y >= size - 7; y--) {\n backup = (backup << 1) | bitAt(matrix, 8, y);\n }\n for (let x = size - 8; x < size; x++) {\n backup = (backup << 1) | bitAt(matrix, x, 8);\n }\n\n return decodeFormat(backup);\n};\n\n/**\n * Read the version out of a matrix.\n *\n * Versions 1-6 carry no version block, so their version comes from the module\n * count alone — a 21x21 symbol is version 1, and each version adds 4 modules\n * per side. For 7 and above the dimension still gives the answer, but the\n * explicit block is read as a cross-check: if the two disagree, the grid was\n * probably sampled at the wrong size, and continuing would produce confident\n * nonsense.\n */\nexport const readVersion = (matrix: BitMatrix): number | null => {\n const size = matrix.width;\n if (size !== matrix.height) return null;\n if (size < 21 || size > 177 || (size - 17) % 4 !== 0) return null;\n\n const fromSize = (size - 17) / 4;\n if (fromSize < 7) return fromSize;\n\n // Bottom-left block, read as 18 bits.\n let bottomLeft = 0;\n for (let y = 5; y >= 0; y--) {\n for (let x = size - 9; x >= size - 11; x--) {\n bottomLeft = (bottomLeft << 1) | bitAt(matrix, x, y);\n }\n }\n\n const decoded = decodeVersion(bottomLeft);\n if (decoded === fromSize) return fromSize;\n\n // Top-right block, as the second copy.\n let topRight = 0;\n for (let x = 5; x >= 0; x--) {\n for (let y = size - 9; y >= size - 11; y--) {\n topRight = (topRight << 1) | bitAt(matrix, x, y);\n }\n }\n\n return decodeVersion(topRight) === fromSize ? fromSize : null;\n};\n","/**\n * Mask patterns and the function-module map.\n *\n * A QR encoder XORs the data region with one of eight patterns before writing\n * it, choosing whichever produces the most evenly-distributed result. That is\n * what stops a payload of mostly-zeroes rendering as a large blank area that\n * scanners mistake for background, or as stripes that look like a finder\n * pattern.\n *\n * Decoding therefore means applying the same pattern again — XOR is its own\n * inverse — but ONLY to data modules. Function modules (finders, timing,\n * alignment, format, version) are never masked, so the map of where they live\n * has to be exact. A single module misclassified shifts every subsequent bit\n * and the payload decodes to noise.\n */\n\nimport type { BitMatrix } from \"../types.js\";\n\n/**\n * The eight mask patterns, from ISO/IEC 18004 §7.8.2.\n *\n * Each answers \"should the module at (x, y) be flipped?\". They are written as\n * predicates rather than lookup tables because the formulae ARE the spec, and\n * a reader checking this against the standard can compare them line by line.\n *\n * Note the argument order: the spec writes these in terms of (row, column),\n * so these take (y, x) — matching it exactly rather than swapping to the (x,\n * y) convention used elsewhere, because a transposed mask still produces a\n * valid-looking symbol that decodes to garbage.\n */\nconst MASK_PATTERNS: ReadonlyArray<(y: number, x: number) => boolean> = [\n (y, x) => (y + x) % 2 === 0,\n (y) => y % 2 === 0,\n (_y, x) => x % 3 === 0,\n (y, x) => (y + x) % 3 === 0,\n (y, x) => (Math.floor(y / 2) + Math.floor(x / 3)) % 2 === 0,\n (y, x) => ((y * x) % 2) + ((y * x) % 3) === 0,\n (y, x) => (((y * x) % 2) + ((y * x) % 3)) % 2 === 0,\n (y, x) => (((y + x) % 2) + ((y * x) % 3)) % 2 === 0\n];\n\n/**\n * Alignment pattern centre coordinates, indexed by version.\n *\n * From ISO/IEC 18004 Annex E. Version 1 has none; every later version places\n * a 5x5 pattern at each intersection of these coordinates, except where one\n * would overlap a finder.\n */\nconst ALIGNMENT_CENTERS: ReadonlyArray<readonly number[]> = [\n [],\n [],\n [6, 18],\n [6, 22],\n [6, 26],\n [6, 30],\n [6, 34],\n [6, 22, 38],\n [6, 24, 42],\n [6, 26, 46],\n [6, 28, 50],\n [6, 30, 54],\n [6, 32, 58],\n [6, 34, 62],\n [6, 26, 46, 66],\n [6, 26, 48, 70],\n [6, 26, 50, 74],\n [6, 30, 54, 78],\n [6, 30, 56, 82],\n [6, 30, 58, 86],\n [6, 34, 62, 90],\n [6, 28, 50, 72, 94],\n [6, 26, 50, 74, 98],\n [6, 30, 54, 78, 102],\n [6, 28, 54, 80, 106],\n [6, 32, 58, 84, 110],\n [6, 30, 58, 86, 114],\n [6, 34, 62, 90, 118],\n [6, 26, 50, 74, 98, 122],\n [6, 30, 54, 78, 102, 126],\n [6, 26, 52, 78, 104, 130],\n [6, 30, 56, 82, 108, 134],\n [6, 34, 60, 86, 112, 138],\n [6, 30, 58, 86, 114, 142],\n [6, 34, 62, 90, 118, 146],\n [6, 30, 54, 78, 102, 126, 150],\n [6, 24, 50, 76, 102, 128, 154],\n [6, 28, 54, 80, 106, 132, 158],\n [6, 32, 58, 84, 110, 136, 162],\n [6, 26, 54, 82, 110, 138, 166],\n [6, 30, 58, 86, 114, 142, 170]\n];\n\n/** Whether a mask index is one of the eight legal patterns. */\nexport const isValidMask = (mask: number): boolean =>\n Number.isInteger(mask) && mask >= 0 && mask < MASK_PATTERNS.length;\n\n/** Apply mask `mask` at `(x, y)`. Its own inverse, so this both masks and unmasks. */\nexport const shouldFlip = (mask: number, x: number, y: number): boolean => {\n const pattern = MASK_PATTERNS[mask];\n if (pattern === undefined) throw new Error(`Unknown mask pattern ${mask}`);\n return pattern(y, x);\n};\n\n/**\n * Build a map of which modules carry data.\n *\n * `true` means the module is a function pattern and must be skipped. Computed\n * once per decode rather than tested per module: the reading order zigzags\n * across the symbol, and re-deriving \"is this a finder?\" at every step is both\n * slower and far easier to get subtly wrong.\n */\nexport const functionModuleMap = (\n size: number,\n version: number\n): Uint8Array => {\n const map = new Uint8Array(size * size);\n const mark = (x: number, y: number): void => {\n if (x >= 0 && y >= 0 && x < size && y < size) map[y * size + x] = 1;\n };\n\n // Finder patterns and their separators, at three corners. 8x8 rather than\n // 7x7 because the one-module separator around each is also reserved.\n for (const [originX, originY] of [\n [0, 0],\n [size - 7, 0],\n [0, size - 7]\n ] as const) {\n for (let y = -1; y <= 7; y++) {\n for (let x = -1; x <= 7; x++) mark(originX + x, originY + y);\n }\n }\n\n // Timing patterns: the alternating row and column at index 6.\n for (let i = 0; i < size; i++) {\n mark(6, i);\n mark(i, 6);\n }\n\n // Format information. The primary copy occupies row 8 and column 8 for\n // indices 0-8; the secondary copy is 8 modules along the top-right row and\n // 7 up the bottom-left column. Marking both arms to 8 — the obvious first\n // guess — reserves modules that actually carry data, which shifts every\n // subsequent bit and decodes the payload as noise.\n for (let i = 0; i <= 8; i++) {\n mark(i, 8);\n mark(8, i);\n }\n for (let i = 0; i < 8; i++) mark(size - 1 - i, 8);\n for (let i = 0; i < 7; i++) mark(8, size - 1 - i);\n\n // The dark module, always set. Fixed at (8, 4 * version + 9) by the spec,\n // which is one row above where the bottom-left format copy ends.\n mark(8, 4 * version + 9);\n\n // Alignment patterns, at every intersection that does not overlap a finder.\n const centers = ALIGNMENT_CENTERS[version] ?? [];\n for (const centerY of centers) {\n for (const centerX of centers) {\n const nearFinder =\n (centerX <= 8 && centerY <= 8) ||\n (centerX <= 8 && centerY >= size - 9) ||\n (centerX >= size - 9 && centerY <= 8);\n if (nearFinder) continue;\n\n for (let y = -2; y <= 2; y++) {\n for (let x = -2; x <= 2; x++) mark(centerX + x, centerY + y);\n }\n }\n }\n\n // Version information, for version 7 and above only.\n if (version >= 7) {\n for (let i = 0; i < 6; i++) {\n for (let j = 0; j < 3; j++) {\n mark(size - 11 + j, i);\n mark(i, size - 11 + j);\n }\n }\n }\n\n return map;\n};\n\n/**\n * Read the data modules in the order the spec writes them.\n *\n * The path runs in two-module-wide columns from the bottom-right, alternating\n * upward and downward, skipping the timing column at index 6 and every\n * function module. Within each column, the right module comes first.\n *\n * Returns unmasked bits, since the caller always wants them that way and\n * doing it here keeps the traversal and the mask in one place — they have to\n * agree about coordinates, and separating them invites them to drift.\n */\nexport const readDataBits = (\n matrix: BitMatrix,\n version: number,\n mask: number\n): Uint8Array => {\n const size = matrix.width;\n const functionMap = functionModuleMap(size, version);\n const bits: number[] = [];\n\n let upward = true;\n for (let right = size - 1; right >= 1; right -= 2) {\n // Column 6 is the vertical timing pattern. It is skipped entirely, and\n // every column to its left shifts by one.\n const columnRight = right <= 6 ? right - 1 : right;\n\n for (let step = 0; step < size; step++) {\n const y = upward ? size - 1 - step : step;\n\n for (const x of [columnRight, columnRight - 1]) {\n if (functionMap[y * size + x] === 1) continue;\n\n const bit = matrix.bits[y * size + x];\n bits.push(shouldFlip(mask, x, y) ? bit ^ 1 : bit);\n }\n }\n upward = !upward;\n }\n\n return Uint8Array.from(bits);\n};\n\n/**\n * The module each data bit was read from, in the same order.\n *\n * The traversal that produces the bitstream is the only thing that knows how\n * image positions map onto codewords, and erasure decoding needs exactly that\n * map: a region the imaging layer distrusts is a set of MODULES, while\n * Reed-Solomon wants a set of codeword indices.\n *\n * Kept separate from {@link readDataBits} rather than returned alongside it,\n * because the ordinary decode path never needs it and building an array of\n * coordinate pairs per frame would cost every scan for the benefit of the few\n * that are damaged.\n */\nexport const dataBitOrigins = (\n size: number,\n version: number\n): Array<readonly [number, number]> => {\n const functionMap = functionModuleMap(size, version);\n const origins: Array<readonly [number, number]> = [];\n\n let upward = true;\n for (let right = size - 1; right >= 1; right -= 2) {\n const columnRight = right <= 6 ? right - 1 : right;\n\n for (let step = 0; step < size; step++) {\n const y = upward ? size - 1 - step : step;\n\n for (const x of [columnRight, columnRight - 1]) {\n if (functionMap[y * size + x] === 1) continue;\n origins.push([x, y]);\n }\n }\n upward = !upward;\n }\n\n return origins;\n};\n","/**\n * Arithmetic over GF(256), the field QR error correction is defined in.\n *\n * Every byte of a QR's error correction is a field element, and Reed-Solomon\n * decoding is polynomial algebra over that field. Doing it with ordinary\n * integer maths does not work: the field's rules are different, and the whole\n * error-correcting property depends on them.\n *\n * Two rules are worth internalising before reading anything below:\n *\n * - **Addition is XOR.** There is no carry, so addition and subtraction are\n * the same operation, and `a + a === 0` for every `a`.\n * - **Multiplication is addition of logarithms**, in a field where the\n * logarithms happen to be exponents of a generator element.\n *\n * The tables are built once at module load rather than written out as\n * literals: 512 entries of magic numbers cannot be reviewed, but eight lines\n * that generate them can.\n */\n\n/**\n * The field's defining polynomial, x^8 + x^4 + x^3 + x^2 + 1.\n *\n * Fixed by ISO/IEC 18004 §7.5.2 — not a tunable. A different primitive\n * polynomial gives a different (valid, but incompatible) field, and every\n * codeword would decode to noise.\n */\nconst PRIMITIVE = 0x11d;\n\n/** `EXP[i]` is the generator raised to `i`. Doubled so callers can skip a modulo. */\nconst EXP = new Uint8Array(512);\n/** `LOG[v]` is the exponent that produces `v`. `LOG[0]` is undefined and unused. */\nconst LOG = new Uint8Array(256);\n\n{\n let x = 1;\n for (let i = 0; i < 255; i++) {\n EXP[i] = x;\n LOG[x] = i;\n // Multiply by the generator (2), reducing modulo the field polynomial\n // whenever the result would exceed one byte.\n x <<= 1;\n if (x & 0x100) x ^= PRIMITIVE;\n }\n // The second half repeats the first, so `EXP[a + b]` is valid for any two\n // logarithms without wrapping the index by hand.\n for (let i = 255; i < 512; i++) EXP[i] = EXP[i - 255]!;\n}\n\n/**\n * Add two field elements.\n *\n * XOR. Named rather than inlined because `a ^ b` at a call site reads as bit\n * twiddling, while `add(a, b)` says which algebra is in play.\n */\nexport const add = (a: number, b: number): number => a ^ b;\n\n/** Multiply two field elements. */\nexport const multiply = (a: number, b: number): number =>\n // Zero has no logarithm, so it is handled before the table lookup rather\n // than producing a wrong answer from `LOG[0]`.\n a === 0 || b === 0 ? 0 : EXP[LOG[a] + LOG[b]];\n\n/** Divide two field elements. `b` must be non-zero. */\nexport const divide = (a: number, b: number): number => {\n if (b === 0) throw new Error(`Division by zero in GF(256)`);\n if (a === 0) return 0;\n // +255 keeps the index non-negative when LOG[a] < LOG[b]; the doubled table\n // makes that safe without a modulo.\n return EXP[LOG[a] + 255 - LOG[b]];\n};\n\n/** Raise the field's generator to a power. */\nexport const exp = (power: number): number => EXP[power % 255];\n\n/** The multiplicative inverse of `a`. */\nexport const inverse = (a: number): number => {\n if (a === 0) throw new Error(`Zero has no inverse in GF(256)`);\n return EXP[255 - LOG[a]];\n};\n","/**\n * Polynomials over GF(256).\n *\n * Reed-Solomon treats a block of codewords as the coefficients of a\n * polynomial, so decoding is polynomial algebra: evaluate it at known points\n * to find syndromes, solve for an error locator, then evaluate again to find\n * the magnitudes. Everything here exists to serve that.\n *\n * Coefficients are stored **highest degree first**, matching how the QR spec\n * writes generator polynomials. The alternative reads more naturally in code\n * (`coefficients[i]` being the x^i term) but forces a mental reversal every\n * time this is checked against ISO/IEC 18004, which is where the errors come\n * from.\n *\n * Leading zeroes are always stripped, so `degree` is meaningful and two\n * equal polynomials have one representation.\n */\n\nimport { add, divide, multiply } from \"./galois.js\";\n\n/** Drop leading zero coefficients so `degree` means what it says. */\nconst normalize = (coefficients: readonly number[]): readonly number[] => {\n let first = 0;\n while (first < coefficients.length - 1 && coefficients[first] === 0) first++;\n return coefficients.slice(first);\n};\n\n/** A polynomial over GF(256), highest degree first. */\nexport class Polynomial {\n readonly coefficients: readonly number[];\n\n constructor(coefficients: readonly number[]) {\n if (coefficients.length === 0) {\n throw new Error(`A polynomial needs at least one coefficient`);\n }\n this.coefficients = normalize(coefficients);\n }\n\n /** The zero polynomial — the additive identity. */\n static zero(): Polynomial {\n return new Polynomial([0]);\n }\n\n /** `coefficient * x^degree`, the building block for constructing others. */\n static monomial(degree: number, coefficient: number): Polynomial {\n if (degree < 0) throw new Error(`Monomial degree must not be negative`);\n if (coefficient === 0) return Polynomial.zero();\n\n const coefficients = Array.from<number>({ length: degree + 1 }).fill(0);\n coefficients[0] = coefficient;\n return new Polynomial(coefficients);\n }\n\n get degree(): number {\n return this.coefficients.length - 1;\n }\n\n get isZero(): boolean {\n return this.coefficients[0] === 0;\n }\n\n /** The coefficient of `x^degree`. */\n coefficientAt(degree: number): number {\n return this.coefficients[this.coefficients.length - 1 - degree] ?? 0;\n }\n\n /**\n * Evaluate at `x`, by Horner's method.\n *\n * Horner rather than summing `c * x^i` term by term: it needs one multiply\n * and one add per coefficient instead of a running power, and this is the\n * innermost loop of syndrome calculation.\n */\n evaluateAt(x: number): number {\n if (x === 0) return this.coefficientAt(0);\n\n let result = this.coefficients[0];\n for (let i = 1; i < this.coefficients.length; i++) {\n result = add(multiply(result, x), this.coefficients[i]);\n }\n return result;\n }\n\n /**\n * Add another polynomial.\n *\n * Also subtraction: the field has characteristic 2, so `a + b` and `a - b`\n * are the same operation.\n */\n add(other: Polynomial): Polynomial {\n if (this.isZero) return other;\n if (other.isZero) return this;\n\n const [shorter, longer] =\n this.coefficients.length > other.coefficients.length\n ? [other.coefficients, this.coefficients]\n : [this.coefficients, other.coefficients];\n\n const difference = longer.length - shorter.length;\n const sum = longer.slice(0, difference);\n for (let i = difference; i < longer.length; i++) {\n sum.push(add(shorter[i - difference], longer[i]));\n }\n return new Polynomial(sum);\n }\n\n /** Multiply by another polynomial. */\n multiply(other: Polynomial): Polynomial {\n if (this.isZero || other.isZero) return Polynomial.zero();\n\n const a = this.coefficients;\n const b = other.coefficients;\n const product = Array.from<number>({\n length: a.length + b.length - 1\n }).fill(0);\n\n for (let i = 0; i < a.length; i++) {\n for (let j = 0; j < b.length; j++) {\n product[i + j] = add(product[i + j], multiply(a[i], b[j]));\n }\n }\n return new Polynomial(product);\n }\n\n /** Multiply every coefficient by a scalar. */\n multiplyScalar(scalar: number): Polynomial {\n if (scalar === 0) return Polynomial.zero();\n if (scalar === 1) return this;\n\n return new Polynomial(this.coefficients.map((c) => multiply(c, scalar)));\n }\n\n /** Multiply by `coefficient * x^degree`. */\n multiplyMonomial(degree: number, coefficient: number): Polynomial {\n if (degree < 0) throw new Error(`Monomial degree must not be negative`);\n if (coefficient === 0) return Polynomial.zero();\n\n return new Polynomial([\n ...this.coefficients.map((c) => multiply(c, coefficient)),\n ...Array.from<number>({ length: degree }).fill(0)\n ]);\n }\n\n /**\n * Divide by `other`, returning quotient and remainder.\n *\n * Long division, one term at a time. Needed by the Euclidean algorithm that\n * solves for the error locator polynomial.\n */\n divide(other: Polynomial): { quotient: Polynomial; remainder: Polynomial } {\n if (other.isZero) throw new Error(`Polynomial division by zero`);\n\n let quotient = Polynomial.zero();\n // Seeded from a copy rather than `this` so the loop reassigns a plain\n // local: the accumulator is what changes each round, not the receiver.\n let remainder = new Polynomial(this.coefficients);\n\n const denominatorLeading = other.coefficientAt(other.degree);\n const inverseLeading = divide(1, denominatorLeading);\n\n while (remainder.degree >= other.degree && !remainder.isZero) {\n const degreeDifference = remainder.degree - other.degree;\n const scale = multiply(\n remainder.coefficientAt(remainder.degree),\n inverseLeading\n );\n\n quotient = quotient.add(Polynomial.monomial(degreeDifference, scale));\n remainder = remainder.add(\n other.multiplyMonomial(degreeDifference, scale)\n );\n }\n\n return { quotient, remainder };\n }\n}\n","/**\n * Reed-Solomon error correction.\n *\n * This is what makes a QR readable when part of it is scratched, glared out,\n * or covered by a logo. The encoder appends check codewords chosen so that the\n * whole block, read as a polynomial, evaluates to zero at a known set of\n * points. If any evaluation comes back non-zero, something changed in transit.\n *\n * The decode runs in four steps, each answering one question:\n *\n * 1. **Syndromes** — did anything change? (evaluate at the known points)\n * 2. **Euclidean algorithm** — where and by how much, jointly? (solve for the\n * error locator and evaluator)\n * 3. **Chien search** — which positions? (find the locator roots)\n * 4. **Forney** — what were those codewords originally? (magnitudes)\n *\n * A block with `n` check codewords corrects `n / 2` errors. Past that the\n * algebra still produces an answer — the wrong one — so a successful return\n * means \"repaired if repairable\", and the layers above verify their own\n * results independently rather than trusting this one.\n */\n\nimport { add, exp, inverse, multiply } from \"./galois.js\";\nimport { Polynomial } from \"./polynomial.js\";\n\n/** Raised when a block is damaged beyond what its check codewords can repair. */\nexport class ReedSolomonError extends Error {\n constructor(message: string) {\n super(message);\n this.name = `ReedSolomonError`;\n }\n}\n\n/**\n * Evaluate the received block at each of the `errorCodewordCount` points.\n *\n * All zero means the block is intact. Anything else encodes where the damage\n * is, in a form the Euclidean step can solve.\n */\nconst syndromes = (\n received: Polynomial,\n errorCodewordCount: number\n): { values: number[]; hasError: boolean } => {\n const values: number[] = [];\n let hasError = false;\n\n for (let i = 0; i < errorCodewordCount; i++) {\n const value = received.evaluateAt(exp(i));\n values.push(value);\n if (value !== 0) hasError = true;\n }\n\n // Collected lowest-power first but consumed as polynomial coefficients,\n // which this codebase stores highest-degree first.\n values.reverse();\n return { values, hasError };\n};\n\n/**\n * Run the extended Euclidean algorithm until the remainder is short enough.\n *\n * Solves for the error locator (sigma) and evaluator (omega) together.\n * Stopping early — once the remainder degree falls below half the check\n * codeword count — is what separates this from an ordinary GCD: that point is\n * exactly where the pair describes the errors.\n */\nconst euclidean = (\n a: Polynomial,\n b: Polynomial,\n limit: number,\n /**\n * Degree at which to stop, when erasures raise it above the usual half.\n *\n * With `e` erasures the algorithm may run until the remainder degree falls\n * below `(limit + e) / 2` rather than `limit / 2` — and that extra room is\n * precisely where the additional correction capacity comes from.\n */\n stopDegree = Math.floor(limit / 2)\n): { locator: Polynomial; evaluator: Polynomial } => {\n let rLast = a;\n let r = b;\n let tLast = Polynomial.zero();\n let t = new Polynomial([1]);\n\n while (r.degree >= stopDegree) {\n const rLastLast = rLast;\n const tLastLast = tLast;\n rLast = r;\n tLast = t;\n\n if (rLast.isZero) {\n throw new ReedSolomonError(\n `Remainder vanished before the locator was solved`\n );\n }\n\n // One division, both outputs: the quotient drives the locator recurrence\n // and the remainder drives the evaluator. Calling divide twice would\n // double the cost of the hot loop for nothing.\n const { quotient, remainder } = rLastLast.divide(rLast);\n r = remainder;\n t = quotient.multiply(tLast).add(tLastLast);\n\n if (r.degree >= rLast.degree) {\n throw new ReedSolomonError(`Euclidean algorithm failed to converge`);\n }\n }\n\n const constantTerm = t.coefficientAt(0);\n if (constantTerm === 0) {\n throw new ReedSolomonError(`Error locator has no constant term`);\n }\n\n // Both scaled so the locator constant term is 1, which is what the Forney\n // step below assumes.\n const scale = inverse(constantTerm);\n return {\n locator: t.multiplyScalar(scale),\n evaluator: r.multiplyScalar(scale)\n };\n};\n\n/**\n * Find error positions by testing every field element — the Chien search.\n *\n * Exhaustive on purpose: the field has 255 non-zero elements, so this is\n * cheaper than anything clever, and closed forms exist only for degree 1 and 2.\n */\nconst errorPositions = (locator: Polynomial): number[] => {\n const count = locator.degree;\n if (count === 1) return [locator.coefficientAt(1)];\n\n const positions: number[] = [];\n for (let i = 1; i < 256 && positions.length < count; i++) {\n if (locator.evaluateAt(i) === 0) positions.push(inverse(i));\n }\n\n if (positions.length !== count) {\n throw new ReedSolomonError(\n `Locator degree ${count} but found ${positions.length} roots`\n );\n }\n return positions;\n};\n\n/**\n * Compute how much each damaged codeword changed — the Forney algorithm.\n *\n * The denominator is the formal derivative of the locator evaluated at the\n * position. Computing it as a product over the *other* roots avoids\n * differentiating explicitly, and sidesteps the trap that in GF(2^k) every\n * even-power term differentiates away, because its coefficient is added to\n * itself.\n */\nconst errorMagnitudes = (\n evaluator: Polynomial,\n positions: readonly number[]\n): number[] =>\n positions.map((position, i) => {\n const positionInverse = inverse(position);\n\n let denominator = 1;\n for (let j = 0; j < positions.length; j++) {\n if (i === j) continue;\n // `add` is XOR: the field has characteristic 2, so this is the ordinary\n // (1 - x) of the Forney formulation.\n denominator = multiply(\n denominator,\n add(1, multiply(positions[j], positionInverse))\n );\n }\n\n if (denominator === 0) {\n throw new ReedSolomonError(`Forney denominator vanished`);\n }\n\n return multiply(\n evaluator.evaluateAt(positionInverse),\n inverse(denominator)\n );\n });\n\n/**\n * Keep only the lowest `count` degrees of a polynomial.\n *\n * Coefficients are stored highest-degree first, so the low-order terms are the\n * TAIL of the array. Both the Forney syndrome and the errata evaluator are\n * defined modulo `x^count`, and taking the wrong end here yields a polynomial\n * that is the right length and entirely wrong.\n */\nconst truncate = (poly: Polynomial, count: number): Polynomial => {\n const { coefficients } = poly;\n if (coefficients.length <= count) return poly;\n return new Polynomial(coefficients.slice(coefficients.length - count));\n};\n\n/** Discrete logarithm by search. Only reached on the error path. */\nconst logOf = (value: number): number => {\n for (let i = 0; i < 255; i++) if (exp(i) === value) return i;\n throw new ReedSolomonError(`Value ${value} is not a field element`);\n};\n\n/**\n * Repair a block, returning the corrected data codewords.\n *\n * `received` is data codewords followed by error-correction codewords; the\n * return is the data portion alone, since the check codewords have done their\n * job by this point.\n */\nexport const decode = (\n received: readonly number[],\n errorCodewordCount: number,\n /**\n * Indices of codewords already known to be unreadable.\n *\n * An **erasure** — damage whose position is known but whose value is not.\n * The distinction is worth real capacity: the bound is\n * `2 * errors + erasures <= errorCodewordCount`, so a codeword costs two\n * check symbols when the decoder has to find it and only one when it is\n * told where to look. With 10 check codewords that is 5 unknown errors\n * against 10 known erasures.\n *\n * The imaging layer can often tell: a region blown out by glare or crushed\n * to black by shadow is visibly untrustworthy, and thresholding it into a\n * confident bit throws that knowledge away. Indices are into `received`.\n */\n erasures: readonly number[] = []\n): number[] => {\n const dataLength = received.length - errorCodewordCount;\n if (dataLength <= 0) {\n throw new ReedSolomonError(`Block is shorter than its error correction`);\n }\n\n const poly = new Polynomial([...received]);\n const { values, hasError } = syndromes(poly, errorCodewordCount);\n\n // Intact block — overwhelmingly the common case, and worth not paying for.\n // Erasures do not change this: if every syndrome is zero the block is\n // already correct, whatever the imaging layer suspected.\n if (!hasError) return received.slice(0, dataLength);\n\n // Erasure positions as field elements. A codeword's index is counted from\n // the END of the block, matching the correction step below.\n const erasureRoots = [\n ...new Set(erasures.filter((i) => i >= 0 && i < received.length))\n ].map((index) => exp(received.length - 1 - index));\n\n if (erasureRoots.length > errorCodewordCount) {\n throw new ReedSolomonError(\n `${erasureRoots.length} erasures exceed ${errorCodewordCount} check codewords`\n );\n }\n\n // The erasure locator, whose roots are the known positions:\n // Lambda(x) = product of (1 - root * x).\n let erasureLocator = new Polynomial([1]);\n for (const root of erasureRoots) {\n erasureLocator = erasureLocator.multiply(new Polynomial([root, 1]));\n }\n\n // The Forney syndrome: the syndrome polynomial with the known erasures\n // folded in, truncated back to the check-codeword count. Feeding this to\n // the Euclidean algorithm in place of the raw syndrome is what lets one\n // pass solve for erasures and errors together.\n const syndromePoly = new Polynomial(values);\n const forney =\n erasureRoots.length === 0\n ? syndromePoly\n : truncate(syndromePoly.multiply(erasureLocator), errorCodewordCount);\n\n const { locator, evaluator } = euclidean(\n Polynomial.monomial(errorCodewordCount, 1),\n forney,\n errorCodewordCount,\n // Erasures buy exactly this: each one raises the degree the remainder may\n // stop at, and so the number of unknown errors solvable alongside them.\n Math.floor((errorCodewordCount + erasureRoots.length) / 2)\n );\n\n // The errata locator covers both kinds of damage at once.\n const errata =\n erasureRoots.length === 0 ? locator : locator.multiply(erasureLocator);\n\n const positions = errorPositions(errata);\n const magnitudes = errorMagnitudes(\n erasureRoots.length === 0\n ? evaluator\n : truncate(new Polynomial(values).multiply(errata), errorCodewordCount),\n positions\n );\n\n const corrected = [...received];\n for (const [i, position] of positions.entries()) {\n // Positions are field elements; the codeword index is their logarithm,\n // counted from the end of the block.\n const index = corrected.length - 1 - logOf(position);\n if (index < 0 || index >= corrected.length) {\n throw new ReedSolomonError(`Corrected position ${index} is out of range`);\n }\n corrected[index] = add(corrected[index], magnitudes[i]);\n }\n\n return corrected.slice(0, dataLength);\n};\n\n/**\n * The generator polynomial for `count` error-correction codewords.\n *\n * Exported because the tests need it: proving the decoder repairs damage means\n * being able to produce correctly-encoded blocks to damage.\n */\nexport const generatorPolynomial = (count: number): Polynomial => {\n let generator = new Polynomial([1]);\n for (let i = 0; i < count; i++) {\n generator = generator.multiply(new Polynomial([1, exp(i)]));\n }\n return generator;\n};\n\n/** Encode data codewords, appending `count` check codewords. */\nexport const encode = (data: readonly number[], count: number): number[] => {\n const generator = generatorPolynomial(count);\n const info = new Polynomial([...data]).multiplyMonomial(count, 1);\n const { remainder } = info.divide(generator);\n\n // The remainder can be shorter than `count` when its leading coefficients\n // are zero. Those zeroes are significant here and have to be restored.\n const check = remainder.coefficients;\n const padding = Math.max(0, count - check.length);\n return [\n ...data,\n ...Array.from<number>({ length: padding }).fill(0),\n ...check\n ];\n};\n","/**\n * Matrix to text — the whole of stage 1, assembled.\n *\n * Everything above this point is pure: given a bit matrix, this produces the\n * string that was encoded, with no pixels, cameras, or DOM involved. That is\n * what makes it exhaustively testable against etiket, which encodes the same\n * matrices this reads.\n */\n\nimport type { BitMatrix } from \"../types.js\";\nimport {\n bitsToCodewords,\n blockStructure,\n deinterleave,\n interleaveMap\n} from \"./blocks.js\";\nimport { readBitstream } from \"./bitstream.js\";\nimport {\n readFormat,\n readVersion,\n type ErrorCorrectionLevel\n} from \"./format.js\";\nimport { dataBitOrigins, readDataBits } from \"./mask.js\";\nimport { decode as correctBlock, ReedSolomonError } from \"./reed-solomon.js\";\n\n/** What a successful matrix decode yields. */\nexport interface MatrixDecodeResult {\n readonly value: string;\n readonly version: number;\n readonly errorCorrectionLevel: ErrorCorrectionLevel;\n readonly mask: number;\n}\n\n/**\n * Decode a bit matrix into the text it encodes.\n *\n * Returns `null` for anything unreadable. Every failure here is a normal\n * outcome rather than an exception: a camera sees far more non-symbols than\n * symbols, and a decoder that threw on each one would make its callers write\n * try/catch around their hot loop.\n */\nexport const decodeMatrix = (\n matrix: BitMatrix,\n /**\n * Modules the imaging layer could not read confidently, as a mask the same\n * shape as `matrix` where 1 marks \"do not trust this\".\n *\n * Reed-Solomon corrects twice as many codewords when it is told WHERE the\n * damage is: the bound is `2 * errors + erasures <= check codewords`. A\n * region blown out by glare or crushed by shadow is visibly untrustworthy,\n * and thresholding it into a confident bit throws that away. Measured on a\n * version 3 symbol at ecM, a blob covering 15% of the area decodes 0% of the\n * time as errors and 100% as erasures.\n *\n * Optional because it costs a per-frame allocation the ordinary path does\n * not need, and because a decoder handed no mask must behave exactly as it\n * did before.\n */\n unreliable?: Uint8Array\n): MatrixDecodeResult | null => {\n const version = readVersion(matrix);\n if (version === null) return null;\n\n const format = readFormat(matrix);\n if (format === null) return null;\n\n const structure = blockStructure(version, format.errorCorrectionLevel);\n if (structure === null) return null;\n\n // Unmasked as it is read, since the traversal and the mask have to agree\n // about coordinates.\n const bits = readDataBits(matrix, version, format.mask);\n const codewords = bitsToCodewords(bits);\n\n const blocks = deinterleave(codewords, structure);\n\n // Follow the untrusted modules through the same traversal the data took:\n // module -> bit -> codeword -> block. Interleaving scatters a contiguous\n // image blob across blocks, which is what stops any one block from\n // absorbing all of it, so this replays that scattering rather than assuming\n // damage stays together.\n const erasures = blocks.map((): number[] => []);\n if (unreliable !== undefined) {\n const origins = dataBitOrigins(matrix.width, version);\n const damagedCodewords = new Set<number>();\n\n for (const [bit, [x, y]] of origins.entries()) {\n if (unreliable[y * matrix.width + x] === 1) {\n damagedCodewords.add(Math.floor(bit / 8));\n }\n }\n\n const layout = interleaveMap(structure);\n for (const codeword of damagedCodewords) {\n const slot = layout[codeword];\n if (slot !== undefined) erasures[slot[0]].push(slot[1]);\n }\n }\n\n // Each block is repaired independently — that is the entire point of the\n // interleaving this just undid.\n const repaired: number[] = [];\n for (const [index, block] of blocks.entries()) {\n try {\n repaired.push(\n ...correctBlock(\n [...block.data, ...block.error],\n structure.errorCodewordsPerBlock,\n erasures[index]\n )\n );\n } catch (error) {\n // One block beyond repair loses the symbol. Reported as an unreadable\n // frame rather than an exception, for the reason above.\n if (error instanceof ReedSolomonError) return null;\n throw error;\n }\n }\n\n // Back to a bit array for the segment reader. The codewords are bytes, so\n // this is a plain unpack.\n const dataBits = new Uint8Array(repaired.length * 8);\n for (const [index, codeword] of repaired.entries()) {\n for (let bit = 0; bit < 8; bit++) {\n dataBits[index * 8 + bit] = (codeword >> (7 - bit)) & 1;\n }\n }\n\n const value = readBitstream(dataBits, version);\n if (value === null) return null;\n\n return {\n value,\n version,\n errorCorrectionLevel: format.errorCorrectionLevel,\n mask: format.mask\n };\n};\n","/**\n * The QR decoder — pixels in, text out.\n *\n * Assembles the stages: binarize, locate the finders, orient them, estimate\n * the size, correct perspective, sample the grid, then hand the matrix to the\n * pure decoder that stage 1 proved correct.\n *\n * Both polarities are tried by default. That is not defensive coding: a symbol\n * rendered light-on-dark is invisible to a decoder that assumes the opposite,\n * and it fails as silence rather than as an error — camera running, frames\n * arriving, nothing ever decoding. Trying both costs one extra pass and\n * removes an entire class of unexplainable failure.\n */\n\nimport {\n binarize,\n binarizeGlobal,\n blur,\n close,\n downscale,\n upscale,\n binarizeAt,\n crop,\n closeGray,\n invertMatrix\n} from \"../binarize.js\";\nimport type {\n BitMatrix,\n DecodedSymbol,\n GrayImage,\n SymbolDecoder\n} from \"../types.js\";\nimport {\n alignmentCentersFor,\n estimateCornerFromEdges,\n locateAlignmentGrid,\n refineBottomRight\n} from \"./alignment.js\";\nimport { decodeMatrix } from \"./decode-matrix.js\";\nimport {\n findFinderBlobs,\n findFinderPatterns,\n orientFinders,\n selectBestTriple,\n type FinderTriple\n} from \"./locate.js\";\nimport {\n applyTransform,\n estimateBottomRight,\n estimateSize,\n rectifySymbol,\n unreadableModules,\n refineTransform,\n samplePiecewise,\n searchCorner,\n sampleGrid,\n transformForSymbol,\n transformFromOutlines,\n sizeFromTimingPattern\n} from \"./sample.js\";\n\n/** Options for {@link createQrDecoder}. */\nexport interface QrDecoderOptions {\n /**\n * Which polarities to attempt.\n *\n * `both` by default. `dark-on-light` is the conventional rendering and is\n * marginally faster; choose it only when you control every symbol the\n * scanner will ever see.\n */\n polarity?: `both` | `dark-on-light` | `light-on-dark`;\n\n /**\n * Milliseconds to spend before giving up, or `0` for no limit.\n *\n * The retry ladder is what reads difficult images, and it is priced for a\n * still photograph rather than a viewfinder. Measured on 1024x768 frames, a\n * symbol that decodes costs 12 to 32ms while one that cannot be read at all\n * costs 570 to 700 — roughly 25 times more, and the early exit cannot help\n * because a finder pattern genuinely is present.\n *\n * That asymmetry is backwards for a camera: the expensive case happens\n * exactly when someone is holding the phone at a bad angle and moving it, so\n * a scanner that reads 43% of stills would stutter at under two frames a\n * second precisely when the user is trying to line up a shot. The next frame\n * is nearly free and probably better, so spending 700ms on this one is a bad\n * trade in a live loop and a good one for a single still.\n *\n * Defaults to 120ms, which fits comfortably inside a frame at 5 scans per\n * second. Set `0` when decoding a still image, where the whole ladder is\n * worth running.\n */\n timeBudgetMs?: number;\n\n /**\n * Retry with a low-pass filter when the sharp pass finds nothing.\n *\n * On by default, and it is what makes a code on a SCREEN readable: moire\n * banding is frequency aliasing between the camera sensor and the display's\n * sub-pixel grid, so it sits at a higher spatial frequency than the modules\n * and blurs away while they survive. Measured on the benchmark corpus this\n * takes the `monitor` category from 0 of 25 to 10 of 25 — and since this\n * library's own device screen is scanned off a TV, that is not a niche case.\n *\n * A retry rather than a default pass, because the same filter destroys\n * already-blurry photographs: `blurred` drops from 5 of 14 to 1, `nominal`\n * from 3 to 0. Costs nothing on images that decode sharp.\n */\n retryBlurred?: boolean;\n}\n\n/** Try to decode one binarized image. */\n/**\n * Largest frame worth enlarging, in pixels.\n *\n * Enlarging costs four times the pixel count, and every stage after it pays\n * that. Two megapixels is the point past which a symbol is very unlikely to be\n * small enough in frame to need it while the pass still costs the most.\n */\nconst UPSCALE_LIMIT = 2_000_000;\n\n/**\n * Candidate count past which a frame is treated as grain for the deep search.\n *\n * Sixty: no corpus image below that count needs the deep search to decode,\n * and every image above it that decodes does so on a cheaper rung. See the\n * gate in `decodeBinarized`.\n */\nconst NOISE_CANDIDATES = 60;\n\n/**\n * Transform pairs, for frames whose faults are independent.\n *\n * See the rung in `decode` for why composition is needed at all and why the\n * order within each pair is what it is.\n */\nconst COMPOSED: ReadonlyArray<(image: GrayImage, radius: number) => GrayImage> =\n [\n // Ordered by measured yield: 5 images, then 3 and 3. The tail pair costs\n // about 15s per image against the first's 2s, and is kept because a time\n // budget clips all of this on a live frame — only a still pays for it.\n (image, radius) => blur(downscale(image, 2), radius),\n (image, radius) => blur(upscale(image, 2), radius),\n (image) => downscale(downscale(image, 2), 2)\n ];\n\n/**\n * Binarization passes, cheapest-per-recovery first.\n *\n * `[denoise, global]`. See the loop in `attempt` for the measurements behind\n * the order.\n */\nconst PASSES: ReadonlyArray<readonly [boolean, boolean]> = [\n [false, false],\n [false, true],\n [true, false],\n [true, true]\n];\n\n/**\n * Fixed thresholds to try when every adaptive choice has failed.\n *\n * Spread across the range rather than concentrated, because the thresholds\n * that rescue an image are themselves spread across it — see\n * {@link binarizeAt}. Twenty apart: closer measured no better, and each step\n * costs a full pass.\n */\nconst THRESHOLD_SWEEP = [60, 80, 100, 120, 140, 160, 180, 200] as const;\n\n/**\n * Candidate symbol regions in a frame, largest-looking first.\n *\n * One region per finder triple, not one box around every candidate. A frame\n * may hold several codes, and boxing their finders together produces a region\n * belonging to no symbol — measured on the `lots` category, that box spans a\n * median 62% of the frame where a single symbol's spans effectively none.\n *\n * Falls back to the whole frame when no triple can be assembled, so a caller\n * always has something to work on.\n */\nconst symbolRegions = (\n image: GrayImage,\n finders: FinderTriple | null\n): GrayImage[] => {\n if (finders === null) return [image];\n\n const corners = [finders.topLeft, finders.topRight, finders.bottomLeft];\n const xs = corners.map((pattern) => pattern.center.x);\n const ys = corners.map((pattern) => pattern.center.y);\n const left = Math.min(...xs);\n const top = Math.min(...ys);\n const width = Math.max(...xs) - left;\n const height = Math.max(...ys) - top;\n\n // The triple spans finder CENTRES, so the symbol extends about 3.5 modules\n // past them on every side; padding by a third of the span covers that with\n // room for the quiet zone.\n const padX = Math.max(8, width / 3);\n const padY = Math.max(8, height / 3);\n\n const region = crop(\n image,\n left - padX,\n top - padY,\n width + padX * 2,\n height + padY * 2\n );\n\n // Only worth it if the crop is actually smaller; a symbol filling the frame\n // gains nothing and a degenerate triple could produce something larger.\n return region.width * region.height < image.width * image.height * 0.9\n ? [region, image]\n : [image];\n};\n\nconst decodeBinarized = (\n image: GrayImage,\n invert: boolean,\n global = false,\n denoise = false,\n deepSearch = false,\n /** A prepared matrix, when the caller already has one for this pass. */\n prepared?: BitMatrix,\n /** Abandon expensive stages when this returns true. */\n exhausted?: () => boolean\n): DecodedSymbol | null => {\n const binarized =\n prepared ??\n (global ? binarizeGlobal(image, { invert }) : binarize(image, { invert }));\n const matrix = denoise ? close(binarized) : binarized;\n\n // Two detectors, pooled. Run-length scanning reads the 1:1:3:1:1 signature\n // and handles perspective well; blob detection reads the finder as a nested\n // shape and handles small modules well, where band widths of two or three\n // pixels destroy the ratio. Neither dominates, and candidates that are not\n // finders are rejected by scoring further down.\n const patterns = findFinderPatterns(matrix);\n\n // Scored rather than taking the first three. Across the benchmark corpus\n // the rotations, high_version and brightness categories return MORE than\n // three candidates on nearly every image, so an arbitrary three discards\n // the right answer and loses a symbol that was successfully found.\n // Scored rather than taking the first three. Across the benchmark corpus\n // the rotations, high_version and brightness categories return MORE than\n // three candidates on nearly every image, so an arbitrary three discards\n // the right answer and loses a symbol that was successfully found.\n //\n // Clearance filtering — dropping candidates with no quiet zone around them\n // — is deliberately NOT applied here. It works exactly as designed on large\n // symbols, cutting 13 candidates to 3 and choosing all three real finders,\n // but measured 51.5% to 51.3% because a symbol shot against a dark edge has\n // a poor clearance score legitimately. `withClearance` remains exported for\n // callers who know their symbols have clean quiet zones.\n let triple = patterns.length >= 3 ? selectBestTriple(patterns) : null;\n\n // Fall back to shape-based detection, POOLED with whatever the scan found.\n //\n // Scoring the two detectors separately was tried on the theory that their\n // module-size estimates are incommensurable — one derived from run lengths,\n // one from a bounding box — and measured slightly worse (39.3% against\n // 39.4%). Pooling lets a triple mix a confidently-scanned finder with a\n // blob-detected one, which is often exactly the right answer.\n //\n // Only attempted when the scan is short of a full triple but found at least\n // one candidate: that means a symbol is probably present and being read\n // badly, rather than absent. Flooding every dark region costs 372ms on a\n // 12-megapixel frame, so it must not run speculatively.\n if (triple === null && patterns.length > 0 && patterns.length < 3) {\n const blobs = findFinderBlobs(matrix);\n if (blobs.length > 0) triple = selectBestTriple([...patterns, ...blobs]);\n }\n\n // Last resort: re-scan tolerating an outer run merged with adjacent content.\n //\n // A symbol printed without its quiet zone puts a dark element against the\n // finder's outer ring, so the leading or trailing dark run grows without\n // bound and the 1:1:3:1:1 test fails on runs that are otherwise perfect.\n // Measuring the module from the interior instead recovers those.\n //\n // Guarded the same way as the blob fallback, and for a stronger reason: as\n // the only rule it roughly triples the candidate rows, which took the corpus\n // from 70.2% to 64.5% — `high_version` to zero — and made the benchmark five\n // times slower. Behind a \"found something, but not three\" guard it costs\n // nothing on symbols whose quiet zone is intact.\n if (triple === null && patterns.length > 0) {\n const merged = findFinderPatterns(matrix, true);\n if (merged.length >= 3) triple = selectBestTriple(merged);\n }\n\n if (triple === null) return null;\n\n const finders = orientFinders(triple);\n if (finders === null) return null;\n\n // Size from the finder spans, and the timing pattern as a second opinion.\n //\n // `estimateSize` divides the finder span by the module size, so an error in\n // the module size is multiplied by the module count. Under foreshortening\n // the near arm measures wider than the far one and the quotient lands on the\n // wrong multiple of four — or outside the legal range, which used to abort\n // the decode outright on 7 of the remaining `perspective` failures.\n const measured = sizeFromTimingPattern(matrix, finders);\n let size = estimateSize(finders) ?? measured;\n if (size === null) return null;\n\n // First pass: assume the symbol is a parallelogram. Good enough to predict\n // roughly where the alignment pattern should be.\n const estimated = estimateBottomRight(finders);\n const rough = transformForSymbol(finders, size, estimated);\n\n const version = (size - 17) / 4;\n\n // Second pass: pin the fourth corner with the alignment pattern, when one\n // is findable. Three finders fix three corners; the fourth is the one the\n // perspective error accumulates towards, and on a 117-module symbol a one\n // percent error there is more than a module of drift — every module in that\n // region samples its neighbour. It is why `high_version` images locate\n // perfectly and decode not at all.\n const moduleSize =\n (finders.topLeft.moduleSize +\n finders.topRight.moduleSize +\n finders.bottomLeft.moduleSize) /\n 3;\n\n // Three candidates for the fourth corner, tried in order of how much they\n // are trusted. Measured against a reference decoder, this one point is the\n // largest error in the pipeline: supplying a correct corner takes\n // `perspective` from 2 of 23 images to 7, `glare` from 2 of 17 to 7, and\n // `curved` from 18 of 36 to 27.\n //\n // Trying several rather than picking one is cheap — each attempt is a\n // sample and a decode, and a wrong grid fails fast at the format check —\n // and no single method wins everywhere: the alignment pattern is exact when\n // present and absent on small or damaged symbols, edge-following handles\n // perspective but needs a clean quiet zone, and the parallelogram is a poor\n // estimate that never fails outright.\n const candidates = [\n refineBottomRight(matrix, rough, finders, size, version, estimated),\n estimateCornerFromEdges(matrix, finders, moduleSize, estimated),\n estimated\n ];\n\n let transform = rough;\n let sampled = sampleGrid(matrix, rough, size);\n let decoded = sampled === null ? null : decodeMatrix(sampled);\n\n // Before searching for a corner, try measuring one instead.\n //\n // The transform above is fitted to three finder CENTRES plus an estimated\n // fourth corner, so a guess is present in every sample it takes. Each\n // finder's outer square is 7 modules on a side at a known position, so\n // tracing its outline gives four measured points per finder and twelve in\n // total — an over-determined fit with no estimate in it.\n //\n // Measured on the corpus with flat sampling alone, twelve points read\n // `perspective` 18 of 26 against four points' 4, `nominal` 60 of 109\n // against 38, and `glare` 9 of 31 against 3.\n if (decoded === null) {\n const candidates = [size, size - 4, size + 4];\n // Counting timing transitions does not divide by anything, so it survives\n // the foreshortening that defeats the span estimate. Tried after it rather\n // than instead of it: the span estimate is right far more often, and\n // sweeping scan lines to find the timing row is not free.\n if (measured !== null && !candidates.includes(measured)) {\n candidates.push(measured);\n }\n\n for (const candidateSize of candidates) {\n if (candidateSize < 21 || candidateSize > 177) continue;\n\n const fitted = transformFromOutlines(matrix, finders, candidateSize);\n if (fitted === null) break;\n\n const fittedGrid = sampleGrid(matrix, fitted, candidateSize);\n if (fittedGrid === null) continue;\n\n const fittedDecode = decodeMatrix(fittedGrid);\n if (fittedDecode !== null) {\n transform = fitted;\n sampled = fittedGrid;\n decoded = fittedDecode;\n size = candidateSize;\n break;\n }\n }\n }\n\n // Each corner is tried at the estimated size and its neighbours. Size comes\n // from finder spacing divided by module size, so an error in either lands\n // on the wrong multiple of four — and rotation is the clearest case:\n // between 43 and 47 degrees the module-size correction overshoots and the\n // estimate reads 33 where the truth is 29, while 29 decodes perfectly at\n // every one of those angles. Only the estimate was ever wrong.\n //\n // Nested rather than run as a separate pass because the two errors\n // interact: correcting the size while holding a wrong corner still does not\n // decode, so they have to vary together.\n const sizes = [size, size - 4, size + 4].filter(\n (candidate) => candidate >= 21 && candidate <= 177\n );\n\n for (const corner of candidates) {\n if (decoded !== null) break;\n\n for (const candidateSize of sizes) {\n const candidateTransform = transformForSymbol(\n finders,\n candidateSize,\n corner\n );\n const candidateGrid = sampleGrid(\n matrix,\n candidateTransform,\n candidateSize\n );\n if (candidateGrid === null) continue;\n\n const candidateDecode = decodeMatrix(candidateGrid);\n if (candidateDecode !== null) {\n transform = candidateTransform;\n sampled = candidateGrid;\n decoded = candidateDecode;\n size = candidateSize;\n break;\n }\n }\n }\n\n if (sampled === null) return null;\n\n // Still nothing. Search for a better transform rather than computing one.\n //\n // Repeatedly across this corpus, symbols located correctly to within a\n // module still failed to decode, and no single corner estimate fixed them —\n // a brute-force corner search recovered only 4 of 15 perspective images.\n // The missing piece was never a better formula but a way to tell \"better\"\n // from \"worse\" without knowing the answer, which `scoreTransform` supplies:\n // a QR's finders, timing lines and alignment patterns sit at positions the\n // standard fixes, so a transform can be graded by whether sampling those\n // positions finds them.\n if (decoded === null) {\n const refined = refineTransform(\n matrix,\n transform,\n size,\n alignmentCentersFor(version)\n );\n const refinedGrid = sampleGrid(matrix, refined, size);\n if (refinedGrid !== null) {\n const refinedDecode = decodeMatrix(refinedGrid);\n if (refinedDecode !== null) {\n transform = refined;\n sampled = refinedGrid;\n decoded = refinedDecode;\n }\n }\n }\n\n // Still nothing. Search the fourth corner by fitness rather than deriving\n // it. Every geometric derivation has fallen short here, while supplying a\n // known-good corner takes `perspective` from 2 of 23 images to 7 — so the\n // information is recoverable but not computable, which makes it a search.\n //\n // Gated on `deepSearch`, because it is by far the most expensive stage in\n // the decoder: 625 candidate transforms scored against refinement's 80. Run\n // unconditionally it starves the cheaper retry rungs above it of their time\n // budget, which measured as `close` collapsing from 9 of 14 to 0 — the\n // search itself is valuable, but not at the price of everything after it.\n // Skipped when the frame produced implausibly many candidates.\n //\n // Sensor grain generates spurious 1:1:3:1:1 runs everywhere: a noisy\n // 1280x720 frame yields 181-193 finder candidates against 0-5 for an\n // ordinary photograph, and the ladder then grades transforms against noise\n // that can never decode — `scoreTransform` alone takes 40% of CPU on such a\n // frame, and the frame costs seconds.\n //\n // Rejecting the frame outright is not safe: 10 real corpus images exceed 100\n // candidates, `monitor/image003` reaches 333, and the whole `lots` category\n // (several codes in one frame, read 100%) sits at 182-188 by design. But\n // every one of those decodes on the cheap path — 7 of 7 in `lots`, 4 of 4 in\n // `monitor` — because they hold real symbols. Only the expensive search is\n // wasted on grain, so only the expensive search is skipped.\n if (decoded === null && deepSearch && patterns.length <= NOISE_CANDIDATES) {\n // Searched at each plausible size, not just the estimated one. Measured\n // on the `perspective` category, supplying a known-good corner takes it\n // from 4 of 23 images to 8, and a corner WITH a size sweep to 10 — so the\n // two errors interact here exactly as they do under rotation, and\n // correcting either alone leaves images on the table.\n for (const candidateSize of sizes) {\n if (decoded !== null) break;\n\n if (exhausted?.() === true) break;\n\n for (const candidate of searchCorner(\n matrix,\n finders,\n candidateSize,\n moduleSize,\n alignmentCentersFor((candidateSize - 17) / 4),\n estimated,\n exhausted\n )) {\n const candidateGrid = sampleGrid(matrix, candidate, candidateSize);\n if (candidateGrid === null) continue;\n\n const candidateDecode = decodeMatrix(candidateGrid);\n if (candidateDecode !== null) {\n transform = candidate;\n sampled = candidateGrid;\n decoded = candidateDecode;\n size = candidateSize;\n break;\n }\n }\n }\n }\n\n // Retry telling Reed-Solomon where the damage is.\n //\n // Placed as a retry rather than folded into the sampling above, because\n // building the mask costs a pass over every module and the overwhelming\n // majority of frames decode without it — this way a healthy symbol pays\n // nothing and only a damaged one pays at all.\n //\n // The capacity is real: `2 * errors + erasures <= check codewords`, so a\n // codeword the decoder is TOLD about costs one check symbol instead of two.\n // Measured against a synthetic blob on a version 3 symbol at ecM, 15% of the\n // area decodes 0% of the time as errors and 100% as erasures.\n if (decoded === null && sampled !== null) {\n const unreliable = unreadableModules(image, transform, size);\n // Only worth a second decode when something actually looks unreadable.\n if (unreliable.some((flag) => flag === 1)) {\n decoded = decodeMatrix(sampled, unreliable);\n }\n }\n\n // Flat sampling failed. On a large symbol that usually means the surface is\n // not flat: a page bows, and one homography models a plane. Measured on a\n // version 40 symbol with verifiably exact corners, interior alignment\n // patterns sat up to 1.09 modules from where the plane predicted — past\n // half a module, every sample lands on the wrong module.\n //\n // Alignment patterns are a grid of known points across the whole symbol, so\n // locating them measures the warp directly and each cell gets a transform\n // fitted to its own corners.\n // Version 2 and up, not 7 and up. The warp this corrects is a property of\n // the SURFACE, not of the symbol: measured on the `curved` category,\n // alignment patterns sit a median of 0.70 modules off the plane — past the\n // half-module threshold where sampling reads the wrong module — regardless\n // of version. Gating at 7 came from first diagnosing this on a version 40\n // symbol and assuming it was a large-symbol phenomenon.\n //\n // Every version from 2 carries at least one alignment pattern, which is\n // the minimum this needs.\n if (decoded === null && version >= 2) {\n const grid = locateAlignmentGrid(\n matrix,\n transform,\n size,\n version,\n moduleSize\n );\n\n if (grid !== null) {\n const warped = samplePiecewise(\n matrix,\n size,\n grid.anchors,\n grid.positions,\n transform\n );\n if (warped !== null) decoded = decodeMatrix(warped);\n }\n }\n\n if (decoded === null) return null;\n\n // Corners in image space, for callers that draw an overlay.\n const corners = [\n { x: 0, y: 0 },\n { x: 1, y: 0 },\n { x: 1, y: 1 },\n { x: 0, y: 1 }\n ].map((corner) => applyTransform(transform, corner.x, corner.y));\n\n return {\n value: decoded.value,\n format: `qr_code`,\n cornerPoints: corners\n };\n};\n\n/**\n * Create a QR decoder.\n *\n * The returned decoder is pure and synchronous: it holds no camera, no canvas,\n * and no DOM reference, which is what lets the same instance run on a worker,\n * a server, or in a test with no browser at all.\n */\nexport const createQrDecoder = ({\n polarity = `both`,\n retryBlurred = true,\n timeBudgetMs = 120\n}: QrDecoderOptions = {}): SymbolDecoder => {\n const attempt = (\n image: GrayImage,\n deepSearch = false,\n exhausted?: () => boolean\n ): DecodedSymbol | null => {\n // Local binarization first, then global. Neither dominates: local follows\n // a shadow across a page and is what makes unevenly-lit photographs\n // readable at all, while global is more faithful on a clean image because\n // local thresholding invents structure in flat regions. zxing-cpp reached\n // the same conclusion — its issue #809 is an image its local binarizer\n // cannot read and its global one can.\n // Local then global binarization; each pass optionally denoised. Denoising\n // is a morphological closing that fills light speckle inside dark regions\n // — zxing-cpp #951 diagnoses an undetected symbol as exactly that, \"white\n // pixels inside the black square that disrupt their detection\", since one\n // stray pixel splits a finder's dark run in two and breaks the 1:1:3:1:1\n // signature a human still sees perfectly well.\n //\n // Last in the ladder because it is the most destructive: closing erases\n // real detail as readily as noise, so it must only run once everything\n // gentler has failed.\n // Ordered by cost per ATTEMPT, which is not cost per recovery.\n //\n // Instrumented across a quarter of the corpus, the four combinations\n // recover 107 / 13 / 3 / 2 images at 646 / 4949 / 7729 / 15124 ms per\n // recovery — so plain/local is four fifths of every success at an eighth\n // the cost of the next best, and it must come first.\n //\n // But reordering the other three by that same measure — putting\n // denoise/local ahead of plain/global, which recovers four times as\n // cheaply per hit — cost the 120ms budgeted rate two images. Under a\n // budget what matters is what each attempt COSTS, not what it eventually\n // yields: a global binarization is 14ms against denoising's 35ms, so it\n // deserves the earlier slot even though it wins less often. Ranking by\n // yield spends the budget before the cheap pass gets its turn.\n for (const [denoise, global] of PASSES) {\n // The corner search runs only on the plainest binarization, not on\n // every combination. It costs about 48ms per candidate size and three\n // sizes are tried, so allowing it inside all four denoise/global\n // combinations across both polarities multiplied it eightfold — over\n // a second per preprocessing pass, and the ladder has several.\n //\n // A symbol that needs denoising AND a corner search was not going to\n // decode anyway: the search corrects geometry, and denoising is for\n // images whose modules are damaged, which is a different fault.\n const deep = deepSearch && !denoise && !global;\n\n // Binarized once per pass, then flipped for the second polarity.\n // Binarization is dominated by computing the adaptive threshold\n // surface, and inversion only changes the comparison against it, so\n // running it twice discards half that work on every rung.\n const upright = global ? binarizeGlobal(image) : binarize(image);\n\n if (polarity !== `light-on-dark`) {\n const normal = decodeBinarized(\n image,\n false,\n global,\n denoise,\n deep,\n upright,\n exhausted\n );\n if (normal !== null) return normal;\n }\n\n if (polarity !== `dark-on-light`) {\n const inverted = decodeBinarized(\n image,\n true,\n global,\n denoise,\n deep,\n invertMatrix(upright),\n exhausted\n );\n if (inverted !== null) return inverted;\n }\n }\n\n return null;\n };\n\n /**\n * Re-run with the binarizer's block grid shifted half a block.\n *\n * Local binarization divides the image into a fixed grid anchored at the\n * origin, so a symbol's position RELATIVE TO THAT GRID changes how it\n * binarizes — two photographs of the same code, differing only in framing,\n * can produce different modules. zxing-cpp hit this exactly: its issue #966\n * reports a symbol detected at one position and not another, and the\n * maintainer traced it to \"some arbitrary 8x8 grid related to the inner\n * workings of the binarization algorithm... just one pixel difference after\n * binarization\".\n *\n * Measured here, one in nine decodable images is sensitive to a few pixels\n * of translation. Offsetting the image by half a block moves every block\n * boundary onto different pixels, so a symbol that straddled one badly no\n * longer does.\n */\n /**\n * Locate the symbol and resample it square, or `null` if it cannot be found.\n *\n * The automatic form of Lightroom's Guided Upright: that tool needs a person\n * to draw guides because nothing in a photograph says what was straight,\n * while a QR tells us — its three finder centres sit at module coordinates\n * the specification fixes.\n */\n /**\n * Locate one symbol cheaply, for the stages that need to know where it is.\n *\n * Both the rectify rung and the crop before upscaling want the same thing —\n * a plausible triple — and each was binarizing and scanning independently.\n * This is the cheap \"is there a code, and roughly where\" pass those stages\n * share: one binarization and one finder scan, whose result then narrows\n * everything after it.\n *\n * Cached for the frame, since the rungs that use it run on the same image.\n */\n const locateOnce = (image: GrayImage): FinderTriple | null => {\n const cached = located.get(image);\n if (cached !== undefined) return cached;\n\n const patterns = findFinderPatterns(binarize(image));\n const triple = patterns.length >= 3 ? selectBestTriple(patterns) : null;\n const finders = triple === null ? null : orientFinders(triple);\n\n located.set(image, finders);\n return finders;\n };\n\n const located = new Map<GrayImage, FinderTriple | null>();\n\n const rectifyUpright = (image: GrayImage): GrayImage | null => {\n const finders = locateOnce(image);\n if (finders === null) return null;\n\n const size = estimateSize(finders);\n if (size === null) return null;\n\n return rectifySymbol(image, finders, size, 8);\n };\n\n const shifted = (image: GrayImage): GrayImage => {\n const offset = 4;\n const width = image.width - offset;\n const height = image.height - offset;\n if (width < 21 || height < 21) return image;\n\n const data = new Uint8ClampedArray(width * height);\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n data[y * width + x] =\n image.data[(y + offset) * image.width + x + offset]!;\n }\n }\n return { data, width, height };\n };\n\n return {\n decode: (image: GrayImage): DecodedSymbol | null => {\n // Measured from the first pass rather than before it, so a budget can\n // never prevent the cheapest attempt from running at all.\n const started = performance.now();\n const spent = (): boolean =>\n timeBudgetMs > 0 && performance.now() - started > timeBudgetMs;\n\n const sharp = attempt(image);\n if (sharp !== null) return sharp;\n\n // Bail before the expensive retries when the frame plainly holds no\n // symbol. A camera loop sees far more empty frames than codes, and the\n // full ladder costs about half a second on a 720p frame — enough to cap\n // a scanner at two frames a second scanning nothing at all.\n //\n // The test is deliberately weak: a single finder candidate anywhere, in\n // either polarity, is enough to justify the retries. Retrying exists\n // precisely to rescue symbols the first pass reads badly, so this must\n // only reject frames where there is nothing to rescue.\n //\n // Checked on the BLURRED image as well as the sharp one. Gating on the\n // sharp pass alone rejected 24 of 718 corpus images outright, two of\n // which a later pass decoded — concentrated in `damaged` and\n // `perspective`, exactly the categories where the first binarization\n // finds nothing and a retry rescues it. Blur is one cheap pass against\n // the whole ladder, so this keeps nearly all of the saving.\n const radius = Math.max(\n 2,\n Math.round(Math.min(image.width, image.height) / 500)\n );\n\n // Only the run-length scan, deliberately. Blob detection floods every\n // dark region and costs 372ms on a 12-megapixel frame; running it here\n // would spend that on frames containing nothing, which is the case this\n // exit exists to make cheap. A symbol that only the blob detector can\n // see is lost — an acceptable trade, since the run-length scan finds\n // SOMETHING in all but 24 of the 718 corpus images, and this gate needs\n // only one candidate anywhere to let the full ladder proceed.\n const hasCandidate = (candidate: GrayImage): boolean =>\n findFinderPatterns(binarize(candidate)).length > 0 ||\n findFinderPatterns(binarize(candidate, { invert: true })).length > 0;\n\n // Run on a downscaled copy when the frame is large enough to spare it.\n //\n // The gate exists to make an empty frame cheap, and on a 2.4MP frame it\n // had become more expensive than the rungs it protects: `hasCandidate`\n // does two binarizations and two finder scans, it is called twice, and\n // the blurred call pays 77ms for the blur alone — 64% of the 120ms\n // budget a viewfinder runs at, before a single retry.\n //\n // Halving each dimension quarters every one of those costs. A finder\n // large enough for the ladder to recover survives it: the gate only\n // needs to know whether ANY candidate exists anywhere, not to locate it\n // precisely.\n // A mip chain, built lazily and shared.\n //\n // The ladder asks for the same reductions more than once — the gate and\n // the downscale rung both want half size, and the blurred gate and the\n // blur rung both want the same radius at full size. Each was recomputed,\n // and on a 2.4MP frame a blur is 77ms and a halving 6ms.\n //\n // Levels are cached rather than precomputed because most frames never\n // reach the rungs that need them: an empty frame should pay for one\n // reduction, not a whole pyramid.\n const levels = new Map<number, GrayImage>([[1, image]]);\n const level = (factor: number): GrayImage => {\n const cached = levels.get(factor);\n if (cached !== undefined) return cached;\n const built = downscale(image, factor);\n levels.set(factor, built);\n return built;\n };\n\n const blurred = new Map<GrayImage, GrayImage>();\n const blurOf = (source: GrayImage, r: number): GrayImage => {\n const cached = blurred.get(source);\n if (cached !== undefined) return cached;\n const built = blur(source, r);\n blurred.set(source, built);\n return built;\n };\n\n const gateImage =\n Math.min(image.width, image.height) >= 600 ? level(2) : image;\n const gateRadius = Math.max(\n 2,\n Math.round(Math.min(gateImage.width, gateImage.height) / 500)\n );\n\n // The cheap check first, and full resolution only to overturn a\n // rejection. An empty frame — the common case, and the one this exists\n // for — pays only the quarter-size pass; a frame the small pass doubts\n // costs one more scan rather than losing a symbol, which downscaling\n // alone measured at one image.\n if (\n !hasCandidate(gateImage) &&\n !hasCandidate(blurOf(gateImage, gateRadius)) &&\n (gateImage === image ||\n (!hasCandidate(image) && !hasCandidate(blurOf(image, radius))))\n ) {\n return null;\n }\n\n // Rungs run cheapest first, so a time budget buys as many attempts as\n // it can before running out. Measured on a 1024x768 frame: downscale\n // 6ms, local binarize 16ms, global binarize 24ms, blur 28ms, denoise\n // 31ms. This was previously ordered by when each rung was written,\n // which put downscaling — the cheapest, and the one that took `close`\n // from 28.6% to 31.0% and `damaged` from 22.9% to 27.1% — last.\n //\n // Downscaling only helps an image large enough to spare the resolution.\n // The guard wraps the LOOP rather than returning, because every rung\n // after it is unrelated to image size; guarding with a return silently\n // skipped the deep search on small frames and cost `nominal` 10 of 14\n // images down to 4.\n if (Math.min(image.width, image.height) >= 600) {\n for (const factor of [2, 3]) {\n if (spent()) return null;\n const smaller = attempt(level(factor));\n if (smaller !== null) return smaller;\n }\n }\n\n // Rectify and re-read. A projective transform already corrects\n // perspective during sampling, so this is not about geometry — it is\n // about what the BINARIZER sees. In an oblique photograph a module at\n // the far edge is a fraction of the size it is near the camera, and one\n // block size cannot suit both: measured on `perspective`, images that\n // fail have a mean leg ratio of 1.58 and modules down to 2.4 pixels,\n // against 1.14 and 7.5 pixels for those that decode.\n //\n // Rectifying makes every module the same size, so binarization and\n // detection run on uniform data. Worth one image each on `perspective`,\n // `glare` and `damaged`.\n if (spent()) return null;\n const upright = rectifyUpright(image);\n if (upright !== null) {\n const rectified = attempt(upright);\n if (rectified !== null) return rectified;\n }\n\n // Ordered by MEASURED cost per image recovered, not by when each rung\n // was written or by the cost of its preprocessing step alone.\n //\n // Instrumenting every rung across a third of the corpus gives, in\n // milliseconds spent per image it alone recovered: sharp 364, downscale\n // x3 634, downscale x2 833, rectify 1534, shifted 4359, deep 6525,\n // sweep 6049, blur 12549, upscale 61205. The ladder had been ordered by\n // the cost of the transform each rung applies, which is a different\n // quantity — enlarging is one cheap pass, but every stage after it then\n // works on four times the pixels.\n //\n // Under a time budget the order IS a coverage decision: a rung that runs\n // early spends budget the rungs behind it would have converted at a\n // better rate.\n if (spent()) return null;\n const offset = attempt(shifted(image));\n if (offset !== null) return offset;\n\n if (spent()) return null;\n const deep = attempt(image, true, spent);\n if (deep !== null) return deep;\n\n if (spent()) return null;\n const softened = attempt(blurOf(image, radius));\n if (softened === null && !retryBlurred) return null;\n if (softened !== null) return softened;\n\n // Closing on the GREY image, before any threshold.\n //\n // The `denoise` pass inside `attempt` does the same job on a binarized\n // matrix, where the information it needs is already gone: a 1-bit\n // speckle can only take its neighbours' bit, while a grey one is filled\n // with their intensities. Thresholding is the pipeline's most\n // destructive step, so an operation that benefits from intensity belongs\n // before it. Measured, that ordering alone recovers `glare` +5 with\n // `damaged`, `monitor` and `bright_spots` each gaining.\n if (spent()) return null;\n const filled = attempt(closeGray(image, 1));\n if (filled !== null) return filled;\n\n // Composed transforms, which no single rung reaches.\n //\n // Every rung above applies exactly one transform to the original, so an\n // image with two independent faults — small in frame AND moire, say —\n // has no rung that addresses both. Measured, each of these pairs\n // recovers images no single transform does.\n //\n // The order within a pair matters and is not arbitrary: downscaling then\n // blurring recovers 5 where blurring then downscaling recovers 3,\n // because a box-average reduction already smooths, so blurring first\n // over-softens what the reduction would have handled.\n if (Math.min(image.width, image.height) >= 600) {\n for (const compose of COMPOSED) {\n if (spent()) return null;\n const composed = attempt(compose(image, radius));\n if (composed !== null) return composed;\n }\n }\n\n // The mirror of downscaling: a symbol small in frame. Local\n // binarization thresholds over a fixed 8px block, so a symbol at two or\n // three pixels per module has one block spanning several of them —\n // averaged into a single verdict before geometry ever runs. Enlarging\n // restores the ratio, taking `nominal` from 99 of 125 to 101 and the\n // corpus from 62.1% to 62.7%.\n //\n // Placed LAST despite being a binarization fix rather than a geometric\n // one, because it is the most expensive rung on the ladder: enlarging\n // 2x quadruples the pixel count and every stage after it pays that.\n // Measured mid-ladder it cost the 120ms budgeted rate 1.8 points — the\n // rung itself gains, but it spends budget that cheaper rungs behind it\n // would have converted at a better rate. Capped by area for the same\n // reason.\n if (image.width * image.height <= UPSCALE_LIMIT) {\n if (spent()) return null;\n\n // Enlarge the SYMBOL, not the frame.\n //\n // The rung fixes a block-to-module ratio, which is a property of the\n // symbol; enlarging everything around it buys nothing and costs\n // everything, since every later stage then works on four times the\n // pixels. Measured, the transform itself is 18ms of a 245ms rung — the\n // other 227ms is the pipeline running at quadruple size.\n //\n // Cropped per TRIPLE rather than around all candidates. A frame\n // holding several codes — the `lots` category, read 100% — has\n // candidates spread across it, and their combined box spans a median\n // 62% of the frame while any single symbol's spans effectively none.\n // Boxing them together would both defeat the saving and merge distinct\n // symbols into one region belonging to neither.\n for (const region of symbolRegions(image, locateOnce(image))) {\n if (spent()) return null;\n const larger = attempt(upscale(region, 2));\n if (larger !== null) return larger;\n }\n }\n\n // Last: sweep a plain threshold across its range.\n //\n // Both binarizers answer \"what is the right threshold?\" — one per image,\n // one per block. On a damaged or unevenly lit symbol there often is not\n // one: measured across the corpus, the thresholds that recover an\n // otherwise-unreadable image spread over 40-190 with no clustering, and\n // the image's own mean does not predict them. Eleven distinct values\n // recover seventeen images between them, so no smaller set would do.\n //\n // Sauvola was measured here first, since the document-binarization\n // literature prefers it for degraded images and an IEEE study validates\n // it for QR under uneven illumination. Nine tuned variants recovered 3\n // images against this sweep's 11, and none the sweep missed — its\n // threshold collapses exactly where local contrast is low, which is what\n // damage and glare produce. See `binarizeAt`.\n //\n // Last on the ladder because it is the most expensive rung: a whole pass\n // per threshold. Everything above it is cheaper per image recovered, and\n // the time budget stops this before it runs on a live frame.\n for (const threshold of THRESHOLD_SWEEP) {\n if (spent()) return null;\n\n const swept = decodeBinarized(\n image,\n false,\n false,\n false,\n false,\n binarizeAt(image, threshold)\n );\n if (swept !== null) return swept;\n }\n\n return null;\n }\n };\n};\n","/**\n * Running the decoder off the main thread.\n *\n * Decoding is synchronous and cannot be made otherwise without rewriting\n * every stage as a coroutine, so a budget bounds how much work is STARTED,\n * not how long the thread is held. Measured on a hard frame, a 40ms budget\n * produced a 208ms block and a 400ms budget a 481ms one — because the first\n * attempt runs before any deadline check, and one expensive stage overruns\n * freely once entered.\n *\n * At 60fps a frame is 16.7ms, so those are 12 and 28 dropped frames: a\n * visible freeze of the preview, on the very frames where the user is trying\n * to line up a shot. No budget setting fixes that, because the problem is\n * occupancy rather than duration.\n *\n * A worker fixes it completely. The decoder is pure — pixels in, string out,\n * no shared state — which is exactly what transfers cleanly across a thread\n * boundary. The buffer is transferred rather than copied, so the cost is a\n * pointer hand-off rather than a megabyte memcpy.\n *\n * This module is the worker side. It is deliberately tiny and has no imports\n * beyond the decoder, so it can be bundled as a worker entry by any tool.\n */\n\nimport { createQrDecoder, type QrDecoderOptions } from \"./qr/decoder.js\";\nimport type { DecodedSymbol } from \"./types.js\";\n\n/** A frame handed to the worker. */\nexport interface DecodeRequest {\n /** Correlates the reply, since frames may be in flight concurrently. */\n readonly id: number;\n readonly data: Uint8ClampedArray;\n readonly width: number;\n readonly height: number;\n}\n\n/** The worker's reply. */\nexport interface DecodeResponse {\n readonly id: number;\n readonly result: DecodedSymbol | null;\n /** Wall-clock time the decode took, for callers pacing their own requests. */\n readonly elapsedMs: number;\n}\n\n/**\n * Wire a worker scope to a decoder.\n *\n * Call from a worker entry module:\n *\n * ```ts\n * import { serveDecoder } from \"@saeris/hanko/scan/worker\";\n * serveDecoder(self);\n * ```\n *\n * The scope is passed in rather than reached for, so this stays testable\n * without a worker and works under any host that provides the same two\n * methods — a DOM `Worker`, a Node `parentPort`, or a stub.\n */\nexport const serveDecoder = (\n scope: {\n addEventListener?: (\n type: string,\n listener: (event: unknown) => void\n ) => void;\n on?: (type: string, listener: (message: unknown) => void) => void;\n postMessage: (message: unknown) => void;\n },\n options: QrDecoderOptions = {}\n): void => {\n // One decoder for the worker's lifetime. Constructing one is cheap, but\n // reusing it lets V8 keep the hot paths optimised across frames rather than\n // rediscovering them each time.\n const decoder = createQrDecoder(options);\n\n const handle = (payload: unknown): void => {\n const request = payload as DecodeRequest | { data?: DecodeRequest };\n // A DOM MessageEvent carries the payload on `.data`; a Node message is\n // the payload itself.\n const frame =\n `data` in request && typeof request.data === `object`\n ? (request.data as DecodeRequest)\n : (request as DecodeRequest);\n\n if (frame === null || typeof frame !== `object` || !(`id` in frame)) return;\n\n const started = Date.now();\n const result = decoder.decode({\n data: frame.data,\n width: frame.width,\n height: frame.height\n });\n\n scope.postMessage({\n id: frame.id,\n result,\n elapsedMs: Date.now() - started\n } satisfies DecodeResponse);\n };\n\n if (typeof scope.addEventListener === `function`) {\n scope.addEventListener(`message`, handle);\n } else if (typeof scope.on === `function`) {\n scope.on(`message`, handle);\n }\n};\n"],"mappings":"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"}
|