Technical Documentation

Understand the system.
Improve the scanner.

Architecture, data flow, platform boundaries, invariants, and verification guidance for FOSScanner contributors and maintainers.

00 · Scope

A native-first, privacy-first scanner

FOSScanner is a Flutter application for capturing or importing document images, correcting their geometry, applying visual processing, retaining editable page state, and exporting a multi-page PDF. Processing is local to the device. The application has no account system, backend, analytics, or cloud storage.

Source of truthThis page summarizes the current repository. For exact APIs, dependency versions, and behavior, consult the source tree, AGENTS.md, CONTRIBUTING.md, and the tests in test/.

01 · Architecture

Keep responsibilities explicit

The application is organized around a small number of stateful screens and platform-isolated services. UI code should depend on stable service entry points rather than platform-specific implementations.

PresentationMaterial 3 screens own interaction state, busy guards, mounted checks, and page actions.
Domain modelScannedPage retains original and processed bytes plus all editing parameters.
Processing boundaryDocumentProcessor exposes matching native and web APIs.

The native pipeline uses OpenCV through opencv_dart. The web implementation is API-compatible but intentionally does not perform native document processing because the bindings are FFI-only.

02 · Data flow

Follow bytes and ownership

  1. Intake: capture or import encoded image bytes. Gallery originals remain untouched.
  2. Validation: check encoded size, decoded dimensions, corner geometry, page count, and memory limits before expensive work.
  3. Editing: retain original bytes and user parameters while producing processed output for preview and export.
  4. Composition: reorder in-memory pages and generate the final PDF from processed output, not a reduced preview.
  5. Sharing: pass PDF bytes to the platform share mechanism. OS/share caches may materialize temporary copies.
  6. Cleanup: remove app-owned camera and OCR temporary files on both success and failure.

Expensive native processing must remain off the UI isolate. Asynchronous screen code must preserve busy guards and verify mounted before updating state.

03 · Code map

Where to make a change

AreaPrimary filesContract
App entry and themelib/main.dartMaterial 3 light/dark configuration.
Page lifecycle and exportlib/screens/scanner_home_page.dartIntake, in-memory pages, reorder, PDF, sharing, About.
Corner editorlib/screens/corner_adjust_screen.dart
lib/widgets/corner_overlay.dart
Corner editing, previews, and final processing.
Geometry and limitslib/services/corner_geometry.dart
image_metadata.dart
Ordering, convexity, finite values, warp bounds, memory checks.
Native processingdocument_processor_native.dartOpenCV lifecycle and filters.
Web processingdocument_processor_web.dartAPI-compatible pass-through behavior.
Android OCRocr_service.dart
MainActivity.kt
assets/tessdata/
MethodChannel, worker execution, Tesseract data, searchable PDF.

04 · Development setup

Use the pinned toolchain

Use Flutter 3.44.0 from .flutter-version, Dart >=3.12.0 <4.0.0, and Java 17 for Android CI. Keep SDK pins consistent when deliberately upgrading the toolchain.

flutter pub get
flutter run

Docker alternatives are defined in docker-compose.yml. The APK service uses an amd64 toolchain and may require emulation on non-amd64 hosts.

05 · Testing matrix

Validate behavior at the right layer

dart format --output=none --set-exit-if-changed lib test
flutter analyze
flutter test
flutter build web
flutter build apk --debug --target-platform android-arm64
ChangeRequired verification
Geometry or image limitsFocused service tests plus capture, corner adjustment, filters, and large-image checks.
Native processingNative tests plus Android/iOS or desktop device validation; web is not sufficient.
OCR or PDF exportAndroid emulator/device: selectable text, search, cancellation, cleanup, dimensions, and multi-page output.
UI or accessibilityFlutter tests plus semantic actions, keyboard/screen-reader behavior where applicable, and responsive layout checks.
Platform configurationRelevant platform build and CI workflow checks; do not hand-edit generated registrants.

Native service tests do not replace an emulator or physical-device check. Report environment limitations precisely instead of treating a web build as native validation.

06 · Platform boundaries

Preserve matching implementations

  • Android, iOS, and desktop native builds use OpenCV for edge detection, perspective correction, filters, rotation, and brightness/contrast.
  • The web processor is a pass-through implementation; the web target is a preview/testing target rather than native-processing validation.
  • Desktop camera availability comes from picker capability. Import must remain available where camera UI is unsupported.
  • Guard unsupported platform calls and keep web compilation green when adding native services.
  • Platform folders contain permissions, identifiers, runners, and build configuration; change their source configuration rather than generated output.

07 · Android OCR bridge

Keep the Dart and Kotlin contracts synchronized

Android searchable-PDF work spans lib/services/ocr_service.dart, the com.fosscanner.app/ocr MethodChannel in MainActivity.kt, Android Gradle dependencies, and the bundled English/Latin Tesseract data under assets/tessdata/.

Bridge contractChanging a method name, argument key, result shape, cancellation state, or tessdata path requires coordinated Dart, Kotlin, and regression-test updates.
  • Run native OCR on a worker executor and return channel results on the main thread.
  • Keep cancellation valid through preparation, recognition, and export; do not fall back after a confirmed cancellation.
  • Wait for native work to finish before deleting temporary files.
  • Verify searchable text, page dimensions, multi-page output, cancellation, and failure cleanup on an Android emulator or device.

08 · Safety invariants

Protect correctness and privacy

  • Preserve original image bytes, editing parameters, and re-editability.
  • Reject invalid, non-finite, non-convex, incorrectly ordered, or out-of-bounds corners before warping.
  • Bound encoded bytes, decoded dimensions, page count, retained memory, and preview/export allocations.
  • Release owned OpenCV Mats, vectors, and Flutter image resources in finally; do not dispose borrowed contour elements.
  • Never log document contents or extracted text. Do not add telemetry, uploads, remote processing, or incidental network dependencies.
  • Do not promise immediate deletion of OS/share caches; they are managed by the platform.

09 · Contribution and release

Make changes easy to review

Base new work on dev. Use Conventional Commits such as fix:, feat:, and docs:. Add regression coverage for changed behavior, avoid unrelated formatting or dependency upgrades, and preserve pubspec.lock when dependencies change.

Read CONTRIBUTING.md, inspect the CI results, and open an issue when behavior or platform support is unclear.

Release Please manages versions and changelogs when changes are promoted to main. Release Android artifacts require the configured signing properties and keystore; never commit signing credentials or replace release signing with debug signing.