How-to: file and image input (the no-camera path)
Not every user can grant a camera: locked-down desktops, kiosk browsers, denied permissions, or someone who just took a screenshot of the animated QR. fromImage decodes QR codes out of a still image, so you always have a fallback.
Single image
import { fromImage } from '@nkwib/ur-scanner';
const input = document.querySelector('input[type=file]') as HTMLInputElement;
input.addEventListener('change', async () => {
const file = input.files?.[0];
if (!file) return;
const { progress, found } = await fromImage(file, { expectedType: 'bytes' });
console.log(`found ${found.length} code(s), complete=${progress.complete}`);
});
source accepts a Blob, a File, an ImageBitmap, an <img>, a <canvas>, or a URL string. Large photos are downscaled to maxSize (default 2000px on the longer side) before detection to keep it fast; raise it if dense codes are being missed.
Multi-part payloads from several screenshots
A single still holds one frame of an animated UR, which is rarely enough. Because UR is fountain-coded, a handful of screenshots taken at different moments is plenty. Thread one receiver across the calls so state accumulates:
import { URReceiver, fromImage } from '@nkwib/ur-scanner';
const receiver = new URReceiver({ expectedType: 'bytes', onComplete: (ur) => use(ur.cbor) });
for (const file of Array.from(input.files ?? [])) {
const { progress } = await fromImage(file, { receiver });
if (progress.complete) break;
}
Paste and drag-drop
The same fromImage handles a pasted or dropped image; just pull the Blob out of the event:
window.addEventListener('paste', async (e) => {
const item = [...(e.clipboardData?.items ?? [])].find((i) => i.type.startsWith('image/'));
const blob = item?.getAsFile();
if (blob) await fromImage(blob, { receiver });
});
Notes
- Detection uses the same detector seam as the camera: native
BarcodeDetectorwhere available, else lazily-loadedjsqr. Installjsqrif you must support Safari/Firefox for image input. fromImagereads pixels withgetImageData, so cross-origin image URLs must be CORS-enabled or the canvas taints and detection throws. Prefer passing aBlob/File.- One still can contain several distinct QR codes; all are detected and fed, and non-UR ones are ignored (reason
not-a-ur).