scanid library

Free, open-source on-device OCR, barcode scanning, and document-edge detection, plus AAMVA driver's-license and ICAO MRZ decoders.

Everything runs on-device (Apple Vision on iOS, ML Kit on Android) — nothing is ever sent to a server, and there's no license fee.

Typical usage:

const capture = PlatformCaptureService();
final payloads = await capture.recognizeBarcodes(imageBytes);
final fields = payloads.map(Aamva.parse).firstWhere(
  (f) => f != null,
  orElse: () => null,
);

final ocr = await capture.recognize(imageBytes);
final mrz = Mrz.parse(ocr.fullText);

Classes

Aamva
Parses the AAMVA payload encoded in the PDF417 barcode on the back of a US/Canada driver license or state ID into structured fields. Like the MRZ, the barcode encodes the data exactly (3-letter element codes, each value newline-terminated) — far more reliable than OCR of the printed front. The barcode bytes come from a scanner (CaptureService.recognizeBarcodes); this just decodes the payload string. Returns null if it isn't an AAMVA payload.
CaptureService
On-device OCR, barcode scanning, and document-edge detection. Nothing ever leaves the device — Apple Vision (iOS) / ML Kit (Android) run locally, and the only thing that crosses the platform channel is the image bytes in and recognized data out.
DocumentRect
A detected document's bounding box, normalized to [0,1] in image space with a top-left origin. Used only as the initial rectangle for a confirm- crop UI — the caller should always let the user adjust/accept it, so a loose detection is fine.
FakeCaptureService
Deterministic OCR for tests + simulators: returns canned results, either a single fixed result or one built from raw lines. No native dependency.
Mrz
Parses the ICAO 9303 Machine Readable Zone — the <<< lines at the bottom of a passport — into structured, check-digit-validated fields. The MRZ encodes the data exactly, so this is far more reliable than guessing fields from the visual text (and the check digits catch OCR slips). Handles TD3 (passport, 2×44), TD1 (ID card, 3×30), and TD2 (2×36). parse returns null when no MRZ is found.
OcrBox
A recognized text element's bounding box, normalized to [0,1] in image space with a top-left origin — so it can be overlaid on the displayed image regardless of scale.
OcrLine
One recognized line of text from on-device OCR, with its position on the image (box) when the platform provides it.
OcrResult
The result of recognizing text in an image — all produced on-device.
PlatformCaptureService
Calls the native OCR/barcode/document-detect plugin over a MethodChannel. The native side (ScanidPlugin.swift / ScanidPlugin.kt) registers scanid/capture and returns a list of {text, confidence, box} maps for recognizeText, a list of payload strings for recognizeBarcodes, and a {left, top, width, height} map or null for detectDocumentRect.