flutter_better_scanner library

A drop-in document scanner for Flutter.

Two ways to use it:

1. Built-in UI — one call:

final result = await BetterScanner.openScanner(
  context,
  config: const ScannerConfig(
    captureMode: CaptureMode.multiple,
    shutterMode: ShutterMode.auto,
    autoCrop: true,
    autoEnhance: true,
    exportFormat: ExportFormat.jpg,
  ),
);
final paths = result?.imagePaths ?? [];

2. Your own UI — drive the controller:

final controller = ScannerController(config: myConfig);
await controller.initialize();

// In your build():
ScannerPreview(controller: controller)

// Wire up your own buttons:
controller.cycleFlashMode();
controller.switchCamera();
controller.setGuide(ScanGuide.a4);
controller.setShutterMode(ShutterMode.auto);
controller.setDetectionQuality(DetectionQuality.medium);
await controller.capture();
await controller.pickFromGallery();
final result = await controller.finish();

Live detection state (outline, hint, auto-capture progress) is published through controller.detection, a ValueListenable that updates per frame without rebuilding the camera preview.

3. Your own review screen. The same controller backs the page list, so a custom preview needs no extra plumbing — it is a ListenableBuilder over controller.pages:

// Read
controller.pages;                    // List<ScanPage>
controller.proxyPath(page);          // thumbnail file to show
page.enhancement, page.rotationQuarterTurns, page.cropCorners;

// Edit — each call re-renders and notifies listeners
controller.rotatePage(page);
controller.flipPage(page);
controller.setPageEnhancement(page, ScanEnhancement.magicColor);
controller.setPageAdjustments(page, brightness: 12, contrast: 1.2);
controller.setPageCrop(page, corners);
controller.duplicatePage(page);
controller.deletePage(page);
controller.reorderPages(oldIndex, newIndex);
controller.rename('Invoice 42');

// Borrow a built-in editor from your own screen
await controller.openCropEditor(context, page);
await controller.openEnhanceEditor(context, page);
await controller.openAnnotateEditor(context, page);

// Build your own filter strip
final thumbs = await controller.renderEnhancementThumbnails(page);

final result = await controller.finish();   // exports, returns paths

4. A-la-carte — one editor, on any image. No camera, no session, no package UI around it. Give it a path, get a new path back:

final cropped  = await ScannerEditor.crop(context, imagePath: path);
final enhanced = await ScannerEditor.enhance(context, imagePath: path);
final signed   = await ScannerEditor.annotate(context, imagePath: path);

// Headless — no screen is shown at all:
final turned = await ScannerEditor.rotate(imagePath: path);
final tidy   = await ScannerEditor.autoCrop(imagePath: path);
final bw     = await ScannerEditor.applyEnhancement(
    imagePath: path, enhancement: ScanEnhancement.blackWhite);

// Or hand the package a pile of images and let it run the whole
// review screen over them:
final result = await ScannerEditor.editImages(
    context, imagePaths: myPaths);

Classes

AutoCaptureTuning
Timing and sensitivity of automatic capture.
BetterScanner
One-call entry points for the document scanner.
DetectionState
Immutable snapshot of the live detection, published on every frame.
GridOverlay
Rule-of-thirds grid.
GuideOverlay
Paper-size framing guide (A4 / Letter).
PreviewScreen
Multi-page review screen: reorder, per-page editors, add more pages, and a single confirm action that finishes the session.
PreviewTools
Which per-page editors the built-in preview screen offers.
Quad
Quadrilateral as 4 corners, TL/TR/BR/BL. Coordinates are either normalized 0,1 (detection output) or pixels (warp input) — the owner tracks which.
QuadOverlay
Paints the detected document outline and the auto-capture ring.
ScannedPage
One finished page of a scan session.
ScannerConfig
Everything the scanner needs to know, in one immutable object.
ScannerController
Headless scanner engine.
ScannerEditor
A-la-carte access to the package's editors, for apps that manage their own images and their own UI.
ScannerPermissions
Camera permission checks, requests and the settings deep link.
ScannerPreview
Live camera preview with the detection outline, framing guide and grid composited on top.
ScannerScreen
The package's camera screen. Pops a ScanResult.
ScannerTheme
Colours used by the built-in screens.
ScanPage
A page inside a live scan session.
ScanResult
What a scan session produced.

Enums

AfterCapture
What the scanner does after a page is captured.
CameraFacing
Which physical camera to open.
CaptureMode
How many pages a scanning session may produce.
DetectionQuality
How hard the live edge detector works per frame.
ExportFormat
File type produced when a session finishes.
ScanEnhancement
Image enhancement applied to a page.
ScanGuide
Framing guide drawn over the camera preview.
ScanHint
What the scanner is telling the user right now.
ScannerFlashMode
Torch / flash behaviour while scanning.
ScannerPermission
Camera permission state, normalized across Android and iOS.
ScannerStatus
Why the camera is not showing a preview.
ScanStatus
Why a scan session ended.
ShutterMode
Shutter behaviour.

Extensions

ScanHintLabel on ScanHint