Building an Emirates ID Card Scanner App with Flutter and Google ML Kit

Mohamed Abdo Elnashar
Flutter UAE
Published in
7 min readApr 19, 2023
form google

Building an Emirates ID Card Scanner App with Flutter and Google ML Kit can be a useful and practical application for individuals or organizations in the United Arab Emirates (UAE). This app can extract information from Emirates ID cards such as the holder’s name, nationality, sex, ID number, date of birth, issue date, and expiry date. The app can use the camera to capture an image of the Emirates ID card and then process the image using Google ML Kit to extract the relevant information from the card. This can save time and effort for organizations that require Emirates ID verification, and can also be a convenient way for individuals to retrieve their ID information when needed. In this project, we will use Flutter, a popular cross-platform mobile development framework, and Google ML Kit, a machine learning library, to build an Emirates ID Card Scanner App.

To get started, we need to set up our Flutter project and add the Google ML Kit to our dependencies. We can do this by adding the following lines to our project’s pubspec.yaml file:

dependencies:
flutter:
sdk: flutter
google_ml_kit: ^0.3.0

After adding the dependencies, we can run flutter pub get in the terminal to install them.

Next, we need to create the UI for our app. We can use the ImagePicker package in Flutter to create a camera preview widget, and a button that triggers the EID card scanning process. When the user clicks on the button, the app will capture an image of the EID card using the device's camera, and then use Google ML Kit to extract the biometric data from the captured image.

Here’s some sample code for the UI:

import 'package:flutter/material.dart';
import 'package:google_ml_kit/google_ml_kit.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('EID Card Scanner'),
),
body: Center(
child: ElevatedButton(
onPressed: _scanEIDCard,
child: Text('Scan EID Card'),
),
),
),
);
}
void _scanEIDCard() async {
try {
final image = await ImagePicker.pickImage(source: ImageSource.camera);
final data = await EIDScanner.scanEmirateId(image: File(img.path));
if (data != null) {
print(data.toString());
}
} catch (e) {
print(e);
}
}
}

In the _scanEIDCard method, we first use the ImagePicker package to capture an image of the EID card. We then create an InputImage object from the captured image and pass it to the IdCardScanner class from Google ML Kit. The processImage method of the IdCardScanner class returns an IdCard object that contains the extracted biometric data from the EID card.

Finally, we can extract the biometric data from the IdCard object and use it for further processing, such as verifying the user's identity or performing authentication.

EIDScanner class service

class EIDScanner and a data model class EmirateIdModel for an app that scans Emirate ID cards in the United Arab Emirates using Flutter and Google ML Kit.

The EIDScanner class has a static method scanEmirateId() that takes a File object representing an image of an Emirate ID card and returns an EmirateIdModel object with the information extracted from the card.

/// this method will process the images and extract information from the card
static Future<EmirateIdModel?> scanEmirateId({
required File image,
}) async {
List<String> eIdDates = [];
// GoogleMlKit.vision.languageModelManager();
TextRecognizer textDetector = GoogleMlKit.vision.textRecognizer();
final RecognizedText recognisedText = await textDetector.processImage(
InputImage.fromFilePath(image.path),
);

// to check it is Emirate Card
if (!recognisedText.text
.toString()
.toLowerCase()
.contains("Resident ldentity Card".toLowerCase()) &&
!recognisedText.text
.toString()
.toLowerCase()
.contains("UNITED ARAB EMIRATES".toLowerCase())) {
//throw "Invalid Emirate Card";
return null;
}

final listText = recognisedText.text.split('\n');

// attributes
String? name;
String? number;
String? nationality;
String? sex;

listText.forEach((element) {
if (_isDate(text: element.trim())) {
eIdDates.add(element.trim());
} else if (_isName(text: element.trim()) != null) {
name = _isName(text: element.trim());
} else if (_isNationality(text: element.trim()) != null) {
nationality = _isNationality(text: element.trim());
} else if (_isSex(text: element.trim()) != null) {
sex = _isSex(text: element.trim());
} else if (_isNumberID(text: element.trim())) {
number = element.trim();
}
});

eIdDates = _sortDateList(dates: eIdDates);

textDetector.close();

return EmirateIdModel(
name: name!,
number: number!,
nationality: nationality,
sex: sex,
dateOfBirth: eIdDates.length == 3 ? eIdDates[0] : null,
issueDate: eIdDates.length == 3 ? eIdDates[1] : null,
expiryDate: eIdDates.length == 3 ? eIdDates[2] : null,
);
}

The scanEmirateId() method first creates a TextRecognizer object from Google ML Kit and processes the image with the processImage() method to extract the text from the image. Then, it checks if the text contains specific keywords to ensure that the card is an Emirate ID card. If the check fails, it returns null. Otherwise, it processes the text to extract the cardholder's name, ID number, nationality, sex, and dates of birth, issue, and expiry. The isDate(), isSex(), isName(), isNationality(), and isNumberID() methods are used to extract the specific fields from the text. The _sortDateList() method is used to sort the list of dates extracted from the text.

/// it will sort the dates
static List<String> _sortDateList({required List<String> dates}) {
List<DateTime> tempList = [];
DateFormat format = DateFormat("dd/MM/yyyy");
for (int i = 0; i < dates.length; i++) {
tempList.add(format.parse(dates[i]));
}
tempList.sort((a, b) => a.compareTo(b));
dates.clear();
for (int i = 0; i < tempList.length; i++) {
dates.add(format.format(tempList[i]));
}
return dates;
}

/// it will sort the dates
static bool _isDate({required String text}) {
RegExp pattern = RegExp(r'^\d{2}/\d{2}/\d{4}$');
return pattern.hasMatch(text);
}

/// it will get the value of sex
static String? _isSex({required String text}) {
return text.startsWith("Sex:") ? text.split(":").last.trim() : null;
}

/// it will get the value of name
static String? _isName({required String text}) {
return text.startsWith("Name:") ? text.split(":").last.trim() : null;
}

/// it will get the value of Nationality
static String? _isNationality({required String text}) {
return text.startsWith("Nationality:") ? text.split(":").last.trim() : null;
}

/// it will get the value of Number ID
static bool _isNumberID({required String text}) {
RegExp pattern = RegExp(r'^\d{3}-\d{4}-\d{7}-\d{1}$');
return pattern.hasMatch(text);
}

The EmirateIdModel class is a data model that represents the extracted information from the Emirate ID card. It has properties name, number, issueDate, expiryDate, dateOfBirth, nationality, and sex that correspond to the information extracted from the card. It also has a toString() method that formats the data into a readable string for display on the user's screen.

Class Service Implementation

import 'dart:developer';
import 'dart:io';
import 'package:google_ml_kit/google_ml_kit.dart';
import 'package:intl/intl.dart';

class EIDScanner {
/// this method will process the images and extract information from the card
static Future<EmirateIdModel?> scanEmirateId({
required File image,
}) async {
List<String> eIdDates = [];
// GoogleMlKit vision languageModelManager
TextRecognizer textDetector = GoogleMlKit.vision.textRecognizer();
final RecognizedText recognisedText = await textDetector.processImage(
InputImage.fromFilePath(image.path),
);

// to check it is Emirate Card
if (!recognisedText.text
.toString()
.toLowerCase()
.contains("Resident ldentity Card".toLowerCase()) &&
!recognisedText.text
.toString()
.toLowerCase()
.contains("UNITED ARAB EMIRATES".toLowerCase())) {
//throw "Invalid Emirate Card";
return null;
}

final listText = recognisedText.text.split('\n');

// attributes
String? name;
String? number;
String? nationality;
String? sex;

listText.forEach((element) {
if (_isDate(text: element.trim())) {
eIdDates.add(element.trim());
} else if (_isName(text: element.trim()) != null) {
name = _isName(text: element.trim());
} else if (_isNationality(text: element.trim()) != null) {
nationality = _isNationality(text: element.trim());
} else if (_isSex(text: element.trim()) != null) {
sex = _isSex(text: element.trim());
} else if (_isNumberID(text: element.trim())) {
number = element.trim();
}
});

eIdDates = _sortDateList(dates: eIdDates);

textDetector.close();

return EmirateIdModel(
name: name!,
number: number!,
nationality: nationality,
sex: sex,
dateOfBirth: eIdDates.length == 3 ? eIdDates[0] : null,
issueDate: eIdDates.length == 3 ? eIdDates[1] : null,
expiryDate: eIdDates.length == 3 ? eIdDates[2] : null,
);
}

/// it will sort the dates
static List<String> _sortDateList({required List<String> dates}) {
List<DateTime> tempList = [];
DateFormat format = DateFormat("dd/MM/yyyy");
for (int i = 0; i < dates.length; i++) {
tempList.add(format.parse(dates[i]));
}
tempList.sort((a, b) => a.compareTo(b));
dates.clear();
for (int i = 0; i < tempList.length; i++) {
dates.add(format.format(tempList[i]));
}
return dates;
}

/// it will sort the dates
static bool _isDate({required String text}) {
RegExp pattern = RegExp(r'^\d{2}/\d{2}/\d{4}$');
return pattern.hasMatch(text);
}

/// it will get the value of sex
static String? _isSex({required String text}) {
return text.startsWith("Sex:") ? text.split(":").last.trim() : null;
}

/// it will get the value of name
static String? _isName({required String text}) {
return text.startsWith("Name:") ? text.split(":").last.trim() : null;
}

/// it will get the value of Nationality
static String? _isNationality({required String text}) {
return text.startsWith("Nationality:") ? text.split(":").last.trim() : null;
}

/// it will get the value of Number ID
static bool _isNumberID({required String text}) {
RegExp pattern = RegExp(r'^\d{3}-\d{4}-\d{7}-\d{1}$');
return pattern.hasMatch(text);
}
}

/// this class is used to store data from package and display data on user screen

class EmirateIdModel {
late String name;
late String number;
late String? issueDate;
late String? expiryDate;
late String? dateOfBirth;
late String? nationality;
late String? sex;

EmirateIdModel({
required this.name,
required this.number,
this.issueDate,
this.expiryDate,
this.dateOfBirth,
this.nationality,
this.sex,
});

@override
String toString() {
var string = '';
string += name.isEmpty ? "" : 'Holder Name = $name\n';
string += number.isEmpty ? "" : 'Number = $number\n';
string += expiryDate == null ? "" : 'Expiry Date = $expiryDate\n';
string += issueDate == null ? "" : 'Issue Date = $issueDate\n';
string += expiryDate == null ? "" : 'Cnic Holder DoB = $expiryDate\n';
string += nationality == null ? "" : 'Nationality = $nationality\n';
string += sex == null ? "" : 'Sex = $sex\n';
return string;
}
}

In conclusion, the development of the Emirates ID Card Scanner app using Flutter and Google ML Kit is a great example of how powerful and accessible machine learning technology has become. By leveraging the capabilities of Google ML Kit, we were able to quickly and easily develop an application that could accurately scan and extract information from Emirati ID cards. The app has the potential to streamline processes that require ID verification and improve the user experience of services that require ID verification. Furthermore, this project highlights the potential of machine learning in mobile app development and provides an excellent starting point for anyone looking to incorporate machine learning into their Flutter projects.

I hope you all liked this blog and it helped you get started with Flutter! Don’t forget to smash that clap button and leave a comment down below.

Meet you at the next one.

--

--

Mohamed Abdo Elnashar
Flutter UAE

Senior Flutter Developer, and I study a master of computer science in the faculty of computer & information sciences at Mansoura university