← Flutter / Dart

Flutter / Dart · 18 / 18

Scan und OCR: Vorschlag, Bestätigung und Speicherung

Du baust einen prüfbaren Erfassungsablauf und hältst Texterkennung von bestätigten Daten getrennt.

  • Groß
  • Anspruchsvoll
  • 120 min

Voraussetzungen: Verschlüsselte Backups sicher wiederherstellen

OCR ist Texterkennung aus einem Bild. Ein erkanntes Wort ist noch keine bestätigte Ablesung. Fotos können Seriennummern, Datumsangaben und mehrere Zahlen enthalten. Zählerstand Log erzeugt deshalb Kandidaten und verlangt eine Nutzerbestätigung. Fahrzeugakte verwendet zusätzlich einen Dokumentenscanner für PDF-Belege, ohne daraus automatisch eine Rechnungsanalyse zu machen. Wir modellieren den gemeinsamen Ablauf über einen Port und testen zuerst mit kontrollierter Erkennung.

Beispieldateien

01Die Erkennungsgrenze definieren

OcrPort liefert erkannte Textzeilen. Der Lernadapter liefert feste Zeilen statt einer Kameraaufnahme. Dadurch können wir den fachlichen Ablauf auf jedem Computer ausführen. Er beweist keine echte OCR-Qualität.

capture.dart · dartDatei öffnen
abstract interface class OcrPort {
  Future<List<String>> recognize(String image);
}

class LearningOcr implements OcrPort {
  @override
  Future<List<String>> recognize(String image) async => [
    'Meter 12345',
    'Reading 64820.5 kWh',
  ];
}

class CaptureService {
  CaptureService(this.ocr);
  final OcrPort ocr;
  final saved = <String>[];
  Future<List<String>> propose(String image) async {
    final lines = await ocr.recognize(image);
    final pattern = RegExp(r'\b\d{1,6}(?:[.,]\d{1,3})?\b');
    return [
      for (final line in lines)
        for (final match in pattern.allMatches(line)) match.group(0)!,
    ];
  }

  void confirm(String candidate, {required bool accepted}) {
    if (!accepted) return;
    if (!RegExp(r'^\d{1,6}(?:[.,]\d{1,3})?$').hasMatch(candidate))
      throw ArgumentError('Invalid value');
    saved.add(candidate.replaceAll(',', '.'));
  }
}

Future<void> main() async {
  final service = CaptureService(LearningOcr());
  final candidates = await service.propose('synthetic-photo');
  if (service.saved.isNotEmpty) throw StateError('Saved before confirmation');
  service.confirm(candidates.last, accepted: false);
  if (service.saved.isNotEmpty) throw StateError('Saved after rejection');
  service.confirm(candidates.last, accepted: true);
  print(service.saved);
}

Starten / prüfen

dart run capture.dart

02Kandidaten erzeugen

Die kleine Regex sucht Zahlen mit optionalem Dezimalteil. Sie ist ausdrücklich kein Ersatz für die echte Kandidatenextraktion. Dort werden unter anderem Zeilen, Positionen und getrennte Zifferngruppen berücksichtigt. Das Lernbeispiel darf mehrere Vorschläge zurückgeben.

03Die Bestätigung als eigene Aktion halten

propose schreibt keine Ablesung. confirm verlangt einen Kandidaten und eine ausdrückliche Entscheidung. Eine echte Oberfläche zeigt Foto und Wert nebeneinander, erlaubt eine Korrektur und prüft erst danach die Fachregel.

04Ressourcen und Abbruch behandeln

Der echte ML-Kit-Adapter schließt TextRecognizer in finally. Ein Abbruch darf keinen Entwurf heimlich bestätigen. Der Service muss Fehler von Kamera, fehlendem Plugin und ungültigem Ergebnis unterscheiden. Die Oberfläche behält einen sinnvollen Wiederholungsweg.

05Scanner und OCR auseinanderhalten

Der Dokumentenscanner in Fahrzeugakte erstellt eine PDF mit bearbeitbaren Scan-Seiten. Die App kopiert das Ergebnis kontrolliert zum Eintrag. Zähler-OCR erzeugt dagegen einen Wertvorschlag. Beide benötigen Geräteadapter, aber ihre fachlichen Ergebnisse sind unterschiedlich.

Erwartetes Ergebnis

Vor Bestätigung ist saved leer. Ablehnung bleibt leer. Bestätigung fügt genau den ausgewählten Wert hinzu.

06Den echten Geräteablauf prüfen

Teste auf Android ein klares und ein unscharfes Foto, fehlende Berechtigung, Abbruch und mehrere Zahlen. Prüfe, dass vor Bestätigung keine Ablesung existiert. Browsertests ersetzen diesen Nachweis nicht. Bei Google-ML-Kit-Scannerfunktionen gelten die im Produkt dokumentierten Geräte- und Play-Services-Anforderungen.

Datenfluss
  1. Foto / Scan
  2. Geräte-Port
  3. OCR-Kandidaten
  4. Nutzerprüfung
  5. Fachregel / Speichern

Deine Übung

Ergänze einen OcrPort, der einen Fehler wirft. Prüfe, dass saved unverändert bleibt.

Lösung mit Erklärung anzeigen

Die Exception muss vor confirm auftreten. Fange sie an der Anwendungsgrenze ab und biete erneute Erfassung oder manuelle Eingabe an. Speichere keinen erfundenen 0-Wert. Ein zusätzlicher Test prüft einen abgelehnten Kandidaten und einen ausdrücklich korrigierten Wert.

Projektbezug und Quellen

Das Beispiel ist zum Lernen vereinfacht. Die verlinkte Codeversion zeigt die Anwendung im Projekt und die dortigen Prüfungen.