doclens 0.0.4
doclens: ^0.0.4 copied to clipboard
Document scanner for Flutter with native edge detection and a 100% Flutter UI you fully control, plus a one-line escape hatch to the OS-native scanner.
0.0.4 #
Resume grace window prevents immediate re-capture
DoclensController.resume()now resets stability tracking and suppresses auto-capture for 1 200 ms (resumeAutoCaptureGrace) after a resume. Without this, a document still aligned in frame from before the pause would re-trip auto-capture within a frame or two of resuming, giving the user no chance to reposition after a retake.- Any in-progress confirmation phase is also cancelled on resume so the two-stage capture timer starts fresh.
0.0.3 #
Android preview no longer stretches
- The live preview now reports its size in the rotated (displayed)
orientation instead of the sensor-natural landscape buffer size, so a
portrait preview fills a portrait screen without
BoxFit.coverstretching it. Driven off CameraX'ssetTransformationInfoListener, with identical sizes deduped and 0x0 events dropped so a stale or repeat emission can't corrupt the layout.
Overlay shows from the first frame
DoclensViewnow paints the quad overlay during the brief window between the first camera frame and the firstpreviewSizeevent. Previously the overlay was missing for that window; the corners are normalized[0,1]so they align to the texture rect immediately.
Primary button
- The default primary button in
DoclensScreenis now icon-only (forward arrow), dropping the inline label + icon row for a cleaner control.
0.0.2 #
EditCornersScreen
- AppBar styled with white foreground, no elevation, and weighted title text.
- Bottom buttons are now full-width (
Expanded) with 12 px gap between them. onSavereturn value (warped image path) is passed back viaNavigator.pop.- New parameters:
resetLabel,saveLabel,savingLabel— customise button text without supplying a fullbuttonBuilder. - New parameters:
buttonStyle(ButtonStyle?) andbuttonTextStyle(TextStyle?) — style the default buttons without a custom builder.
0.0.1 #
Initial release.
Drop-in scanner
DoclensScreen.scan(context)— one-line, full-screen scanner route with live preview, auto-capture, and a built-in review screen (retake / edit corners / accept). ReturnsFuture<ScanResult?>.- Every visible string and behaviour knob (auto-capture timing, JPEG quality, flash mode, lens, accent colours, labels, edit-corners toggle) exposed as a top-level parameter with rich dartdoc.
Custom UI
DoclensViewFlutter widget rendering aTexture-backed live camera preview plus your overlay / shutter / flash button builders. Every slot acceptsnullto render nothing, a static default for quick start, or a custom widget.DoclensController extends ChangeNotifierowning the session. Streams:quadStream,statusStream,autoCaptureStream,lowLightStream,previewSizeStream. Methods:initialize,capture,warpImage,focusAt,setFlashMode,cycleFlashMode,switchCamera,pause,resume,dispose.QuadOverlayfamily of pre-built overlay widgets with named constructors:outline,filled,corners,cornersFilled,dots,dotsLine,glow. Status-driven colour followsaccent/warning. The drop-inDoclensScreenexposes anoverlayStyle: QuadOverlayStyleparameter so consumers can switch the look without writing a builder.
Native detection pipeline
- iOS —
VNDetectDocumentSegmentationRequest(the Core ML detector used by VisionKit) on iOS 15+, with a docs-tunedVNDetectRectanglesRequestfallback on iOS 13/14. - Android — pure-Kotlin Sobel + connected-components + convex-hull approximation on CameraX (no OpenCV, no on-device ML model bundling on the live-preview path).
- Streams normalised
Quadto Dart at a configurable throttle rate (default 15 Hz). - Two-stage auto-capture with
DetectionStatus.confirmingphase, configurable thresholds and durations.
Focus
- Continuous autofocus enabled by default on both platforms (iOS
.continuousAutoFocus+ near-distance hint; Android CameraXCONTROL_AF_MODE_CONTINUOUS_PICTURE). - Tap-to-focus on the preview triggers a one-shot focus + auto-exposure
at the tap point, with a focus-reticle animation. Reverts to
continuous AF after ~3 seconds. Programmatic access via
controller.focusAt(Offset).
Capture + warp
- Full-resolution still capture with native perspective warp
(
CIPerspectiveCorrectionon iOS,Matrix.setPolyToPolyon Android), EXIF orientation baked into pixel layout. - Graceful fallback when warp fails —
ScanResult.warpErroris surfaced, raw image and quad still returned. EditCornersScreenwith draggable handles, customisable builders, and re-warp callback.
Quality of life
- Median-of-N corner smoothing (
QuadSmoother) to kill single-frame jitter. - Flash / torch toggle, camera switching, pause/resume on app lifecycle.
- Low-light detection emitted on the status stream.
- Preview-size event so the overlay coordinate space always matches the rendered preview pixels.
ScannerConfigwith feature flags for auto-capture timing, smoothing, detection throttle, JPEG quality, flash mode, lens, lifecycle, telemetry, tap-to-focus, pinch-to-zoom — all with sensible defaults.- Typed exceptions:
ScannerPermissionException,ScannerUnavailableException,ScannerInitializationException,ScannerCaptureException.
OS-native scanner (one-line opt-in)
scanWithNativeUI()launches the OS-native scanner UI:VNDocumentCameraViewControlleron iOS,GmsDocumentScanner(Google Play services) on Android.- Returns the cropped page image paths or
nullon user cancel, consistently on both platforms. - Pre-launch Google Play services check on Android with
ScannerUnavailableExceptionon devices without GMS.
Tests + docs
- Pure-Dart unit tests for
Quad,StabilityTracker,StatusClassifier, andQuadSmoother. doc/architecture.mdwith the Dart ↔ native pipeline diagram.doc/decisions.md— every non-obvious design choice cited against Apple / Google docs.