itc_scanner 0.0.4 copy "itc_scanner: ^0.0.4" to clipboard
itc_scanner: ^0.0.4 copied to clipboard

Flutter plugin for extracting data from Ghana vehicle licensing documents using ML Kit text recognition. Simple integration for cross-platform document scanning.

ITC Scanner #

A Flutter plugin for extracting data from Ghana vehicle documents using ML Kit text recognition and advanced AI processing.

Features #

  • 🚗 Extract data from Ghana driver and vehicle licensing authority documents (Road Worthy)
  • 📋 Extract data from Ghana vehicle registration forms (Registration Particulars)
  • 📱 Cross-platform support (Android/iOS)
  • 🔧 Simple integration with image bytes input
  • 📊 Structured output with confidence scores
  • Direct key-value access for easy third-party integration
  • 🛡️ Robust error handling for production use

Screenshots #

iOS - Document Scanning iOS - Extraction Results
[iOS Scanning] [iOS Results]
iOS - App Interface Android - Full Experience
[iOS Interface] [Android]

Cross-platform support - works on both iOS and Android

Installation #

dependencies:
  itc_scanner: ^0.0.4
flutter pub get

Usage #

Basic Usage #

import 'package:itc_scanner/itc_scanner.dart';
import 'dart:typed_data';

final scanner = ItcScanner();

// Extract Registration Particulars (uses advanced KIT processing)
Future<void> scanRegistrationForm(Uint8List imageBytes) async {
  try {
    final result = await scanner.extractDocument(
      imageBytes, 
      extractionKey: 'itc_reg_form'
    );
    
    if (result?['success'] == true) {
      // Easy direct access
      final regNumber = result!['data']['reg_number'];
      final make = result['data']['make'];
      final owner = result['data']['owner'];
      
      print('Registration: $regNumber');
      print('Make: $make');
      print('Owner: $owner');
    }
  } catch (e) {
    print('Error: $e');
  }
}

// Extract Driver Vehicle Licenses (Road Worthy) (uses local Kit)
Future<void> scanRoadWorthy(Uint8List imageBytes) async {
  try {
    final result = await scanner.extractDocument(imageBytes);
    
    if (result?['success'] == true) {
      // Easy direct access
      final regNumber = result!['data']['reg_number'];
      final make = result['data']['make'];
      final documentId = result['data']['document_id'];
      
      print('Registration: $regNumber');
      print('Make: $make');
      print('Document ID: $documentId');
    }
  } catch (e) {
    print('Error: $e');
  }
}

Complete Example with Image Picker #

import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:itc_scanner/itc_scanner.dart';
import 'dart:typed_data';
import 'dart:io';

class DocumentScannerWidget extends StatefulWidget {
  @override
  _DocumentScannerWidgetState createState() => _DocumentScannerWidgetState();
}

class _DocumentScannerWidgetState extends State<DocumentScannerWidget> {
  final _scanner = ItcScanner();
  final _picker = ImagePicker();
  Map<String, dynamic>? _result;
  bool _isLoading = false;

  Future<void> _scanRegistrationForm() async {
    final XFile? image = await _picker.pickImage(
      source: ImageSource.camera,
      maxWidth: 1024,
      maxHeight: 1024,
      imageQuality: 90,
    );
    
    if (image != null) {
      await _processImage(File(image.path), isRegistration: true);
    }
  }

  Future<void> _scanRoadWorthy() async {
    final XFile? image = await _picker.pickImage(
      source: ImageSource.camera,
      maxWidth: 1024,
      maxHeight: 1024,
      imageQuality: 90,
    );
    
    if (image != null) {
      await _processImage(File(image.path), isRegistration: false);
    }
  }

  Future<void> _processImage(File imageFile, {required bool isRegistration}) async {
    setState(() => _isLoading = true);
    
    try {
      final Uint8List imageBytes = await imageFile.readAsBytes();
      final result = await _scanner.extractDocument(
        imageBytes,
        extractionKey: isRegistration ? 'itc_reg_form' : null,
      );
      
      setState(() => _result = result);
      
      // Direct data access
      if (result?['success'] == true) {
        final data = result!['data'] as Map<String, dynamic>;
        print('Registration Number: ${data['reg_number']}');
        print('Make: ${data['make']}');
        
        if (isRegistration) {
          print('Owner: ${data['owner']}');
          print('Color: ${data['colour']}');
        } else {
          print('Document ID: ${data['document_id']}');
          print('Expiry: ${data['expiry_date']}');
        }
      }
    } catch (e) {
      print('Error: $e');
    } finally {
      setState(() => _isLoading = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ElevatedButton(
          onPressed: _isLoading ? null : _scanRegistrationForm,
          child: Text('Scan Registration Form'),
        ),
        ElevatedButton(
          onPressed: _isLoading ? null : _scanRoadWorthy,
          child: Text('Scan Road Worthy'),
        ),
        if (_result != null) ...[
          Text('Success: ${_result!['success']}'),
          Text('Processing Time: ${_result!['processingTime']}ms'),
          // Access data directly
          if (_result!['data'] != null)
            ...(_result!['data'] as Map<String, dynamic>).entries.map(
              (entry) => Text('${entry.key}: ${entry.value}'),
            ),
        ],
      ],
    );
  }
}

Response Format #

The plugin returns both detailed field information and direct key-value access:

{
  "success": true,
  "documentType": "VEHICLE_REGISTRATION",
  "processingTime": 1250,
  "fields": [
    {
      "label": "Registration Number",
      "value": "GE4019-23",
      "confidence": 0.95,
      "fieldType": "ID_NUMBER"
    }
  ],
  "data": {
    "reg_number": "GE4019-23",
    "make": "NISSAN",
    "colour": "SILVER",
    "owner": "STEPHANIE OTOO DANKWA"
  }
}

Direct Access Keys #

Registration Particulars (extractionKey: 'itc_reg_form') #

Perfect for vehicle registration forms with comprehensive vehicle and owner information:

final data = result['data'];
final regNumber = data['reg_number'];
final owner = data['owner'];
final postalAddress = data['postal_address'];
final resAddress = data['res_address'];
final make = data['make'];
final colour = data['colour'];
final model = data['model'];
final type = data['type'];
final chassisNumber = data['chassis_number'];
final countryOfOrigin = data['country_of_origin'];
final yearOfManufacturing = data['year_of_manufacturing'];
final numberOfAxles = data['number_of_axles'];
final numberOfWheels = data['number_of_wheels'];
final numberOfPersons = data['number_of_persons'];
final engineMake = data['engine_make'];
final engineCylinders = data['engine_number_of_clys'];
final engineCC = data['engine_cc'];
final horsepower = data['hp'];
final fuelType = data['fuel'];
final useType = data['use_private_or_commercial'];
final dateOfEntry = data['date_of_entry'];

Road Worthy Documents (no extractionKey) #

Perfect for driver and vehicle licensing authority documents:

final data = result['data'];
final regNumber = data['reg_number'];
final documentId = data['document_id'];
final make = data['make'];
final model = data['model'];
final colour = data['colour'];
final use = data['use'];
final expiryDate = data['expiry_date'];

Error Handling #

The plugin provides comprehensive error handling:

try {
  final result = await scanner.extractDocument(imageBytes);
  
  if (result?['success'] == true) {
    // Process successful extraction
    final data = result!['data'] as Map<String, dynamic>;
    // All keys are guaranteed to exist (may be empty strings)
  } else {
    // Handle extraction failure
    print('Extraction failed');
  }
} on Exception catch (e) {
  // Handle plugin errors
  if (e.toString().contains('INVALID_IMAGE')) {
    print('Invalid image format');
  } else if (e.toString().contains('EXTRACTION_FAILED')) {
    print('Could not extract document data');
  } else {
    print('Unexpected error: $e');
  }
}

Requirements #

  • Android: API 24+
  • iOS: 15.5+
  • Flutter: 3.3.0+

Field Types #

  • TEXT: General text (Make, Model, Color)
  • ID_NUMBER: Document identifiers
  • DATE: Date fields
  • NUMBER: Numeric values

Tips for Best Results #

  • Use good lighting when capturing documents
  • Keep document flat and properly aligned
  • Optimize image size: Use maxWidth: 1024, maxHeight: 1024, imageQuality: 90 for better performance
  • Recommended image size: 1024x1024 or higher (but not too large)
  • Smaller images = faster processing and better app performance
  • Choose the correct document type for optimal results

Integration Notes #

  • Empty Fields: All data keys are always present, returning empty strings for missing information
  • Cross-Platform: Identical response format on Android and iOS
  • Production Ready: Robust error handling for real-world usage
  • No Internet Required: Road Worthy extraction works completely offline

Support #

ITC Consortium Ghana
Email: apps@itconsortiumgh.com

License #

Proprietary - Internal use only

3
likes
120
points
112
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for extracting data from Ghana vehicle licensing documents using ML Kit text recognition. Simple integration for cross-platform document scanning.

Homepage

Topics

#ocr #document-scanning #ghana #vehicle-documents #ml-kit

Funding

Consider supporting this project:

www.itconsortiumgh.com

License

unknown (license)

Dependencies

flutter, google_mlkit_commons, plugin_platform_interface

More

Packages that depend on itc_scanner

Packages that implement itc_scanner