flutter_ocr_native 0.3.8
flutter_ocr_native: ^0.3.8 copied to clipboard
Flutter plugin for on-device OCR using ML Kit (Android), Vision (iOS/macOS), WinRT (Windows), Tesseract (Linux). Document parsing, validation, and masking.
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
DocumentDetailsmodel — 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}');
}
Document Search #
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')
Smart Search #
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.