DEV Community

Xiao Ling
Xiao Ling

Posted on • Originally published at dynamsoft.com

How to Create an MRZ Scanner App for Android and iOS with .NET MAUI

Creating a mobile app that scans and decodes Machine Readable Zones (MRZs) is essential for many industries, including travel, security, and identification verification. With .NET MAUI (Multi-platform App UI), developers can build cross-platform applications for Android and iOS using a single codebase, streamlining development and maintenance. In this tutorial, we’ll demonstrate how to leverage .NET MAUI alongside the Dynamsoft Capture Vision MAUI Bundle to create an MRZ scanner app with ease.

.NET MAUI MRZ Scanner Demo Video

Prerequisites

To get started, ensure you have the following tools installed:

  • Dynamsoft Capture Vision Trial License
  • Xcode
  • Android Studio
  • Visual Studio for Windows or Visual Studio Code for macOS with the .NET MAUI extension
  • Provisioning Profile for iOS (required if building a .NET MAUI app with Visual Studio Code on macOS):
    1. Log into your Apple Developer account.
    2. Navigate to Certificates, Identifiers & Profiles to create an App ID and Provisioning Profile.
    3. Download the *.mobileprovision file and copy it to the ~/Library/MobileDevice/Provisioning Profiles folder.

Getting Started with the Official MRZ Scanner Sample

Dynamsoft’s GitHub page offers several .NET MAUI samples, including those for barcode reading, document normalization, and MRZ recognition.

Dynamsoft MAUI samples

To get started, clone the MRZ MAUI sample project from the GitHub repository:

git clone https://github.com/Dynamsoft/mrz-scanner-mobile-maui.git
Enter fullscreen mode Exit fullscreen mode

This project is configured for .NET 7.0. To update the target framework to .NET 8.0:

  1. Open the .csproj file and change the TargetFramework value from net7.0 to net8.0.
  2. Add <SupportedOSPlatformVersion> to the PropertyGroup element to ensure compatibility:

    <PropertyGroup Condition="$(TargetFramework.Contains('-ios'))">
        <SupportedOSPlatformVersion>11.0</SupportedOSPlatformVersion>
    </PropertyGroup>
    

The sample project includes basic MRZ scanning functionality. You can run the app on Android and iOS devices to test the MRZ recognition feature. In the following sections, we will examine the MRZ scanner app in detail and explain how it works.

Anatomy of the .NET MAUI MRZ Scanner App

The MRZ scanner app consists of three pages: MainPage, ScanPage, and ResultPage. The MainPage is the entry point of the app, where users can initiate the MRZ scanning process. The ScanPage performs real-time MRZ scanning using the camera stream, while the ResultPage displays the MRZ information extracted from the recognized MRZ strings.

MainPage

The MainPage contains a button that navigates to the ScanPage.

MainPage.xml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage NavigationPage.HasNavigationBar="False"
             NavigationPage.HasBackButton="False"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             Title=""
             BackgroundColor="#323234"
             x:Class="mrz_scanner_mobile_maui.MainPage">
    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            VerticalOptions="Start"
            Padding="30,130">

            <Button
                x:Name="NavigationBtn"
                Text="Scan an MRZ"
                FontSize="16"
                WidthRequest="180"
                BackgroundColor="#FE8E14"
                Clicked="OnNavigationBtnClicked"
                HorizontalOptions="Center" />

        </VerticalStackLayout>


    </ScrollView>

</ContentPage>
Enter fullscreen mode Exit fullscreen mode

MainPage.xaml.cs

namespace mrz_scanner_mobile_maui;

public partial class MainPage : ContentPage
{

    public MainPage()
    {
        InitializeComponent();
    }

    private async void OnNavigationBtnClicked(object sender, EventArgs e)
    {
        await Navigation.PushAsync(new ScanPage());

    }

}
Enter fullscreen mode Exit fullscreen mode

ScanPage

The ScanPage starts a camera preview with the CameraView control provided by the Dynamsoft Capture Vision SDK. Here’s the ScanPage.xml file:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage 
    Shell.NavBarIsVisible="False"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:controls="clr-namespace:Dynamsoft.CameraEnhancer.Maui;assembly=Dynamsoft.CameraEnhancer.Maui"
    Title=""
    x:Class="mrz_scanner_mobile_maui.ScanPage">
    <AbsoluteLayout>
        <controls:CameraView x:Name="camera"
                             AbsoluteLayout.LayoutBounds="0,0,1,1"
                             AbsoluteLayout.LayoutFlags="All">
        </controls:CameraView>

        ...
    </AbsoluteLayout>
</ContentPage>

Enter fullscreen mode Exit fullscreen mode

The CameraView is connected to a CameraEnhancer object, which serves as the input source for the CaptureVisionRouter object. The CaptureVisionRouter processes the camera stream and recognizes MRZ strings, returning results through callback events.

Here's the code snippet from the ScanPage.xaml.cs file:

  • Set the license key for the Dynamsoft Capture Vision SDK and instantiate CameraEnhancer and CaptureVisionRouter in the constructor.

    public ScanPage()
    {
        InitializeComponent();
        LicenseManager.InitLicense("LICENSE-KEY", this);
        currentTemplate = "ReadPassportAndId";
        enhancer = new CameraEnhancer();
        router = new CaptureVisionRouter();
    }
    
  • Bind the CameraView to the CameraEnhancer object:

    protected override void OnHandlerChanged()
    {
        base.OnHandlerChanged();
        if (this.Handler != null)
        {
            enhancer.SetCameraView(camera);
            enhancer.EnableEnhancedFeatures(EnumEnhancedFeatures.EF_FRAME_FILTER);
        }
    }
    
  • Register callback events for MRZ recognition and start camera capturing in the OnAppearing event handler:

    void OnParsedResultReceived(ParsedResult result)
    {
        if (result.Items == null)
        {
            return;
        }
        ImageData data = router.GetIntermediateResultManager().GetOriginalImage(result.OriginalImageHashId);
    
        Dictionary<String, String> labelMap = AssembleMap(result.Items[0]);
        if (labelMap != null && labelMap.Count != 0)
        {
            MainThread.BeginInvokeOnMainThread(() =>
            {
                Navigation.PushAsync(new ResultPage(labelMap, data));
                ClearText();
            });
    
        }
    }
    
    protected override async void OnAppearing()
    {
        base.OnAppearing();
        beepStatus = Preferences.Default.Get("status", true);
        UpdateBackground();
        await Permissions.RequestAsync<Permissions.Camera>();
        MultiFrameResultCrossFilter filter = new MultiFrameResultCrossFilter();
        filter.EnableResultCrossVerification(EnumCapturedResultItemType.CRIT_TEXT_LINE, true);
        router?.AddResultFilter(filter);
        try
        {
            router.SetInput(enhancer);
        }
        catch (Exception e)
        {
            e.GetBaseException();
        }
        router.AddResultReceiver(this);
        restartCapture();
        enhancer?.SetColourChannelUsageType(EnumColourChannelUsageType.CCUT_FULL_CHANNEL);
        enhancer?.Open();
    }
    

    When a recognized result is returned, a corresponding image is stored in the CaptureVisionRouter object. By default, the image is converted to grayscale. To retain the original color, call SetColourChannelUsageType method with CCUT_FULL_CHANNEL before starting camera capture.

ResultPage

The ResultPage displays the MRZ information extracted from the recognized MRZ strings in a ScrollView.

The ResultPage.xaml file is as follows:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="mrz_scanner_mobile_maui.ResultPage"
             BackgroundColor="#3B3B3B"
             Title="ResultPage">


    <ScrollView x:Name="ScrollView">
        <VerticalStackLayout x:Name="VerticalLayout"
                             Padding="30">
        </VerticalStackLayout>

    </ScrollView>

</ContentPage>
Enter fullscreen mode Exit fullscreen mode

The ResultPage.xaml.cs file populates the VerticalStackLayout with MRZ information extracted from recognized MRZ strings. It also displays an image of the scanned document.

namespace mrz_scanner_mobile_maui;

using Dynamsoft.Core.Maui;

public partial class ResultPage : ContentPage
{
    public ResultPage(Dictionary<String, String> labelMap, ImageData imageData)
    {
        InitializeComponent();
        if (labelMap.Count > 0)
        {
            VerticalLayout.Add(ChildView("Document Type:", labelMap["Document Type"]));
            VerticalLayout.Add(ChildView("Document Number:", labelMap["Document Number"]));
            VerticalLayout.Add(ChildView("Full Name:", labelMap["Name"]));
            VerticalLayout.Add(ChildView("Sex:", labelMap["Sex"].First().ToString().ToUpper()));
            VerticalLayout.Add(ChildView("Age:", labelMap["Age"]));
            VerticalLayout.Add(ChildView("Issuing State:", labelMap["Issuing State"]));
            VerticalLayout.Add(ChildView("Nationality:", labelMap["Nationality"]));
            VerticalLayout.Add(ChildView("Date of Birth(YYYY-MM-DD):", labelMap["Date of Birth(YY-MM-DD)"]));
            VerticalLayout.Add(ChildView("Date of Expiry(YYYY-MM-DD):", labelMap["Date of Expiry(YY-MM-DD)"]));

            var imageControl = new Image
            {
                HeightRequest = 400,
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center,
            };
            imageControl.Source = imageData.ToImageSource();
            VerticalLayout.Add(imageControl);
        }
    }

    IView ChildView(string label, string text)
    {
        return new VerticalStackLayout
            {
                new Label
                {
                    Text = label,
                    TextColor = Color.FromArgb("AAAAAA"),
                    FontSize = 16,
                    Padding = new Thickness(0, 20, 0, 0),
                },
                new Entry
                {
                    Text = text,
                    TextColor = Colors.White,
                    FontSize = 16,
                    BackgroundColor = Colors.Transparent, 
                    IsReadOnly = false, 
                }
            };

    }
}

Enter fullscreen mode Exit fullscreen mode

Running the .NET MAUI MRZ Scanner

  1. Scan the machine-readable zone (MRZ) on a passport or ID card.

    .NET MAUI MRZ recognition

  2. Extract MRZ information from the scanned document.

    .NET MAUI MRZ scanner

Source Code

https://github.com/yushulx/maui-barcode-mrz-document-scanner/tree/main/examples/MrzScanner

Top comments (0)