IRONSOFTWAREHOME
FILMY

Migracja z TesseractOcrMaui do IronOCR

Kannaopat Udonpant
Kannapat Udonpant
Updated: 1 sierpnia 2026

Ten przewodnik przeprowadza użytkownika przez kompletną migrację zTesseractOcrMauido IronOCR, zawierając praktyczne przykłady kodu "przed" i "po" dla każdego kroku. Jest on skierowany do programistów, którzy już zdecydowali się wyjść poza ograniczenia platformy MAUI i potrzebują systematycznej ścieżki do biblioteki, która działa identycznie w aplikacjach mobilnych, interfejsach API po stronie serwera, procesach działających w tle oraz funkcjach chmurowych. Nie jest wymagana wcześniejsza lektura artykułu porównawczego.

Dlaczego warto przejść z TesseractOcrMaui

TesseractOcrMaui powstał, aby wypełnić istniejącą lukę: istniejące opakowania .NET Tesseract nie były w stanie samodzielnie rozwiązać problemu interoperacyjności z platformami mobilnymi. W przypadku czystego prototypu MAUI bez śladu serwerowego wypełnia on tę lukę. Problemy pojawiają się w momencie, gdy produkt wykracza poza ten wąski zakres.

**Platformy docelowe wyłącznie dla MAUI uniemożliwiają współdzielenie kodu.**TesseractOcrMauizawiera cele dla net8.0-ios, net8.0-android i net8.0-windows — wszystkie to powiązania platformy MAUI. Pakiet nie zawiera net8.0, ani netstandard2.1, ani celu kompatybilnego z serwerem. Odwołanie do niego z biblioteki klas, projektu .NET Core lub funkcji Azure powoduje błąd kompilacji. Nie ma rozwiązania alternatywnego: architektura pakietu uniemożliwia jego uruchomienie poza hostem MAUI. Za każdym razem, gdy pojawia się wymóg OCR w kontekście innym niż MAUI, konieczne jest wprowadzenie i równoległe utrzymywanie drugiej biblioteki.

Obowiązkowe MAUI powiązanie przez wstrzykiwanie zależności. Wywołanie AddTesseractOcr() w MauiProgram.cs łączy ITesseract z dostawcą usług MAUI. Poza tym grafem DI nie ma metody fabrycznej, statycznego punktu wejścia ani konstruktóra. Oznacza to, że logika OCR nie może być wyodrębniona do przenośnej biblioteki klasowej — każda klasa, która przyjmuje ITesseract w swoim konstruktorze, jest przypisana do hosta aplikacji MAUI na cały okres jej życia.

Brak danych wejściowych w formacie PDF na żadnym poziomie. Dokumenty PDF są najpopularniejszym formatem skanowanych umów, faktur i dokumentów tożsamości.TesseractOcrMauiwyrzuca NotSupportedException przy każdym wejściu PDF. Przetwarzanie pliku PDF wymaga dodania oddzielnej biblioteki renderującej PDF, napisania kodu do wyodrębniania obrazów strona po stronie, zarządzania plikami tymczasowymi w pamięci podręcznej urządzenia oraz ich czyszczenia po każdym wywołaniu. To ponad 100 linii kodu infrastruktury, zanim zostanie wykonane pojedyncze wywołanie OCR — a mimo to działa to tylko na MAUI.

Brak wbudowanego przetwarzania wstępnego dla rzeczywistych obrazów. Aparaty w telefonach komórkowych generują obrazy z obrotem, szumem czujnika i niejednolitym DPI w różnych modelach urządzeń.TesseractOcrMauiprzekazuje obrazy bezpośrednio do silnika Tesseract bez żadnego przetwarzania wstępnego. Zespoły, które potrzebują większej dokładności, muszą dodać SkiaSharp lub ImageSharp, ręcznie zaimplementować algorytmy prostowania i usuwania szumów, napisać kod do zarządzania plikami tymczasowymi oraz przetestować to wszystko na różnych urządzeniach z systemami iOS i Android. Większość pomija to. W rezultacie cierpi na tym dokładność rzeczywistych zrzutów ekranu z urządzeń mobilnych.

**Ryzyko związane z utrzymaniem zależności produkcyjnej przez jednego programistę.**TesseractOcrMauijest utrzymywane przez jednego programistę. Nie ma za tym żadnej firmy, nie ma umowy SLA, nie ma zobowiązania do dostarczania poprawek bezpieczeństwa i nie ma ścieżki eskalacji poza zgłoszeniem na GitHubie. W przypadku aplikacji produkcyjnych w branżach podlegających regulacjom — finansowej, medycznej, prawnej — biblioteka utrzymywana przez wolontariuszy, z około 33 900 pobrań NuGet, nie jest akceptowalną zależnością.

Podstawowy problem

TesseractOcrMaui kompiluje się wyłącznie w ramach projektu MAUI. W momencie, gdy inny typ projektu wymaga OCR, architektura ulega załamaniu:

// TesseractOcrMaui: wired to MAUI host — cannot escape to a shared library
// This code compiles only inside a .NET MAUI application
public class OcrService
{
    private readonly ITesseract _tesseract; // resolved from MAUI DI — no other source exists

    public OcrService(ITesseract tesseract) { _tesseract = tesseract; }

    public async Task<string> ReadAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng"); // traineddata must be bundled as MauiAsset
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.Success ? result.RecognizedText : string.Empty;
    }
    // Cannot reference this class from ASP.NET Core, Azure Functions, or Docker
}
C#
// IronOCR: plain instantiable class — compiles in any .NET project type
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract(); // no DI, no MAUI host

    public string Read(string imagePath)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return _ocr.Read(input).Text;
    }
    // Place this in a netstandard2.1 library — reference from MAUI, API, and Functions together
}
C#

##IronOCR vs TesseractOcrMaui: Porównanie funkcji

Poniższa tabela przedstawia różnice w możliwościach istotne dla zespołów oceniających tę migrację.

FunkcjaTesseractOcrMauiIronOCR
.NET MAUI (iOS)TakTak (IronOcr.iOS)
.NET MAUI (Android)TakTak (IronOcr.Android)
.NET MAUI (Windows)TakTak
ASP.NET CoreNieTak
Azure FunctionsNieTak
AWS LambdaNieTak
Docker / kontenery LinuxNieTak
Aplikacje konsoloweNieTak
WPF / WinFormsNieTak
Wspólna biblioteka klas .NETNieTak
Wejście PDF (natywne)NieTak
Plik PDF chroniony hasłemNieTak
Dane wejściowe strumieniaNieTak
Wejście tablicy bajtówNieTak
Wielostronicowy plik wejściowy w formacie TIFFNieTak
Wynik w formacie PDF z możliwością wyszukiwaniaNieTak
eksport hOCRNieTak
Automatyczne prostowanieNieTak
Automatyczne usuwanie szumówNieTak
Wzmocnienie kontrastuNieTak
BinaryzacjaNieTak
OCR oparte na regionieNieTak
Odczytywanie BarCode podczas OCRNieTak
Współrzędne na poziomie WORDNieTak
Wielojęzyczne tłumaczenie symultaniczneNieTak
Obsługiwane językiRęcznie zebrane dane szkoleniowePonad 125 pakietów dostępnych za pośrednictwem NuGet
Bezpieczeństwo wątkówPodręcznikWbudowane
Wsparcie komercyjneBrak (pojedynczy programista)Tak (Iron Software)
LicencjonowanieApache 2.0 (bezpłatna)Wieczysta od $999
Pobieranie z NuGet~33 9005,3 mln+

Szybki start: Migracja zTesseractOcrMauido IronOCR

Krok 1: Zastąp pakiet NuGet

UsuńTesseractOcrMauiz projektu MAUI:

dotnet remove package TesseractOcrMaui
SHELL

Zainstaluj IronOCR. W przypadku projektów MAUI należy dodać pakiety specyficzne dla platformy obok pakietu podstawowego:

dotnet add package IronOcr, IronOcr.Android, IronOcr.iOS

W przypadku projektów po stronie serwera (ASP.NET Core, Azure Functions, konsola):

dotnet add package IronOcr

Strona pakietu IronOCR NuGet zawiera listę wszystkich dostępnych pakietów platformowych.

Krok 2: Aktualizacja przestrzeni nazw

Zastąp przestrzenie nazwTesseractOcrMauiz przestrzenią nazw IronOCR:

// Before (TesseractOcrMaui)
using TesseractOcrMaui;
using TesseractOcrMaui.Results;
using Microsoft.Maui.Storage;

// After (IronOCR)
using IronOcr;
C#

Krok 3: Inicjalizacja licencji

Dodaj inicjalizację licencji przy starcie aplikacji. W aplikacji MAUI umieść to w MauiProgram.cs; wASP.NET Coreumieść to w Program.cs:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

Przykłady migracji kodu

Zastąpienie rejestracji wstrzykiwania zależności MAUI

TesseractOcrMaui wymaga rejestracji silnika OCR za pośrednictwem dostawcy usług MAUI. Usunięcie tej rejestracji jest pierwszym krokiem architektonicznym, ponieważ to właśnie ona blokuje cały późniejszy kod OCR na hoście MAUI.

Podejście TesseractOcrMaui:

// MauiProgram.cs — OCR engine registered here; nowhere else resolves it
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>();

        // Binds OCR to MAUI DI — no standalone path exists after this
        builder.Services.AddTesseractOcr();

        return builder.Build();
    }
}

// Any class that needs OCR must receive ITesseract from the MAUI container
public class InvoicePageViewModel
{
    private readonly ITesseract _tesseract;

    public InvoicePageViewModel(ITesseract tesseract)
    {
        _tesseract = tesseract; // fails to construct outside MAUI host
    }

    public async Task<string> ScanInvoiceAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.RecognizedText ?? string.Empty;
    }
}
C#

Podejście IronOCR:

// MauiProgram.cs — license only; no DI registration needed
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>();

        // One-line initialization — works for all project types
        IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

        return builder.Build();
    }
}

// Nie constructor injection needed — IronTesseract instantiates directly
public class InvoicePageViewModel
{
    public string ScanInvoice(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return ocr.Read(input).Text;
    }
}
C#

Usunięcie AddTesseractOcr() eliminuje powiązanie DI MAUI. Klasa IronTesseract ma publiczny konstruktor bezparametrowy i nie niesie ze sobą zależności platformowej — może być zainicjowana wszędzie. Opcje inicjalizacji, w tym tryb silnika i konfigurację językową, można znaleźć w przewodniku konfiguracji IronTesseract.

Przeniesienie logiki OCR do wspólnej biblioteki klas

W przypadkuTesseractOcrMauiwspółdzielenie logiki OCR między różnymi typami projektów jest strukturalnie niemożliwe. Z IronOCR, ścieżka migracji jest prosta: wyodrębnij usługę do biblioteki klasowej .NET Standard 2.1 lub net8.0 i odwołaj ją z każdego projektu w rozwiązaniu.

Podejście TesseractOcrMaui:

// This service CANNOT be extracted to a shared library.
// It compiles only in a project that references TesseractOcrMaui,
// which only has MAUI platform targets.
//
// Result: every non-MAUI project must use a different OCR library,
// duplicating language config, error handling, and accuracy tuning.

public class DocumentOcrService
{
    private readonly ITesseract _tesseract; // MAUI DI only

    public DocumentOcrService(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<string> ProcessDocumentAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);
        return result.Success ? result.RecognizedText : string.Empty;
    }
    // Server team writes their own version using a different library
    // Two codebases, two accuracy profiles, two maintenance tracks
}
C#

Podejście IronOCR:

// Place this in: MyCompany.OcrCore (net8.0 or netstandard2.1 class library)
// Reference from: MyCompany.MauiApp, MyCompany.Api, MyCompany.BatchWorker

using IronOcr;

namespace MyCompany.OcrCore
{
    public class DocumentOcrService
    {
        private readonly IronTesseract _ocr;

        public DocumentOcrService()
        {
            _ocr = new IronTesseract();
        }

        public string ProcessDocument(string imagePath)
        {
            using var input = new OcrInput();
            input.LoadImage(imagePath);
            input.Deskew();
            input.DeNoise();
            return _ocr.Read(input).Text;
        }

        public string ProcessDocumentFromBytes(byte[] imageData)
        {
            using var input = new OcrInput();
            input.LoadImage(imageData);
            input.Deskew();
            input.DeNoise();
            return _ocr.Read(input).Text;
        }

        public string ProcessDocumentFromStream(Stream imageStream)
        {
            using var input = new OcrInput();
            input.LoadImage(imageStream);
            return _ocr.Read(input).Text;
        }
    }
}
C#

Jedna biblioteka klasowa, jeden zestaw testów, jeden profil dokładności. Aplikacja MAUI wywołuje ProcessDocument(photoPath), APIASP.NET Corewywołuje ProcessDocumentFromBytes(uploadedBytes), a Azure Function wywołuje ProcessDocumentFromStream(blobStream) — wszystko opiera się na tej samej implementacji. Przewodnik wejścia strumieniowego i przewodnik wejścia obrazów dokumentują wszystkie warianty ładowania OcrInput.

Włączanie OCR po stronie serwera w ASP.NET Core

Nie można odwołać się doTesseractOcrMauiz projektu ASP.NET Core. Zespoły, które dodają punkt końcowy do przesyłania dokumentów, są zmuszone sięgnąć po zupełnie inną bibliotekę.IronOCR działa w środowiskuASP.NET Corebez żadnych zmian konfiguracyjnych poza wprowadzeniem klucza licencyjnego.

Podejście TesseractOcrMaui:

//ASP.NET CoreWeb API —TesseractOcrMauiCANNOT be used here.
// The package has no net8.0 or netstandard target.
// Referencing it produces: "The given project does not support targeting net8.0-ios/android/windows."
//
// Team is forced to add a second OCR library — Tesseract charlesw wrapper,
// a cloud API, or another solution — creating a split codebase.

[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
    // Cannot inject ITesseract here — no MAUI host, no MAUI DI container
    // Must use a completely different OCR library for server-side processing
}
C#

Podejście IronOCR:

//ASP.NET Core—IronOCR works without modification
using IronOcr;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
    [HttpPost("extract-text")]
    public async Task<IActionResult> ExtractText(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file uploaded.");

        var ocr = new IronTesseract();
        using var input = new OcrInput();

        // Load directly from the upload stream — no temp files
        using var stream = file.OpenReadStream();

        if (file.ContentType == "application/pdf")
            input.LoadPdf(stream);
        else
            input.LoadImage(stream);

        input.Deskew();
        input.DeNoise();

        var result = ocr.Read(input);

        return Ok(new
        {
            text = result.Text,
            confidence = result.Confidence,
            pageCount = result.Pages.Count()
        });
    }

    [HttpPost("extract-text-batch")]
    public async Task<IActionResult> ExtractTextBatch(List<IFormFile> files)
    {
        var results = new List<object>();

        // Thread-safe: create one IronTesseract per thread
        await Parallel.ForEachAsync(files, async (file, ct) =>
        {
            var ocr = new IronTesseract();
            using var input = new OcrInput();
            using var stream = file.OpenReadStream();
            input.LoadImage(stream);
            var result = ocr.Read(input);

            lock (results)
            {
                results.Add(new { file = file.FileName, text = result.Text });
            }
        });

        return Ok(results);
    }
}
C#

Ten sam kod można wdrożyć bez zmian na IIS, Kestrel lub w kontenerze Docker w systemie Linux. Przewodnik po OCR w ASP.NET obejmuje konfigurację oprogramowania pośredniczącego, a przewodnik wdrażania Docker dokumentuje konfigurację kontenerów w systemie Linux.

Eliminacja kodu obsługi specyficznego dla platformy

Architektura TesseractOcrMaui, przeznaczona wyłącznie dla platformy MAUI, zmusza programistów do pisania kodu uzależnionego od platformy podczas próby integracji OCR z rozwiązaniami obsługującymi wiele platform.IronOCR eliminuje potrzebę stosowania warunków platformowych, ponieważ ten sam pakiet działa poprawnie na każdym systemie docelowym.

Podejście TesseractOcrMaui:

// Attempting to share OCR logic across MAUI and non-MAUI targets
// requires platform-conditional compilation — a maintenance hazard

#if ANDROID || IOS || WINDOWS
// Only compile this block in MAUI targets
// Non-MAUI targets cannot referenceTesseractOcrMauiat all
using TesseractOcrMaui;

public class PlatformOcrHandler
{
    private readonly ITesseract _tesseract;

    public PlatformOcrHandler(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<string> ProcessAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var r = await _tesseract.RecognizeTextAsync(imagePath);
        return r.RecognizedText ?? string.Empty;
    }
}
#else
// Server targets need a completely different implementation
public class PlatformOcrHandler
{
    public string ProcessAsync(string imagePath)
    {
        // Duplicate logic using a different library
        throw new PlatformNotSupportedException("Use server OCR library here");
    }
}
#endif
C#

Podejście IronOCR:

// One implementation — no conditional compilation, no duplicate logic
using IronOcr;

public class PlatformOcrHandler
{
    // This class compiles identically for:
    // net8.0-android, net8.0-ios, net8.0-windows (MAUI targets)
    // net8.0 (server targets)
    // netstandard2.1 (shared library targets)

    public string Process(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        input.Deskew();
        return ocr.Read(input).Text;
    }
}

// Multi-target .csproj — no conditional package references needed
// <TargetFrameworks>net8.0;net8.0-android;net8.0-ios</TargetFrameworks>
// IronOcr resolves correctly for all three targets from one package reference
C#

Warunki platformowe w kodzie obsługi OCR wskazują na podział architektury, który z czasem się pogłębia. Każda zmiana konfiguracji języka, każda korekta przetwarzania wstępnego, każda modyfikacja progu pewności musi zostać zastosowana w obu gałęziach.IronOCR sprawia, że podział ten staje się zbędny. Przegląd biblioteki OCR .NET szczegółowo omawia strukturę projektu wielocelowego.

Pobieranie danych ustrukturyzowanych za pomocą współrzędnych słów WORD

TesseractOcrMaui udostępnia tylko result.RecognizedText oraz najwyższy poziom wskaźnika zaufania. Wyodrębnianie pojedynczych słów wraz z ich ramkami ograniczającymi — wymagane do walidacji pól formularzy, analizowania dokumentów lub nakładania podświetleń — nie jest możliwe.IronOCR udostępnia pełny model obiektowy dokumentu: strony, akapity, wiersze, słowa i znaki, z których każdy posiada współrzędne pikselowe.

Podejście TesseractOcrMaui:

// TesseractOcrMaui: flat text string only — no structure, no coordinates
public class TesseractMauiFormParser
{
    private readonly ITesseract _tesseract;

    public TesseractMauiFormParser(ITesseract tesseract)
    {
        _tesseract = tesseract;
    }

    public async Task<Dictionary<string, string>> ParseFormAsync(string imagePath)
    {
        await _tesseract.InitAsync("eng");
        var result = await _tesseract.RecognizeTextAsync(imagePath);

        // result.RecognizedText is one flat string — no field positions
        // Parsing requires fragile line-splitting and regex heuristics
        var fields = new Dictionary<string, string>();
        var lines = result.RecognizedText?.Split('\n') ?? Array.Empty<string>();

        foreach (var line in lines)
        {
            // Hope the layout stays consistent enough to parse
            var parts = line.Split(':');
            if (parts.Length == 2)
                fields[parts[0].Trim()] = parts[1].Trim();
        }

        return fields;
        // Nie way to validate against expected field positions
        // Nie confidence per word — only document-level confidence
    }
}
C#

Podejście IronOCR:

// IronOCR: full document structure with bounding boxes per word
using IronOcr;

public class IronOcrFormParser
{
    public List<WordLocation> ExtractWordsWithPositions(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);

        var result = ocr.Read(input);
        var wordLocations = new List<WordLocation>();

        foreach (var page in result.Pages)
        {
            foreach (var word in page.Words)
            {
                wordLocations.Add(new WordLocation
                {
                    Text = word.Text,
                    Confidence = word.Confidence,
                    X = word.X,
                    Y = word.Y,
                    Width = word.Width,
                    Height = word.Height
                });
            }
        }

        return wordLocations;
    }

    public FormData ParseStructuredForm(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        input.Deskew();

        var result = ocr.Read(input);
        var form = new FormData();

        foreach (var page in result.Pages)
        {
            foreach (var paragraph in page.Paragraphs)
            {
                // Use Y coordinate to identify form regions
                if (paragraph.Y < 200)
                    form.HeaderText += paragraph.Text + " ";
                else if (paragraph.Y > 800)
                    form.FooterText += paragraph.Text + " ";
                else
                    form.BodyLines.Add(paragraph.Text);
            }
        }

        form.OverallConfidence = result.Confidence;
        return form;
    }
}

public class WordLocation
{
    public string Text { get; set; }
    public float Confidence { get; set; }
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
}

public class FormData
{
    public string HeaderText { get; set; } = string.Empty;
    public string FooterText { get; set; } = string.Empty;
    public List<string> BodyLines { get; set; } = new();
    public float OverallConfidence { get; set; }
}
C#

Koordynaty słów umożliwiają weryfikację względem znanych szablonów formularzy, oznaczanie oparte na poziomie pewności do weryfikacji przez człowieka oraz nakładanie podświetleń w interfejsach przeglądarek dokumentów. Przewodnik strukturalnych wyników dokumentuje pełen model obiektowy OcrResult, w tym dostęp na poziomie znaku, a przewodnik wskaźników zaufania pokrywa wzorce filtracji zaufania dla każdego słowa.

Przetwarzanie w tle z wykorzystaniem natywnej asynchroniczności i śledzenia postępu

TesseractOcrMaui dostarcza asynchroniczne API (RecognizeTextAsync), ale tylko w kontekście aplikacji MAUI. Długotrwałe zadania wsadowe muszą być uruchamiane w usłudze działającej w tle, funkcji Azure lub procesie roboczym — żadna z tych opcji nie jest obsługiwana przez TesseractOcrMaui.IronOCR zapewnia natywną obsługę asynchroniczną, która działa w każdej usłudze hostowanej.

Podejście TesseractOcrMaui:

// Background processing is impossible with TesseractOcrMaui.
// IHostedService runs in a server context —TesseractOcrMauihas no server target.
// The MAUI async API exists, but there is nowhere to run it outside the MAUI app host.

public class DocumentBatchWorker : BackgroundService
{
    // ITesseract cannot be injected here — no MAUI DI in a hosted service
    // Attempting to referenceTesseractOcrMauiwill fail to compile:
    // error: PackageTesseractOcrMauidoes not support target net8.0
    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        throw new PlatformNotSupportedException(
            "TesseractOcrMaui has no server target. Use a different OCR library.");
    }
}
C#

Podejście IronOCR:

// IronOCR: hosted service background batch processor
using IronOcr;
using Microsoft.Extensions.Hosting;

public class DocumentBatchWorker : BackgroundService
{
    private readonly ILogger<DocumentBatchWorker> _logger;
    private readonly string _inputFolder;
    private readonly string _outputFolder;

    public DocumentBatchWorker(ILogger<DocumentBatchWorker> logger, IConfiguration config)
    {
        _logger = logger;
        _inputFolder = config["Ocr:InputFolder"];
        _outputFolder = config["Ocr:OutputFolder"];
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var pendingFiles = Directory.GetFiles(_inputFolder, "*.pdf")
                .Concat(Directory.GetFiles(_inputFolder, "*.jpg"))
                .ToList();

            if (pendingFiles.Count > 0)
            {
                _logger.LogInformation("Processing {Count} documents.", pendingFiles.Count);

                // Thread-safe parallel processing — one IronTesseract per thread
                await Parallel.ForEachAsync(pendingFiles,
                    new ParallelOptions { MaxDegreeOfParallelism = 4, CancellationToken = stoppingToken },
                    async (filePath, ct) =>
                    {
                        await ProcessDocumentAsync(filePath, ct);
                    });
            }

            await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
        }
    }

    private async Task ProcessDocumentAsync(string filePath, CancellationToken ct)
    {
        try
        {
            var ocr = new IronTesseract();
            using var input = new OcrInput();

            if (Path.GetExtension(filePath).Equals(".pdf", StringComparison.OrdinalIgnoreCase))
                input.LoadPdf(filePath);
            else
                input.LoadImage(filePath);

            input.Deskew();
            input.DeNoise();

            var result = await Task.Run(() => ocr.Read(input), ct);

            // Produce searchable PDF from the same OCR pass
            var outputPath = Path.Combine(_outputFolder,
                Path.GetFileNameWithoutExtension(filePath) + "_searchable.pdf");
            result.SaveAsSearchablePdf(outputPath);

            File.Delete(filePath); // move from input queue
            _logger.LogInformation("Processed {File}: {Confidence:F1}% confidence.", filePath, result.Confidence);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to process {File}.", filePath);
        }
    }
}
C#

Pracownik rejestruje się w Program.cs z builder.Services.AddHostedService<DocumentBatchWorker>() i działa w każdym hoście .NET 8 — Windows Service, jednostka systemd Linux, kontener Docker lub Azure Container App. Przewodnik asynchronicznego OCR pokrywa asynchroniczne wzorce, a przewodnik przeszukiwalnego PDF-a dokumentuje opcje wyjściowe SaveAsSearchablePdf.

Odnośnik do dokumentacji APITesseractOcrMauido IronOCR

TesseractOcrMauiOdpowiednik IronOCR
dotnet add package TesseractOcrMauidotnet add package IronOcr
builder.Services.AddTesseractOcr()Usunąć całkowicie — nie jest wymagana rejestracja
ITesseract (wstrzyknięte)new IronTesseract() (bezpośrednie inicjalizacja)
_tesseract.InitAsync("eng")ocr.Language = OcrLanguage.English; (lub pomiń dla domyślnego angielskiego)
_tesseract.RecognizeTextAsync(imagePath)ocr.Read(input)
result.RecognizedTextresult.Text
result.SuccessOparte na wyjątkach; brak flagi boolowskiej
result.Statuscatch (Exception ex) komunikat
result.Confidenceresult.Confidence (także dla każdego słowa)
TesseractOcrMaui.Results.RecognitionResultIronOcr.OcrResult
<MauiAsset> paczka traineddatadotnet add package IronOcr.Languages.French
Resources/Raw/tessdata/eng.traineddataUsuń — dane językowe znajdują się w pakiecie NuGet
FileSystem.OpenAppPackageFileAsync() (dla traineddata)Usuń — niepotrzebne
Brak obsługi plików PDFinput.LoadPdf(path) lub input.LoadPdf(stream)
Brak przetwarzania wstępnegoinput.Deskew(), input.DeNoise(), input.Binarize(), input.Contrast()
Brak możliwości wyszukiwania w pliku PDFresult.SaveAsSearchablePdf(outputPath)
Brak współrzędnych słownychresult.Pages[0].Words[i].X, .Y, .Width, .Height
Brak pewności co do poszczególnych słówresult.Pages[0].Words[i].Confidence
net8.0-ios tylko celnet8.0 + IronOcr.iOS pakiet
net8.0-android tylko celnet8.0 + IronOcr.Android pakiet

Typowe problemy związane z migracją i ich rozwiązania

Problem 1: Nie można usunąć AddTesseractOcr bez uszkodzenia klas zależnych

TesseractOcrMaui: Każda klasa, która wykonuje OCR, otrzymuje ITesseract poprzez wstrzyknięcie w konstruktorze. Usunięcie AddTesseractOcr() natychmiast powoduje awarię tych konstruktorów z wyjątkiem rozwiązywania DI.

Rozwiązanie: Usuń parametr konstruktora i zastąp go bezpośrednim przekazaniem IronTesseract. Jeśli projekt używa kontenera DI i chcesz zachować wzorzec wstrzykiwalny, zarejestruj IronTesseract ręcznie:

// Option A: Direct instantiation (recommended for most cases)
public class ScanPageViewModel
{
    public string ScanDocument(string imagePath)
    {
        var ocr = new IronTesseract();
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return ocr.Read(input).Text;
    }
}

// Option B: Register IronTesseract in DI if your architecture requires it
// In MauiProgram.cs or Program.cs:
builder.Services.AddSingleton<IronTesseract>();

// Then inject normally:
public class ScanPageViewModel
{
    private readonly IronTesseract _ocr;
    public ScanPageViewModel(IronTesseract ocr) { _ocr = ocr; }

    public string ScanDocument(string imagePath)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath);
        return _ocr.Read(input).Text;
    }
}
C#

Problem 2: Brak plików danych szkoleniowych po usunięciu pakietu

TesseractOcrMaui: Folder Resources/Raw/tessdata/, pliki .traineddata wewnątrz, oraz deklaracje <MauiAsset> w .csproj trzeba usunąć. Pozostawienie ich powoduje wyświetlanie ostrzeżeń kompilacji i powiększa pakiet aplikacji o nieużywane pliki.

Rozwiązanie: Usuń folder tessdata, usuń wpisy <MauiAsset> i odinstaluj jakikolwiek język pobrany ręcznie. Zamiast tego zainstaluj odpowiedni pakiet językowy IronOCR:

# Delete traineddata assets
rm -rf Resources/Raw/tessdata

# Remove from .csproj (delete the MauiAsset ItemGroup):
# <ItemGroup>
#   <MauiAsset Include="Resources\Raw\tessdata\*.traineddata" />
# </ItemGroup>

# Install IronOCR language pack (if non-English language was needed)
dotnet add package IronOcr.Languages.French
dotnet add package IronOcr.Languages.German
SHELL

Pakiety językowe z IronOCRsą rozpoznawane w czasie kompilacji i dołączane bez konieczności ręcznego zarządzania plikami. W przewodniku po wielu językach opisano wszystkie dostępne pakiety oraz konfigurację wielu języków jednocześnie.

Problem 3: Funkcja InitAsync musi być wywołana przed każdą funkcją RecognizeTextAsync

TesseractOcrMaui: Wywołanie ITesseract.InitAsync(language) musi poprzedzać każde wywołanie RecognizeTextAsync. Zespoły często dodają znaczniki _isInitialized, podwójnie sprawdzane blokowanie lub semafory, aby uniknąć powtarzającej się inicjalizacji. Cały ten kod staje się kodem martwym po migracji.

Rozwiązanie: IronTesseract nie ma kroku inicjalizacji. Język jest ustawiany raz na instancji. Usuń wszystkie wywołania InitAsync, wszystkie flagi _isInitialized i całą logikę strażnika inicjalizacji:

// Before: initialization guard required before every OCR call
private bool _isInitialized = false;
private readonly SemaphoreSlim _initLock = new SemaphoreSlim(1, 1);

public async Task<string> GetTextAsync(string imagePath)
{
    await _initLock.WaitAsync();
    try
    {
        if (!_isInitialized)
        {
            await _tesseract.InitAsync("eng");
            _isInitialized = true;
        }
    }
    finally { _initLock.Release(); }

    var result = await _tesseract.RecognizeTextAsync(imagePath);
    return result.RecognizedText ?? string.Empty;
}

// After: no initialization, no guard, no semaphore
public string GetText(string imagePath)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    return ocr.Read(input).Text;
}
C#

Problem 4: Należy zastąpić wzorzec sprawdzania result.Success

TesseractOcrMaui: Wartość zwracana RecognizeTextAsync niesie Success logiczne oraz ciąg Status. Kod, który sprawdza if (!result.Success) i odczytuje result.Status dla informacji o błędach, musi być przepisany.

**Rozwiązanie:**IronOCR wykorzystuje standardową semantykę wyjątków .NET. Zastąp sprawdzanie flag sukcesu konstrukcją try/catch. W przypadku powodzenia, .Text jest zawsze uzupełnione (pusty ciąg, jeśli nie znaleziono tekstu):

// Before: success-flag pattern
var result = await _tesseract.RecognizeTextAsync(imagePath);
if (!result.Success)
{
    logger.LogError("OCR failed: {Status}", result.Status);
    return string.Empty;
}
return result.RecognizedText ?? string.Empty;

// After: exception pattern
try
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    var result = ocr.Read(input);
    return result.Text; // empty string if no text found — never null
}
catch (Exception ex)
{
    logger.LogError(ex, "OCR failed for {Path}.", imagePath);
    return string.Empty;
}
C#

Problem 5: Framework docelowy wyłącznie MAUI w projektach bibliotek współdzielonych

TesseractOcrMaui: Biblioteka klasowa, która odwołuje się do TesseractOcrMaui, automatycznie dziedziczy jej ograniczenie platformy. Zmienna <TargetFramework> biblioteki musi być ustawiona na moniker MAUI (net8.0-android, net8.0-ios, lub net8.0-windows), co uniemożliwia jej użycie przez projekty serwerowe.

Rozwiązanie: Zmień cel biblioteki klasowej na net8.0 lub netstandard2.1 i zamiast tego odwołaj się do IronOcr. Biblioteka działa teraz poprawnie w każdym projekcie, który z niej korzysta:

<!-- Before: locked to MAUI target becauseTesseractOcrMauihas no net8.0 target -->
<TargetFramework>net8.0-android</TargetFramework>
<PackageReference Include="TesseractOcrMaui" Version="*" />

<!-- After: universal target — referenced from MAUI, API, worker, and Functions -->
<TargetFramework>net8.0</TargetFramework>
<PackageReference Include="IronOcr" Version="*" />
XML

Problem 6: Przetwarzanie plików PDF wymaga usunięcia drugiej biblioteki

TesseractOcrMaui: Zespoły, które wprowadziły wsparcie PDF, dodały drugą bibliotekę (PDFium, PdfPig, lub renderer chmurowy), aby przekonwertować strony PDF na obrazy przed przekazaniem ich do RecognizeTextAsync. Po migracji do IronOCR ta druga biblioteka i cały jej kod renderujący strony mogą zostać usunięte.

Rozwiązanie: Usuń bibliotekę renderowania PDF i zastąp cały pipeline ekstrakcji stron input.LoadPdf():

// Before: PDF library + manual temp file management (50+ lines)
using var pdfDoc = PdfDocument.Open(pdfPath);
var results = new List<string>();
foreach (var page in pdfDoc.GetPages())
{
    var tempImagePath = Path.Combine(FileSystem.CacheDirectory, $"page_{page.Number}.png");
    RenderPageToImage(page, tempImagePath, dpi: 300);
    await _tesseract.InitAsync("eng");
    var r = await _tesseract.RecognizeTextAsync(tempImagePath);
    results.Add(r.RecognizedText ?? string.Empty);
    File.Delete(tempImagePath);
}
return string.Join("\n", results);

// After: native PDF support — 5 lines
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf(pdfPath);
var result = ocr.Read(input);
return result.Text;
C#

Przewodnik dotyczący plików PDF obejmuje wybór zakresu stron, pliki PDF chronione hasłem oraz ładowanie strumieniowe.

Lista kontrolna migracji TesseractOcrMaui

Przed migracją

Przed wprowadzeniem jakichkolwiek zmian w kodzie należy przeprowadzić audyt kodu źródłowego w celu sporządzenia wykazu wszystkich miejsc użycia TesseractOcrMaui:

# Find all files that referenceTesseractOcrMauinamespaces
grep -r "TesseractOcrMaui" --include="*.cs" .

# Find all ITesseract injection points
grep -r "ITesseract" --include="*.cs" .

# Find all AddTesseractOcr registrations
grep -r "AddTesseractOcr" --include="*.cs" .

# Find all InitAsync calls
grep -r "InitAsync" --include="*.cs" .

# Find all RecognizeTextAsync calls
grep -r "RecognizeTextAsync" --include="*.cs" .

# Find traineddata asset declarations in project files
grep -r "tessdata" --include="*.csproj" .

# Find MauiAsset traineddata declarations
grep -r "MauiAsset" --include="*.csproj" .

# Identify projects with MAUI-only target frameworks that hold OCR logic
grep -r "net8.0-android\|net8.0-ios\|net8.0-windows" --include="*.csproj" .
SHELL

Zanotuj każdą klasę, która przyjmuje ITesseract w konstruktorze — te konstruktory ulegną zmianie. Zanotuj każdy plik projektu, który deklaruje <MauiAsset> dla traineddata — te deklaracje zostaną usunięte. Należy sprawdzić, czy biblioteka renderowania plików PDF jest obecna i czy jest używana wyłącznie do przetwarzania wstępnego OCR.

Migracja kodu

  1. Uruchom dotnet remove package TesseractOcrMaui w każdym projekcie, który się do niego odwołuje
  2. Uruchom dotnet add package IronOcr w każdym projekcie, który będzie wykonywał OCR
  3. Uruchom dotnet add package IronOcr.Android w projektach MAUI celujących w Android
  4. Uruchom dotnet add package IronOcr.iOS w projektach MAUI celujących w iOS
  5. Uruchom dotnet add package IronOcr.Languages.* dla każdego języka innego niż angielski, wcześniej pakowanego jako traineddata
  6. Dodaj IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; przy starcie aplikacji w każdym projekcie wejściowym
  7. Usuń Resources/Raw/tessdata/ i wszystkie pliki .traineddata z projektów MAUI
  8. Usuń wszystkie linie <MauiAsset Include="Resources\Raw\tessdata\*.traineddata" /> z plików .csproj
  9. Usuń builder.Services.AddTesseractOcr() ze wszystkich plików MauiProgram.cs
  10. Zastąp wszystkie using TesseractOcrMaui; i using TesseractOcrMaui.Results; przez using IronOcr;
  11. Usuń parametry konstruktora ITesseract ze wszystkich klas serwisowych i view-modelowych
  12. Zastąp wywołania await _tesseract.InitAsync("eng") wywołaniami ocr.Language = OcrLanguage.English; jeśli potrzeba (domyślnie jest angielski)
  13. Zastąp await _tesseract.RecognizeTextAsync(imagePath) przez ocr.Read(input) używając instancji OcrInput
  14. Zastąp result.RecognizedText przez result.Text
  15. Zastąp kontrolę if (!result.Success) blokami try/catch
  16. Jeśli biblioteka renderowania PDF została dodana wyłącznie w celu wsparcia TesseractOcrMaui, usuń ją i zastąp kod ekstrakcji stron przez input.LoadPdf()
  17. Zmień jakąkolwiek platformę docelową wyłącznie dla MAUI w bibliotekach klasowych, które przechowywały logikę OCR na net8.0 lub netstandard2.1

Po migracji

  • Sprawdź, czy OCR generuje tekst z obrazu JPEG zarejestrowanego przez aparat urządzenia zarówno na platformach iOS, jak i Android
  • Zweryfikuj, że OCR produkuje tekst z tego samego obrazu załadowanego przez byte[] w punkcie końcowym API po stronie serwera
  • Sprawdź, czy wspólna biblioteka klas kompiluje się i działa identycznie, gdy jest wywoływana zarówno z projektów MAUI, jak i .NET Core
  • Sprawdź, czy wprowadzanie plików PDF działa od początku do końca bez tworzenia plików tymczasowych
  • Zweryfikuj, że wyjście SaveAsSearchablePdf jest indeksowalne w przeglądarce PDF
  • Potwierdź, że wskaźniki zaufania są obecne na result.Confidence i na page.Words[i].Confidence
  • Sprawdź, czy aplikacja MAUI generuje dziennik uruchomienia bez błędów, bez wyjątków typu "nie znaleziono pliku danych szkoleniowych".
  • Zweryfikuj, że folder Resources/Raw/tessdata/ jest nieobecny w pakiecie aplikacji MAUI w kompilacjach do wydania
  • Uruchom równoległe zadanie wsadowe z co najmniej 10 dokumentami, aby potwierdzić bezpieczeństwo wątków
  • Potwierdź, że usunięcie InitAsync nie pozostawiło osieroconych semaforów ani zmiennych stanu _isInitialized w żadnej klasie serwisowej

Kluczowe korzyści z migracji do IronOCR

Jedna baza kodu dla całego produktu. Po migracji, każdy projekt w rozwiązaniu — aplikacja mobilna MAUI, API ASP.NET Core, Azure Function, pracownik w tle — woła tę samą klasę DocumentOcrService z tej samej współdzielonej biblioteki. Konfiguracja języka, ustawienia przetwarzania wstępnego i dostosowanie dokładności odbywają się w jednym miejscu. Gdy nowy typ dokumentu wymaga nowego filtra przetwarzania wstępnego, zmiana jest wprowadzana jednorazowo i obowiązuje wszędzie.

**Wdrażanie po stronie serwera bez konieczności przepisywania kodu.**IronOCR można wdrażać w kontenerach Linux, na serwerach Windows Server, w usłudze Azure App Service,AWS Lambdaoraz w dowolnym innym środowisku uruchomieniowym .NET 8 bez konieczności wprowadzania modyfikacji. Ta sama instancja IronTesseract, która przetwarza uchwyty kamery mobilnej, przetwarza serwerowe przesyłanie PDF. Przewodnik wdrażania platformy Azure oraz przewodnik wdrażania AWS dokumentują kroki konfiguracji specyficzne dla danej platformy.

Przetwarzanie PDF bez drugiej biblioteki. Natychmiastowy wkład PDF przez input.LoadPdf() eliminuje bibliotekę renderowania PDF, pętlę ekstrakcji obrazu z każdej strony, zarządzanie plikami tymczasowymi oraz kod czyszczący, które wymagała architektura TesseractOcrMaui. Skanowane PDF-y umów, faktur i dokumentów tożsamości ładują się w jednej linii. Ten sam przebieg OCR, który wyodrębnia tekst, może stworzyć przeszukiwalny PDF dzięki result.SaveAsSearchablePdf() — zdolność, którejTesseractOcrMauinie może zapewnić na żadnym poziomie.

Przetwarzanie wstępne obsługujące rzeczywiste obrazy mobilne. input.Deskew(), input.DeNoise(), input.Binarize() oraz input.Sharpen() to jedno-metodowe wywołania stosujące skalibrowane korekty obrazów zanim silnik Tesseract zobaczy dane. Zespoły, które akceptowały 40–60% dokładności w przypadku zdjęć mobilnych wykonanych przy słabym oświetleniu bez wstępnego przetwarzania, zazwyczaj osiągają 85–90%+ po dodaniu potoku trzech filtrów. Nie jest wymagane stosowanie SkiaSharp, ImageSharp ani implementacja algorytmów. Przewodnik po korekcji jakości obrazu dokumentuje każdy dostępny filtr oraz sytuacje, w których należy go zastosować.

Wsparcie komercyjne z określoną ścieżką eskalacji. Iron Software zapewnia wsparcie e-mail dla wszystkich poziomów licencji IronOCR oraz priorytetowe wsparcie telefoniczne i przez czat na poziomach Professional i Enterprise. Gdy aktualizacja platformy zakłóca rozpoznawanie bibliotek natywnych na określonym poziomie API systemu Android — tego rodzaju awaria, którą wolontariusze zTesseractOcrMauirozwiązują w ramach zgłoszeń na GitHubie — istnieje prawdziwy zespół inżynierów, który ma obowiązek zareagować. Licencjonowanie wieczyste zaczyna się od $999 dla poziomu Lite; Na stronie licencyjnej wymieniono wszystkie poziomy oraz zawarte w nich usługi wsparcia.

**Ponad 125 języków za pośrednictwem NuGet bez zwiększania rozmiaru pakietu aplikacji.**TesseractOcrMauidołącza pliki danych szkoleniowych do aplikacji MAUI — każdy język zwiększa rozmiar pobieranej aplikacji o 10–50 MB. Pakiety językowe IronOCR instaluje się za pośrednictwem NuGet i są one dołączane wyłącznie do kompilacji po stronie serwera lub do kompilacji platformowych, w których są wyraźnie wskazane. Pakiety aplikacji mobilnych pozostają niewielkie; Wersje po stronie serwera otrzymują pełny zestaw języków. Dodanie nowego języka to jedno polecenie dotnet add package bez zmian w pliku projektu i bez zarządzania plikami. Pełny katalog języków zawiera listę wszystkich ponad 125 dostępnych pakietów.

Zwróć uwagę: PDFium, PdfPig i Tesseract są zarejestrowanymi znakami towarowymi odpowiednich właścicieli. Ta strona nie jest powiązana z, rekomendowana przez ani sponsorowana przez projekt Chromium, Google ani UglyToad. Wszystkie nazwy produktów, logo i marki są własnością ich odpowiednich właścicieli. Porównania mają charakter wyłącznie informacyjny i odzwierciedlają informacje dostępne publicznie w momencie pisania.

Powiązane artykuły

Key in blue circle

Uzyskaj natychmiast swój darmowy 30-dniowy Klucz Testowy.

Your trial license will be sent to your email address

Brak ograniczeń. 100% dostępności. Bez karty kredytowej.

bullet_checkedNie wymaga karty kredytowej ani tworzenia kontaBrak ograniczeń. 100% dostępności. Bez karty kredytowej.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Otrzymaj swoją Konsultację Bez Zobowiązań
Wypełnij poniższy formularz lub wyślij e-mail na sales@ironsoftware.com
Twoje dane zawsze będą utrzymywane w tajemnicy.
Zaufane przez miliony inżynierów na całym świecie
Logotypy klientów Iron Software
Otrzymaj swój darmowy Klucz Próbny na 30 dni natychmiast.
Nie wymaga karty kredytowej ani tworzenia konta