Chapter 8: MainPage (Sample App)
April 25, 2025 ยท View on GitHub
In the previous chapter, we explored the UseOcr extension method, which provides a modern way to integrate OCR functionality into your MAUI applications. Now, let's see how all these concepts come together in a real-world application by exploring the sample app's MainPage.
Introduction to the Sample App
Imagine you've just learned about a powerful new tool, but you're not quite sure how to use it in practice. That's where a sample app comes in! The MainPage in our OCR sample app serves as a practical demonstration of how to use the OCR library in a real application.
Think of it like a test drive at a car dealership - it gives you a chance to see the OCR library in action before you implement it in your own app.
Understanding the Sample App Through an Analogy
Think of the sample app as a cooking show:
- The chef (the sample app) demonstrates how to use various kitchen tools (OCR features)
- The audience (you, the developer) watches to learn techniques
- The recipe (the code) is available for you to replicate later
- The finished dish (the working app) shows what's possible with these tools
Key Features of the Sample App
The MainPage of our sample app demonstrates several important features:
- Image Capture: Taking photos with the device camera
- File Selection: Choosing existing images from the device
- Text Recognition: Extracting text from images
- Image Preprocessing: Enhancing images to improve OCR accuracy
- Results Display: Showing the recognized text to the user
Let's explore each of these features one by one.
The User Interface
First, let's take a look at the basic structure of the MainPage:
public partial class MainPage
{
private readonly IOcrService _ocr;
private byte[] _originalImageData;
private byte[] _preprocessedImageData;
public MainPage(IOcrService feature)
{
InitializeComponent();
_ocr = feature;
}
protected override async void OnAppearing()
{
base.OnAppearing();
await _ocr.InitAsync();
}
// Other methods...
}
This code shows the basic structure of the MainPage class:
- It has a private field
_ocrto hold the OCR service - It accepts the OCR service through its constructor (dependency injection)
- It initializes the OCR service when the page appears
The UI is divided into several sections:
- A tab control to switch between camera and file input
- Buttons to capture or select images
- A preview area to display the selected image
- A results area to display the recognized text
- Controls for image preprocessing
Capturing Images from the Camera
One of the main features of the sample app is the ability to capture images using the device's camera:
private async void OpenFromCameraBtn_Clicked(object sender, EventArgs e)
{
if (MediaPicker.Default.IsCaptureSupported)
{
var photo = await MediaPicker.Default.CapturePhotoAsync();
if (photo == null)
{
return;
}
var result = await ProcessPhoto(photo);
ResultLbl.Text = result.AllText;
NoImagePlaceholder.IsVisible = false;
}
else
{
await DisplayAlert("Sorry", "Image capture is not supported on this device.", "OK");
}
}
This code:
- Checks if the device supports capturing photos
- Opens the camera to take a photo
- Processes the photo using the OCR service
- Displays the recognized text in the results area
Selecting Images from Files
The sample app also allows users to select existing images from their device:
private async void OpenFromFileBtn_Clicked(object sender, EventArgs e)
{
var photo = await MediaPicker.Default.PickPhotoAsync();
if (photo != null)
{
var result = await ProcessPhoto(photo);
ResultLbl.Text = result.AllText;
NoImagePlaceholder.IsVisible = false;
}
}
This code:
- Opens the file picker to select a photo
- Processes the selected photo using the OCR service
- Displays the recognized text in the results area
Processing Photos
Both the camera and file selection features use a common method to process photos:
private async Task<OcrResult> ProcessPhoto(FileResult photo)
{
try
{
ShowLoading("Reading image...");
// Open a stream to the photo
await using var sourceStream = await photo.OpenReadAsync();
// Create a byte array to hold the image data
_originalImageData = new byte[sourceStream.Length];
// Read the stream into the byte array
var dataLength = await sourceStream.ReadAsync(_originalImageData);
ShowLoading("Preprocessing image...");
_preprocessedImageData = await PreprocessImageForOcr(_originalImageData);
await DisplayImage(_preprocessedImageData);
var options = new OcrOptions.Builder()
.SetTryHard(TryHardSwitch.IsToggled)
.Build();
// Process the image data using the OCR service
ShowLoading("Extracting text...");
return await _ocr.RecognizeTextAsync(_preprocessedImageData, options);
}
finally
{
HideLoading();
}
}
This code:
- Shows a loading indicator with a message
- Opens a stream to the selected photo
- Reads the photo data into a byte array
- Preprocesses the image to improve OCR accuracy
- Displays the preprocessed image in the preview area
- Creates OCR options based on user settings
- Processes the image using the OCR service
- Hides the loading indicator and returns the result
Image Preprocessing
One of the most important features of the sample app is image preprocessing, which can significantly improve OCR accuracy:
private static async Task<byte[]> PreprocessImageForOcr(byte[] imageData)
{
await using var ms = new MemoryStream(imageData);
using var image = await Image.LoadAsync<L8>(ms);
// Resize large images to improve processing speed
const int MaxDimension = 1500;
if (image.Width > MaxDimension || image.Height > MaxDimension)
{
var ratio = Math.Min((float)MaxDimension / image.Width,
(float)MaxDimension / image.Height);
var newWidth = (int)(image.Width * ratio);
var newHeight = (int)(image.Height * ratio);
image.Mutate(x => x.Resize(newWidth, newHeight));
}
// Apply preprocessing steps
image.Mutate(x => x
.Contrast(1.2f) // Boost contrast
.GaussianBlur(1.1f) // Slight blur to reduce noise
.BinaryThreshold(0.45f) // Convert to black and white
);
// Convert back to byte array
using var resultMs = new MemoryStream();
await image.SaveAsPngAsync(resultMs);
return resultMs.ToArray();
}
This code:
- Loads the image from the byte array
- Resizes large images to improve processing speed
- Applies several preprocessing steps:
- Increases contrast to make text more visible
- Applies a slight blur to reduce noise
- Converts the image to black and white
- Saves the preprocessed image back to a byte array
Advanced Image Enhancement
The sample app also includes a button to apply more advanced image enhancement techniques:
private async void EnhanceImageBtn_Clicked(object sender, EventArgs e)
{
try
{
if (_originalImageData == null)
{
return;
}
ShowLoading("Enhancing image...");
EnhanceImageBtn.IsEnabled = false;
try
{
// Apply advanced preprocessing
_preprocessedImageData = ApplyAdvancedPreprocessing(_originalImageData);
// Display the enhanced image
await DisplayImage(_preprocessedImageData);
// Re-run OCR on the enhanced image
ShowLoading("Running OCR on enhanced image...");
var options = new OcrOptions.Builder()
.SetTryHard(TryHardSwitch.IsToggled)
.Build();
var result = await _ocr.RecognizeTextAsync(_preprocessedImageData, options);
// Update the results
ResultLbl.Text = result.AllText;
}
finally
{
EnhanceImageBtn.IsEnabled = true;
}
}
finally
{
HideLoading();
}
}
This code:
- Checks if an image has been loaded
- Shows a loading indicator and disables the enhance button
- Applies advanced preprocessing to the original image
- Displays the enhanced image in the preview area
- Runs OCR on the enhanced image
- Updates the results with the new recognized text
- Re-enables the enhance button and hides the loading indicator
Using Events for Asynchronous Recognition
The sample app also demonstrates how to use events for asynchronous OCR recognition:
private async void OpenFromCameraUseEventBtn_Clicked(object sender, EventArgs e)
{
if (MediaPicker.Default.IsCaptureSupported)
{
var photo = await MediaPicker.Default.CapturePhotoAsync();
if (photo == null)
{
return;
}
_ocr.RecognitionCompleted += OnRecognitionCompleted;
await StartProcessingPhoto(photo);
}
else
{
await DisplayAlert("Sorry", "Image capture is not supported on this device.", "OK");
}
}
private void OnRecognitionCompleted(object sender, OcrCompletedEventArgs e)
{
// Remove the event handler to avoid multiple subscriptions
_ocr.RecognitionCompleted -= OnRecognitionCompleted;
// Update UI on the main thread
MainThread.BeginInvokeOnMainThread(() =>
{
ResultLbl.Text = e is { IsSuccessful: true, Result: not null }
? e.Result.AllText
: $"Error: {(!string.IsNullOrEmpty(e.ErrorMessage) ? e.ErrorMessage : "Unknown")}";
NoImagePlaceholder.IsVisible = false;
});
}
This code:
- Captures a photo using the device's camera
- Subscribes to the
RecognitionCompletedevent of the OCR service - Starts processing the photo asynchronously
- When recognition completes, updates the UI with the results
How the Sample App Works Behind the Scenes
When you use the sample app to recognize text in an image, here's what happens:
sequenceDiagram
participant User
participant UI as MainPage UI
participant MP as MainPage Code
participant OCR as OCR Service
participant PP as Image Preprocessing
User->>UI: Tap "Open Camera"
UI->>MP: OpenFromCameraBtn_Clicked()
MP->>User: Open camera
User->>MP: Take photo
MP->>PP: PreprocessImageForOcr()
PP-->>MP: Return preprocessed image
MP->>UI: Display preprocessed image
MP->>OCR: RecognizeTextAsync()
OCR-->>MP: Return OcrResult
MP->>UI: Display recognized text
UI->>User: Show results
- The user taps the "Open Camera" button
- The app opens the device's camera
- The user takes a photo
- The app preprocesses the image to improve OCR accuracy
- The app displays the preprocessed image in the preview area
- The app sends the preprocessed image to the OCR service
- The OCR service recognizes text in the image
- The app displays the recognized text in the results area
Putting It All Together
The sample app demonstrates how to use all the components of the OCR library together:
- It uses the IOcrService Interface to access OCR functionality
- It receives OcrResult objects containing the recognized text
- It creates OcrOptions to customize the OCR process
- It indirectly uses OcrPatternMatcher through the OCR options
- It relies on the platform-specific OcrImplementation behind the scenes
- It can access the OCR service through OcrPlugin or the UseOcr Extension Method
Learning from the Sample App
The sample app is designed to be a learning tool. Here are some ways you can use it to learn about OCR:
- Run the app: Install and run the sample app on your device to see OCR in action
- Experiment with different images: Try scanning different types of text to see how well OCR works
- Try different preprocessing options: See how image preprocessing affects OCR accuracy
- Read the code: Study the sample app's code to understand how to implement OCR in your own app
- Modify the app: Make changes to the sample app to experiment with different features
Implementing OCR in Your Own App
Now that you've seen how the sample app uses OCR, you can implement similar functionality in your own app:
- Add the OCR library to your app using NuGet
- Register the OCR service using the UseOcr Extension Method
- Inject the IOcrService Interface into your pages or view models
- Add UI for capturing or selecting images
- Process images using the OCR service
- Display the recognized text to the user
Conclusion
In this chapter, we've explored the MainPage of the sample app, which demonstrates how to use the OCR library in a real application. We've seen how to capture images from the camera, select images from files, preprocess images to improve OCR accuracy, and display the recognized text to the user.
The sample app serves as a practical example of how to use all the components of the OCR library together, from the IOcrService Interface to the OcrResult and OcrOptions. By studying and experimenting with the sample app, you can learn how to implement OCR in your own applications.
Now that you've completed all the chapters in this tutorial, you have a solid understanding of how to use the OCR library in your own applications. You can refer back to specific chapters as needed when implementing OCR features in your projects.
Key Takeaways
- The sample app demonstrates how to use the OCR library in a real application
- It shows how to capture images from the camera and select images from files
- It demonstrates how to preprocess images to improve OCR accuracy
- It shows how to display the recognized text to the user
- It serves as a practical example of how to use all the components of the OCR library together
- You can learn from the sample app by running it, experimenting with it, and studying its code
Generated by AI Codebase Knowledge Builder