flutter_ocr_native ✍️ Raja Asaithambi

A Flutter plugin for extracting text from images and PDFs using native on-device OCR engines — no third-party Dart OCR packages required.

  • Android: Google ML Kit Text Recognition
  • iOS: Apple Vision Framework
  • macOS: Apple Vision Framework
  • Windows: Windows.Media.Ocr (WinRT)
  • Linux: Tesseract OCR

Features

  • Read text from image file path, File, or raw bytes
  • Native PDF to image — render PDF pages without third-party packages
  • Structured results: blocks → lines → elements with bounding boxes & confidence scores
  • English-only extraction — non-Latin scripts auto-filtered
  • Auto-orientation correction — detects correct image rotation using OCR confidence
  • Image cropper with rotate support — crop & rotate before OCR
  • Capture instructions widget — show best practices before scan/upload
  • Document type auto-detection — Aadhaar, PAN, Passport, Driving License, Voter ID, Cheque, Vehicle Report
  • Old & new document format support — all parsers handle both legacy and current Indian document layouts
  • MRZ passport parsing — extracts all fields directly from Machine Readable Zone lines
  • Unified DocumentDetails model — single API for all document types
  • Vehicle report parsing — RC, loan documents, inspection reports, valuation reports from any vendor
  • Loan statement parsing — Housing Finance / NBFC loan account statements with EMI transaction history
  • Bank SOA parsing — Statement of Account with transaction table, opening/closing balance
  • Document search — full-text search with regex, whole-word, case-sensitive modes
  • Smart search — natural language queries ("name", "EMI amount", "loan account") across all document types
  • Aadhaar number masking (text + image) — configurable
  • Aadhaar & PAN number validation (Verhoeff checksum, format check)
  • Bilingual document support — Hindi + English labels (नाम / Name, पिता का नाम / Father's Name) on Aadhaar and PAN
  • Passport, Driving License, Voter ID, IFSC, Account number validation
  • Face extraction from document images (Android, iOS, macOS)
  • Smart handwriting detection — per-document-type policy; passport signatures and cheque handwriting no longer cause false rejections
  • Device & app security — root detection, jailbreak detection, emulator detection, app tamper detection
  • Document viewer with pinch-to-zoom
  • Download with configurable watermark (Lead ID, Lat, Long, etc.)
  • Watermark auto-scales to image resolution — always readable
  • Configurable image compression (JPEG quality 1-100 or PNG lossless)
  • Supports any input image format (JPEG, PNG, WEBP, BMP, GIF, HEIC, TIFF)
  • Platform-specific download paths handled internally
  • Fully on-device — no network calls, works offline

Getting Started

dependencies:
  flutter_ocr_native: ^0.3.8

Android

Minimum SDK 21. Add to android/app/build.gradle:

android {
    defaultConfig {
        minSdk 21
    }
}

iOS / macOS

iOS minimum 13.0, macOS minimum 10.15.

Windows

Requires Windows 10+. No additional setup.

Linux

Requires Tesseract:

sudo apt install libtesseract-dev tesseract-ocr-eng libleptonica-dev

Usage

Basic OCR

import 'package:flutter_ocr_native/flutter_ocr_native.dart';

final reader = OcrReader();
final result = await reader.readFromPath('/path/to/image.jpg');
log(result.text);

// From File
final result = await reader.readFromFile(File('image.png'));

// From bytes
final result = await reader.readFromBytes(imageBytes);

// From PDF (native rendering — no third-party packages)
final result = await reader.readFromPdf(pdfBytes, page: 0);
final result = await reader.readFromPdfFile(File('document.pdf'));

// Structured data
for (final block in result.blocks) {
  for (final line in block.lines) {
    log('${line.text} (confidence: ${line.confidence})');
  }
}

await reader.dispose();

PDF to Image (Native)

Render PDF pages to images natively — no Dart PDF packages needed.

// Render single page
final imageBytes = await OcrDocumentSaver.renderPdfPage(
  pdfBytes,
  page: 0,      // zero-based index
  scale: 2.0,   // render quality (2x = good for OCR)
);

// Get page count
final count = await OcrDocumentSaver.getPdfPageCount(pdfBytes);

// Render all pages
final allPages = await OcrDocumentSaver.renderAllPdfPages(pdfBytes);

// Direct PDF → OCR (single call)
final result = await reader.readFromPdf(pdfBytes);
Platform PDF Engine
Android PdfRenderer (API 21+)
iOS CGPDFDocument
macOS CGPDFDocument
Windows Windows.Data.Pdf
Linux Not supported (returns null)

Auto-Orientation Correction

Automatically detects and corrects image rotation — works even without EXIF data. Uses OCR confidence scoring across all 4 rotations to find the readable orientation.

final corrected = await OcrDocumentSaver.correctOrientation(imageBytes);
final result = await reader.readFromBytes(corrected);

Image Cropper with Rotate

final cropped = await OcrImageCropper.show(
  context,
  imageBytes: correctedBytes,
  title: 'Crop Document',
);

if (cropped != null) {
  final result = await reader.readFromBytes(cropped);
}

Capture Instructions (Show Before Scan)

Guide users on best angle, lighting, and document clarity before capture.

// Bottom sheet (recommended for mobile)
final proceed = await OcrCaptureInstructions.showAsBottomSheet(context);
if (proceed != true) return;

// Dialog
await OcrCaptureInstructions.showAsDialog(context);

// Custom instructions
OcrCaptureInstructions.showAsBottomSheet(
  context,
  title: 'PAN Card Upload Tips',
  customInstructions: [
    OcrInstruction(
      icon: Icons.credit_card,
      title: 'Front Side Only',
      description: 'Upload only the front side of your PAN card.',
      color: Colors.indigo,
    ),
  ],
);

// Inline widget
OcrCaptureInstructions()

Validation & Aadhaar Masking

final reader = OcrReader(
  validateDocument: true,  // reject empty & handwritten
  maskAadhaar: true,       // mask Aadhaar in text
);

try {
  final result = await reader.readFromPath('/path/to/aadhaar.jpg');

  // Masked text
  log(result.text); // "XXXX XXXX 2356"

  // Masked image (Aadhaar digits blacked out)
  if (result.hasAadhaar) {
    Image.memory(result.maskedImageBytes!);
  }
} on EmptyImageException {
  log('No text found');
} on HandwrittenTextException {
  log('Handwritten — not accepted');
}

Smart Handwriting Detection

Documents that always contain handwritten fields (passport signature, cheque amount/payee, old-format driving license entries) are handled with a mixed-mode policy — only rejected if the document contains zero printed keywords at all.

final reader = OcrReader(validateDocument: true);

// Hint the document type to apply the correct policy immediately
// Passport: signature won't cause HandwrittenTextException
final result = await reader.readFromBytes(
  passportBytes,
  docType: DetectedDocType.passport,
);

// Cheque: handwritten amount/payee won't cause HandwrittenTextException
final result = await reader.readFromBytes(
  chequeBytes,
  docType: DetectedDocType.cheque,
);

// Aadhaar/PAN/Voter ID: strict — fully handwritten document is rejected
final result = await reader.readFromBytes(
  aadhaarBytes,
  docType: DetectedDocType.aadhaar,
);
Document Policy Behaviour
Aadhaar, PAN Strict Rejected if native says not printed
Passport, Cheque, DL, Vehicle Report Mixed Only rejected if zero printed keywords found
Voter ID Skip Handwriting check skipped (old laminated cards have typewritten fields)

Document Type Auto-Detection

final result = await reader.readFromBytes(imageBytes);

log(result.docType);      // DetectedDocType.aadhaar
log(result.docTypeLabel); // "Aadhaar Card"

Unified Document Details

Single API for all document types — handles old format, new bilingual format, and MRZ passports.

final details = await DocumentDetails.fromResult(
  result,
  imageBytes: processedBytes,
);

log(details.docType);         // DetectedDocType.aadhaar
log(details.documentNumber);  // "5399 8956 2356"
log(details.name);            // "Ram Deva"
log(details.dob);             // "01/08/1994"
log(details.isValid);         // true
log(details.validationError); // null

// Structured display map — auto-masks Aadhaar
final fields = details.toDisplayMap(maskAadhaar: true);
// {'Document No.': 'XXXX XXXX 2356', 'Name': 'Ram Deva', 'DOB': '01/08/1994', ...}

// Face photo (Aadhaar, PAN, Passport, DL, Voter ID)
if (details.hasPhoto) {
  Image.memory(details.photoBytes!);
}

// Synchronous (no face extraction)
final details = DocumentDetails.fromResultSync(result);

// From raw text
final details = DocumentDetails.fromText(ocrText, DetectedDocType.passport);

Document Number Validation

// Standalone validation — no OCR needed
DocumentNumberValidator.isValidAadhaar('5399 8956 2356'); // true/false
DocumentNumberValidator.validateAadhaar('0000 0000 0000'); // "Aadhaar cannot start with 0"
DocumentNumberValidator.isValidPAN('ABCPD1234F'); // true/false
DocumentNumberValidator.validatePAN('ABCXD1234F'); // "PAN 4th character is invalid holder type"

DocumentNumberValidator.isValidPassport('A1234567');
DocumentNumberValidator.isValidDrivingLicense('KA0120190001234');
DocumentNumberValidator.isValidVoterId('IBW0643130');
DocumentNumberValidator.isValidIFSC('SBIN0001234');
DocumentNumberValidator.isValidAccountNumber('12345678901');

Loan Statement Parsing

Extract structured data from Housing Finance / NBFC loan account statements.

final result = await reader.readFromBytes(loanStatementBytes);
final details = LoanStatementDetails.fromText(result.text);

log(details.loanAccountNumber); // 'APTL123456'
log(details.customerName);      // 'Rajesh Kumar'
log(details.emiAmount);         // '28585.00'
log(details.rateOfInterest);    // '11.50%'
log(details.amtSanctioned);     // '1479134.00'

// Disbursement entries
for (final d in details.disbursements) {
  log('${d.date}: ₹${d.formattedAmount}');
}

// EMI transaction history
for (final tx in details.transactions) {
  log('${tx.date} | ${tx.particulars} | ${tx.transactionType}');
}

Bank Statement of Account (SOA) Parsing

Extract account details and full transaction history from bank SOA PDFs.

final result = await reader.readFromBytes(soaBytes);
final soa = SoaDetails.fromText(result.text);

log(soa.accountNumber);  // '123456789012'
log(soa.accountHolder);  // 'Ram Kumar'
log(soa.ifscCode);       // 'SBIN0001234'
log(soa.closingBalance); // '45,230.50'

for (final tx in soa.transactions) {
  log('${tx.date} | ${tx.description} | Dr: ${tx.debit} | Cr: ${tx.credit}');
}

Full-text search over any OCR-extracted document with regex, whole-word, and case-sensitive modes.

final service = DocumentSearchService(text: result.text, fileName: 'statement.pdf');

// Text search
final matches = service.search('HDFC', caseSensitive: false);
for (final m in matches) {
  log('Line ${m.lineNumber}: ${m.lineText}');
}

// Extract all label:value pairs
final fields = service.extractLabelValues();

// Extract all dates and numbers
final dates = service.extractDates();
final numbers = service.extractNumbers();

// Widget
DocumentSearchWidget(searchService: service)

// Full tabbed page (Search / Fields / Numbers / Dates)
DocumentSearchPage(initialText: result.text, fileName: 'statement.pdf')

Natural language queries that understand what you mean across all document types.

final smart = SmartDocumentSearch(
  text: result.text,
  extractedFields: details.toDisplayMap(),
  documentType: 'loan',
);

// Ask anything
final r = smart.query('EMI amount');       // → '28585.00'
final r = smart.query('name');             // → 'Rajesh Kumar'
final r = smart.query('loan account');     // → 'APTL123456'
final r = smart.query('aadhaar number');   // → '5399 8956 2356'

log(r.value);       // the answer
log(r.confidence);  // 0.0 – 1.0
log(r.found);       // true/false

// Suggestions based on document type
final suggestions = smart.getSuggestions();

// Top 5 key fields
final summary = smart.getQuickSummary();

// Widget
SmartSearchWidget(searchService: smart)

// Full-screen page
SmartSearchPage(searchService: smart, documentType: 'Loan Statement')

Vehicle Report Parsing

Extract data from any vehicle document — RC, Vahan reports, loan documents, inspection reports, valuation reports. Works with different vendors and formats.

final result = await reader.readFromBytes(vehicleDocBytes);
final details = await DocumentDetails.fromResult(result);

if (details.docType == DetectedDocType.vehicleReport) {
  final fields = details.toDisplayMap();
  // {
  //   'Document No.': 'MH12AB1234',
  //   'Chassis No.': 'MA3FYEB1S00123456',
  //   'Engine No.': 'K12MN1234567',
  //   'Owner Name': 'Rajesh Kumar',
  //   'Maker': 'MARUTI SUZUKI',
  //   'Model': 'SWIFT VXI',
  //   'Fuel Type': 'PETROL',
  //   'Reg. Date': '15/03/2020',
  //   'Fitness Valid Upto': '14/03/2035',
  //   'Hypothecation': 'YES',
  //   'Financier': 'HDFC BANK LTD',
  //   'Loan A/C No.': '12345678901234',
  //   ... (40+ fields supported)
  // }
}

Supported Fields:

Category Fields
Registration Registration No., Chassis No., Engine No., RTO Code, RTO Name
Owner Owner Name, Father's Name, Address
Vehicle Class, Type, Maker, Model, Fuel Type, Color, Mfg. Year, CC, Seating Capacity
Validity Reg. Date, Reg. Valid Upto, Fitness Valid Upto, Insurance Valid Upto, PUC Valid Upto
Insurance Insurance Company, Policy No., IDV
Finance Hypothecation, Financier, Loan A/C No., Loan Amount, EMI, Loan Start/End Date
Status NOC Issued, Blacklist Status, Challan Pending
Inspection Odometer Reading, Inspection Date, Inspector Name, Vehicle Condition, Market Value

Supported Document Types:

  • Registration Certificate (RC)
  • Vahan / Parivahan reports
  • Vehicle loan sanction letters
  • Vehicle inspection reports
  • Vehicle valuation reports
  • Insurance documents
  • Any vendor format with label:value pairs

Face Extraction

final faceBytes = await OcrDocumentSaver.extractFace(imageBytes);
if (faceBytes != null) {
  Image.memory(faceBytes);
}

// Check platform support
if (OcrDocumentSaver.isFaceExtractionSupported) {
  // Android, iOS, macOS only
}

Document Viewer

OcrDocumentViewer.show(
  context,
  result: result,
  originalBytes: processedBytes,
  title: 'My Document',
  watermark: OcrWatermark(lines: {
    'Lead ID': 'LD-20250101-001',
    'Lat': '12.9716',
    'Long': '77.5946',
  }),
  onSave: (bytes) async {
    await OcrDocumentSaver.downloadBytes(imageBytes: bytes);
  },
);

Download with Watermark

final watermark = OcrWatermark(
  lines: {
    'Lead ID': 'LD-20250101-001',
    'Lat': '12.9716',
    'Long': '77.5946',
    'Agent': 'Ram Kumar',
    'Date': '2025-01-15 10:30',
  },
);

final file = await OcrDocumentSaver.downloadBytes(
  imageBytes: processedBytes,
  watermark: watermark,
);

final file = await OcrDocumentSaver.downloadFromPath(
  result: result,
  originalImagePath: imagePath,
  watermark: watermark,
);

Image Compression

// JPEG with quality (default 90)
final file = await OcrDocumentSaver.downloadBytes(
  imageBytes: processedBytes,
  imageQuality: 70,
);

// PNG lossless
final file = await OcrDocumentSaver.downloadBytes(
  imageBytes: processedBytes,
  format: OcrImageFormat.png,
);

// Standalone compress
final compressed = await OcrDocumentSaver.compressImage(anyImageBytes, quality: 60);

Custom Validator

final reader = OcrReader(
  validateDocument: true,
  validator: OcrValidator(minTextLength: 20),
);

Device & App Security

Blocks KYC on rooted devices, jailbroken iPhones, emulators, BlueStacks, and tampered/repackaged app binaries. Runs at app startup before any KYC screen loads — zero UX impact.

// Development — no config needed, all tamper checks are skipped
final security = await OcrIntegrity.checkDeviceSecurity();
if (!security.secure) {
  // security.reason explains why — show blocked screen
  return;
}

// Production — pass your values from Dart, no native file edits needed
final security = await OcrIntegrity.checkDeviceSecurity(
  expectedCertHash: 'A1:B2:C3:...',    // SHA-256 of your release keystore
  expectedPackage: 'com.yourcompany.app',
  checkInstaller: true,                 // blocks sideloaded APKs
);
Signal Android iOS
Rooted device ✅ su binary, dangerous apps, rw paths, test-keys —
Jailbroken device — ✅ Cydia, sandbox violation, dylib injection, symlinks
Emulator / BlueStacks ✅ filesystem + build signals ✅ simulator flag
Repackaged APK / IPA ✅ cert hash + package name + installer source ✅ MobileProvision + bundle ID + dylib injection

expectedPackage works for both platforms — Android uses it as the package name, iOS uses it as the bundle ID. One Dart call configures both.

Android — generate your release cert hash:

keytool -list -v -keystore release.keystore -alias <your_alias>
# Copy the SHA-256 fingerprint and pass it as expectedCertHash above

See TAMPER_DETECTION.md for full documentation, attack bypass analysis, and recommended additional hardening.

Toggle at Runtime

reader.validateDocument = false;
reader.maskAadhaar = false;

Complete Example Flow

Future<void> processDocument(File file) async {
  // 1. Handle PDF or image
  final rawBytes = await file.readAsBytes();
  final Uint8List imageBytes;
  if (file.path.toLowerCase().endsWith('.pdf')) {
    final rendered = await OcrDocumentSaver.renderPdfPage(rawBytes);
    if (rendered == null) return;
    imageBytes = rendered;
  } else {
    imageBytes = rawBytes;
  }

  // 2. Auto-correct orientation
  final corrected = await OcrDocumentSaver.correctOrientation(imageBytes);

  // 3. Crop (with rotate option)
  final cropped = await OcrImageCropper.show(context, imageBytes: corrected);
  if (cropped == null) return;

  // 4. OCR — hint doc type for correct handwriting policy
  final reader = OcrReader(validateDocument: true, maskAadhaar: true);
  final result = await reader.readFromBytes(
    cropped,
    docType: DetectedDocType.aadhaar, // optional — auto-detected if omitted
  );

  // 5. Get unified details (parses fields + extracts face)
  final details = await DocumentDetails.fromResult(result, imageBytes: cropped);

  // 6. Display
  final fields = details.toDisplayMap(maskAadhaar: true);

  // 7. Download with watermark
  await OcrDocumentSaver.downloadBytes(
    imageBytes: cropped,
    watermark: OcrWatermark(lines: {'Agent': 'Ram Kumar'}),
  );
}

Public API

OcrReader                      readFromPath / readFromBytes / readFromFile
                               readFromPdf / readFromPdfFile
                               validateDocument, maskAadhaar, validator

OcrResult                      text, blocks, isPrinted, hasAadhaar,
TextBlock / TextLine           maskedImageBytes, docType, docTypeLabel
TextElement

DocumentDetails                fromResult() / fromResultSync() / fromText()
                               docType, documentNumber, name, fatherName,
                               dob, gender, address, isValid, validationError,
                               photoBytes, extraFields, toDisplayMap()

LoanStatementDetails           fromText() — loan account statement parser
                               loanAccountNumber, customerName, emiAmount,
                               rateOfInterest, amtSanctioned, amtDisbursed,
                               disbursements, initialCharges, transactions
LoanTransaction                date, particulars, dueForRepayment,
                               interestPaid, principalPaid, runningBalance
                               isPayment, isDue, isPenalty, transactionType
DisbursementEntry              date, amount, formattedAmount
ChargeEntry                    name, amount, formattedAmount

SoaDetails                     fromText() — bank SOA parser
                               accountNumber, accountHolder, bankName,
                               branchName, ifscCode, accountType, period,
                               openingBalance, closingBalance, transactions
SoaTransaction                 date, description, debit, credit, balance, refNo

DocumentSearchService          search() / countMatches()
                               extractLabelValues() / findFieldValue()
                               extractNumbers() / extractDates()
                               findLinesContaining() / highlightInText()
SearchMatch                    lineNumber, lineText, matchedText, contextBefore/After
ExtractedNumber                value, originalText, lineNumber
ExtractedDate                  originalText, lineNumber

SmartDocumentSearch            query() / getSuggestions() / getQuickSummary()
SmartSearchResult              found, value, fieldName, confidence,
                               resultType, displayText, iconHint
SearchResultType               exactMatch / fuzzyMatch / extracted / textMatch / notFound

DocumentSearchWidget           full-text search widget with nav + options
DocumentSearchPage             tabbed page: Search / Fields / Numbers / Dates
SmartSearchWidget              natural language query widget with suggestions
SmartSearchPage                full-screen smart search page

OcrDocumentSaver               renderPdfPage / getPdfPageCount / renderAllPdfPages
                               correctOrientation / extractFace
                               download / downloadBytes / downloadFromPath
                               save / saveFromPath / burnWatermark / compressImage

DocumentNumberValidator        isValidAadhaar / validateAadhaar
                               isValidPAN / validatePAN / panHolderType
                               isValidPassport / isValidDrivingLicense
                               isValidVoterId / isValidIFSC / isValidAccountNumber
                               extractAadhaar / extractPAN / extractPassport
                               extractDrivingLicense / extractVoterId / extractIFSC

DocumentTypeDetector           detect() / label() / icon()
DetectedDocType                aadhaar / pan / passport / drivingLicense
                               voterId / cheque / vehicleReport / unknown

OcrValidator                   validate(result, docType)
OcrWatermark                   lines, textColor, backgroundColor, fontSize
OcrImageFormat                 jpeg / png

OcrIntegrity                   checkDeviceSecurity() → DeviceSecurityResult
                               hashDetails / hashImage
                               checkImageQuality / checkConfidence
                               consistencyErrors / verify
                               persistAuditRecord / persistTamperEvent
DeviceSecurityResult           secure, reason
OcrAuditRecord                 create() / fromJson() / toJson()
OcrVerificationResult          passed, reason
TamperEvent                    fromVerification() / toJson()

EmptyImageException            thrown when no text detected
HandwrittenTextException       thrown when document is fully handwritten

OcrCaptureInstructions         showAsBottomSheet() / showAsDialog() / inline widget
OcrInstruction                 icon, title, description, color
OcrImageCropper                show() — full-screen crop + rotate
OcrDocumentViewer              show() — full-screen viewer with zoom + save

Architecture

lib/
├── flutter_ocr_native.dart               # Public barrel export
└── src/
    ├── models/
    │   ├── aadhaar_details.dart            # internal — AadhaarDetails parser
    │   ├── cheque_details.dart             # internal — ChequeDetails parser
    │   ├── document_details.dart           # DocumentDetails (public unified model)
    │   ├── driving_license_details.dart    # internal — DrivingLicenseDetails parser
    │   ├── loan_statement_details.dart     # LoanStatementDetails parser + LoanTransaction
    │   ├── ocr_exception.dart              # EmptyImageException, HandwrittenTextException
    │   ├── ocr_result.dart                 # OcrResult, TextBlock, TextLine, TextElement
    │   ├── ocr_watermark.dart              # OcrWatermark config
    │   ├── passport_details.dart           # internal — PassportDetails parser (+ MRZ)
    │   ├── soa_details.dart                # SoaDetails parser + SoaTransaction
    │   ├── vehicle_report_details.dart     # internal — VehicleReportDetails parser
    │   └── voter_id_details.dart           # internal — VoterIdDetails parser
    ├── utils/
    │   ├── document_search_service.dart    # DocumentSearchService — full-text search
    │   ├── ocr_document_saver.dart         # Download, save, watermark, compress, face, orientation, PDF
    │   └── smart_document_search.dart      # SmartDocumentSearch — natural language queries
    ├── security/
    │   └── ocr_integrity.dart              # Device security, tamper detection, audit trail, hashing
    ├── validators/
    │   ├── document_number_validator.dart  # Aadhaar, PAN, Passport, DL, Voter ID, IFSC validation
    │   ├── document_type_detector.dart     # Auto-detect document type from OCR text
    │   └── ocr_validator.dart              # Document validation (printed check, min length)
    ├── widgets/
    │   ├── document_search_widget.dart     # DocumentSearchWidget + DocumentSearchPage
    │   ├── ocr_capture_instructions.dart   # Pre-scan tips widget
    │   ├── ocr_details_card.dart           # internal — details card widget
    │   ├── ocr_document_viewer.dart        # Full-screen viewer with zoom
    │   ├── ocr_image_cropper.dart          # Crop + rotate widget
    │   ├── smart_search_widget.dart        # SmartSearchWidget + SmartSearchPage
    │   └── voter_id_details_card.dart      # internal — Voter ID card widget
    ├── ocr_platform_interface.dart         # internal — abstract platform contract
    ├── ocr_method_channel.dart             # internal — MethodChannel implementation
    └── ocr_reader.dart                     # OcrReader public API

android/src/main/kotlin/com/flutter_ocr_native/
    └── OcrPlugin.kt                        # ML Kit OCR + face + orientation + crop + rotate + PDF

ios/Classes/
    └── OcrPlugin.swift                     # Vision OCR + face + orientation + crop + rotate + PDF

macos/Classes/
    └── OcrPlugin.swift                     # Vision OCR + face + orientation + crop + rotate + PDF

windows/
    └── ocr_plugin.cpp                      # WinRT OCR + GDI+ + PDF

linux/
    └── ocr_plugin.cc                       # Tesseract OCR + Leptonica

Supported Platforms

Platform Min Version OCR Engine Face Extraction Auto-Orientation PDF Render
Android SDK 21 Google ML Kit ✅ ✅ ✅
iOS 13.0 Apple Vision ✅ ✅ ✅
macOS 10.15 Apple Vision ✅ ✅ ✅
Windows 10 WinRT OCR ❌ ❌ ✅
Linux Any Tesseract OCR ❌ ❌ ❌

Flutter Compatibility

Requires Flutter 3.19.0+ (Dart SDK >=3.2.4 <4.0.0)

License

MIT License — see LICENSE for details.

Libraries

flutter_ocr_native