Umstellung von TesseractOcrMaui auf IronOCR
Dieser Leitfaden führt Sie durch eine vollständige Migration von TesseractOcrMauizu IronOCR und enthält für jeden Schritt praktischen Vorher-Nachher-Code. Er richtet sich an Entwickler, die sich bereits entschieden haben, die Einschränkungen der MAUI-Plattform hinter sich zu lassen, und einen systematischen Weg zu einer Bibliothek benötigen, die in mobilen Apps, serverseitigen APIs, Hintergrundprozessen und Cloud-Funktionen identisch läuft. Das vorherige Lesen des Vergleichsartikels ist nicht erforderlich.
Warum von TesseractOcrMauimigrieren?
TesseractOcrMaui wurde entwickelt, um eine echte Lücke zu schließen: Bestehende .NET-Tesseract-Wrapper konnten die Interoperabilität mit mobilen Plattformen nicht eigenständig gewährleisten. Für einen reinen MAUI-Prototyp ohne Server-Footprint schließt es diese Lücke. Die Probleme treten in dem Moment zutage, in dem das Produkt über diesen engen Anwendungsbereich hinauswächst.
Nur MAUI-Zielplattformen verhindern die Code-Teilhabe. TesseractOcrMauiliefert Ziele für net8.0-ios, net8.0-android und net8.0-windows — alle MAUI-Plattformmoniker. Das Paket enthält keinen net8.0, keinen netstandard2.1, kein server-kompatibles Ziel. Der Aufruf aus einer Klassenbibliothek, einem .NET Core-Projekt oder einer Azure-Funktion führt zu einem Kompilierungsfehler. Es gibt keine Umgehungslösung: Das Paket ist architektonisch nicht in der Lage, außerhalb eines MAUI-Hosts ausgeführt zu werden. Jedes Mal, wenn die OCR-Anforderung in einem Nicht-MAUI-Kontext auftritt, muss eine zweite Bibliothek eingeführt und parallel gepflegt werden.
Verpflichtende MAUI-Abhängigkeitsinjektions-Kopplung. Der AddTesseractOcr() Aufruf in MauiProgram.cs verbindet ITesseract mit dem MAUI-Dienstleister. Es gibt keine Factory-Methode, keinen statischen Einstiegspunkt und keinen Konstruktor außerhalb dieses DI-Graphen. Dies bedeutet, dass die OCR-Logik nicht in eine portable Klassenbibliothek extrahiert werden kann — jede Klasse, die ITesseract in ihrem Konstruktor verwendet, ist für ihre gesamte Lebensdauer an den MAUI-Anwendungshost gebunden.
Keine PDF-Eingabe auf irgendeiner Ebene. PDF-Dokumente sind das gängigste Format für gescannte Verträge, Rechnungen und Ausweisdokumente. TesseractOcrMauiwirft NotSupportedException bei jeder PDF-Eingabe. Die Verarbeitung einer PDF-Datei erfordert das Hinzufügen einer separaten PDF-Rendering-Bibliothek, das Schreiben von seitenweiser Bild-Extraktion, die Verwaltung temporärer Dateien im Geräte-Cache und deren Bereinigung nach jedem Aufruf. Das sind über 100 Zeilen Infrastrukturcode, bevor ein einziger OCR-Aufruf ausgeführt wird – und es funktioniert immer noch nur auf MAUI.
Keine integrierte Vorverarbeitung für Bilder aus der realen Welt. Handykameras erzeugen Bilder mit Drehung, Sensorrauschen und uneinheitlichen DPI-Werten je nach Gerätemodell. TesseractOcrMauileitet Bilder ohne jegliche Vorverarbeitung direkt an die Tesseract-Engine weiter. Teams, die eine höhere Genauigkeit benötigen, müssen SkiaSharp oder ImageSharp hinzufügen, Algorithmen zur Entzerrung und Rauschunterdrückung manuell implementieren, eine Verwaltung für temporäre Dateien schreiben und das Ganze auf allen iOS- und Android-Gerätevarianten testen. Die meisten überspringen es. Die Genauigkeit bei echten mobilen Aufnahmen leidet darunter.
Risiko der Wartung durch einen einzelnen Entwickler bei einer Produktionsabhängigkeit. TesseractOcrMauiwird von einem einzigen Entwickler gewartet. Es gibt kein Unternehmen dahinter, kein SLA, keine Verpflichtung zu Sicherheitspatches und keinen Eskalationsweg über ein GitHub-Issue hinaus. Für Produktionsanwendungen in regulierten Branchen – Finanzen, Gesundheitswesen, Rechtswesen – ist eine von Freiwilligen gepflegte Bibliothek mit insgesamt rund 33.900 NuGet-Downloads keine akzeptable Abhängigkeit.
Das grundsätzliche Problem
TesseractOcrMaui lässt sich nur innerhalb eines MAUI-Projekts kompilieren. Sobald ein anderer Projekttyp OCR benötigt, bricht die Architektur zusammen:
// 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
}
// 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
}
##IronOCR vs. TesseractOcrMaui: Funktionsvergleich
Die folgende Tabelle behandelt die Funktionsunterschiede, die für Teams relevant sind, die diese Migration evaluieren.
| Feature | TesseractOcrMaui | IronOCR |
|---|---|---|
| .NET MAUI (iOS) | Ja | Ja (IronOcr.iOS) |
| .NET MAUI (Android) | Ja | Ja (IronOcr.Android) |
| .NET MAUI (Windows) | Ja | Ja |
| ASP.NET Core | Nein | Ja |
| Azure Functions | Nein | Ja |
| AWS Lambda | Nein | Ja |
| Docker / Linux-Container | Nein | Ja |
| Konsolenanwendungen | Nein | Ja |
| WPF/WinForms | Nein | Ja |
| Gemeinsam genutzte .NET Klassenbibliothek | Nein | Ja |
| PDF-Eingabe (nativ) | Nein | Ja |
| Passwortgeschützte PDF-Eingabe | Nein | Ja |
| Stream-Eingabe | Nein | Ja |
| Byte-Array-Eingabe | Nein | Ja |
| Mehrseitige TIFF-Eingabe | Nein | Ja |
| Durchsuchbare PDF-Ausgabe | Nein | Ja |
| hOCR-Export | Nein | Ja |
| Automatischer Entzerrung | Nein | Ja |
| Automatische Rauschunterdrückung | Nein | Ja |
| Kontrastverbesserung | Nein | Ja |
| Binärisierung | Nein | Ja |
| Regionsbasierte OCR | Nein | Ja |
| Barcode-Lesung während der OCR | Nein | Ja |
| Wortkoordinaten | Nein | Ja |
| Mehrsprachige Simultanübertragung | Nein | Ja |
| Unterstützte Sprachen | Manuell gebündelte Trainingsdaten | Mehr als 125 über NuGet -Pakete |
| Gewindesicherheit | Handbuch | Eingebaut |
| Kommerzielle Unterstützung | Keine (Einzelentwickler) | Ja (Iron Software) |
| Lizenzierung | Apache 2.0 (kostenlos) | Unbefristet ab $999 |
| NuGet -Downloads | ~33.900 | 5,3 Mio.+ |
Schnellstart: Migration von TesseractOcrMauizu IronOCR
Schritt 1: Ersetzen des NuGet-Pakets
Entfernen Sie TesseractOcrMauiaus dem MAUI-Projekt:
dotnet remove package TesseractOcrMaui
Installieren Sie IronOCR. Für MAUI-Projekte fügen Sie neben dem Kernpaket die plattformspezifischen Pakete hinzu:
Für serverseitige Projekte (ASP.NET Core, Azure Functions, Konsole):
Auf der Seite des IronOCR-NuGet-Pakets sind alle verfügbaren Plattformpakete aufgeführt.
Schritt 2: Namespaces aktualisieren
Ersetzen Sie TesseractOcrMaui-Namensräume durch den IronOCR-Namespace:
// Before (TesseractOcrMaui)
using TesseractOcrMaui;
using TesseractOcrMaui.Results;
using Microsoft.Maui.Storage;
// After (IronOCR)
using IronOcr;
Schritt 3: Lizenz initialisieren
Lizenzinitialisierung beim Anwendungsstart hinzufügen. In einer MAUI-App geht dies in MauiProgram.cs; in ASP.NET Coregeht es in Program.cs:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"Beispiele für die Code-Migration
Ersetzen der MAUI-Dependency-Injection-Registrierung
TesseractOcrMaui erfordert die Registrierung der OCR-Engine über den MAUI-Dienstanbieter. Das Entfernen dieser Registrierung ist der erste architektonische Schritt, da dadurch der gesamte nachfolgende OCR-Code an den MAUI-Host gebunden wird.
TesseractOcrMaui-Ansatz:
// 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;
}
}
IronOCR Ansatz:
// 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();
}
}
//Neinconstructor 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;
}
}
Das Entfernen von AddTesseractOcr() beseitigt die MAUI DI-Kopplung. Die IronTesseract Klasse hat einen öffentlichen parameterlosen Konstruktor und trägt keine Plattformabhängigkeit — sie kann überall instanziiert werden. Informationen zu Initialisierungsoptionen wie dem Engine-Modus und der Sprachkonfiguration finden Sie im IronTesseract-Einrichtungsleitfaden.
Verlagerung der OCR-Logik in eine gemeinsame Klassenbibliothek
Mit TesseractOcrMauiist es strukturell unmöglich, OCR-Logik projektübergreifend zu nutzen. Mit IronOCR ist der Migrationspfad einfach: Extrahieren Sie den Dienst in eine .NET Standard 2.1 oder net8.0 Klassenbibliothek und referenzieren Sie ihn von jedem Projekt in der Lösung.
TesseractOcrMaui-Ansatz:
// 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
}
IronOCR Ansatz:
// 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;
}
}
}
Eine Klassenbibliothek, eine Gruppe von Tests, ein Genauigkeitsprofil. Die MAUI-App ruft ProcessDocument(photoPath) auf, die ASP.NET CoreAPI ruft ProcessDocumentFromBytes(uploadedBytes) auf, und die Azure-Funktion ruft ProcessDocumentFromStream(blobStream) auf — alle basieren auf der gleichen Implementierung. Der Stream-Eingabeführer und der Bild-Eingabeführer dokumentieren alle OcrInput Ladevarianten.
Aktivieren von serverseitiger OCR in ASP.NET Core
TesseractOcrMaui kann nicht aus einem .NET Core-Projekt aufgerufen werden. Teams, die einen Endpunkt für das Hochladen von Dokumenten hinzufügen, sind gezwungen, auf eine völlig andere Bibliothek zurückzugreifen.IronOCR läuft in ASP.NET Coreohne weitere Konfigurationsänderungen außer der Eingabe des Lizenzschlüssels.
TesseractOcrMaui-Ansatz:
// 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
}
IronOCR Ansatz:
// 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);
}
}
Derselbe Code lässt sich unverändert auf IIS, Kestrel oder einen Linux-Docker-Container bereitstellen. Der ASP.NET-OCR-Leitfaden behandelt die Middleware-Konfiguration, und der Docker-Bereitstellungsleitfaden dokumentiert die Einrichtung von Linux-Containern.
Beseitigung plattformspezifischen Handler-Codes
Die ausschließlich auf MAUI ausgerichtete Architektur von TesseractOcrMauizwingt Entwickler dazu, plattformabhängigen Code zu schreiben, wenn sie versuchen, OCR in Lösungen mit mehreren Zielplattformen zu integrieren.IronOCR macht Plattformabhängigkeiten überflüssig, da dasselbe Paket auf jeder Zielplattform korrekt aufgelöst wird.
TesseractOcrMaui-Ansatz:
// 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 reference TesseractOcrMauiat 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
IronOCR Ansatz:
// 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
Plattformabhängige Bedingungen im OCR-Verarbeitungscode deuten auf eine architektonische Aufspaltung hin, die sich mit der Zeit verstärkt. Jede Änderung der Sprachkonfiguration, jede Anpassung der Vorverarbeitung und jede Optimierung des Konfidenzschwellenwerts muss in beiden Zweigen angewendet werden.IronOCR macht die Aufteilung überflüssig. Die Übersicht über die .NET-OCR-Bibliothek behandelt die Struktur von Multi-Target-Projekten im Detail.
Strukturierte Datenextraktion mit Wortkoordinaten
TesseractOcrMaui stellt nur result.RecognizedText und einen Spitzenvertrauenswert bereit. Das Extrahieren einzelner WORDs mit ihren Begrenzungsrahmen – erforderlich für die Validierung von Formularfeldern, das Parsen von Dokumenten oder Hervorhebungs-Overlays – ist nicht möglich.IronOCR stellt ein vollständiges Dokumentobjektmodell bereit: Seiten, Absätze, Zeilen, Wörter und Zeichen, jeweils mit Pixelkoordinaten.
TesseractOcrMaui-Ansatz:
// 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;
//Neinway to validate against expected field positions
//Neinconfidence per word — only document-level confidence
}
}
IronOCR Ansatz:
// 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; }
}
WORD-Koordinaten ermöglichen die Validierung anhand bekannter Formularvorlagen, die markierungsbasierte Kennzeichnung zur manuellen Überprüfung sowie Hervorhebungen in den Benutzeroberflächen von Dokumentenbetrachtern. Der strukturierte Ergebnisführer dokumentiert das vollständige OcrResult Objektmodell einschließlich zugriff auf Zeichenebene und der Vertrauenswerteführer behandelt pro-Wort-Vertrauensfilterungsmuster.
Hintergrundverarbeitung mit nativem Async und Fortschrittsverfolgung
TesseractOcrMaui stellt eine asynchrone API (RecognizeTextAsync) bereit, jedoch nur innerhalb des MAUI-Anwendungskontexts. Lang laufende Batch-Jobs müssen in einem Hintergrunddienst, einer Azure-Funktion oder einem Worker-Prozess ausgeführt werden – keine dieser Optionen kann von TesseractOcrMauiangesprochen werden.IronOCR bietet native Async-Unterstützung, die in jedem gehosteten Dienst funktioniert.
TesseractOcrMaui-Ansatz:
// 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 reference TesseractOcrMauiwill fail to compile:
// error: Package TesseractOcrMauidoes not support target net8.0
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
throw new PlatformNotSupportedException(
"TesseractOcrMaui has no server target. Use a different OCR library.");
}
}
IronOCR Ansatz:
// 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);
}
}
}
Der Worker registriert sich in Program.cs mit builder.Services.AddHostedService<DocumentBatchWorker>() und läuft in jedem .NET 8-Host — Windows Service, Linux systemd-Einheit, Docker-Container oder Azure Container App. Der asynchrone OCR-Führer behandelt asynchrone Muster und der durchsuchbarer PDF-Führer dokumentiert die SaveAsSearchablePdf Ausgabeoptionen.
TesseractOcrMaui-API-zu-IronOCR-Zuordnungsreferenz
| TesseractOcrMaui | IronOCR-Äquivalent |
|---|---|
dotnet add package TesseractOcrMaui | dotnet add package IronOcr |
builder.Services.AddTesseractOcr() | Vollständig entfernen – keine Registrierung erforderlich |
ITesseract (injiziert) | new IronTesseract() (direkte Instanziierung) |
_tesseract.InitAsync("eng") | ocr.Language = OcrLanguage.English; (oder weglassen für standardmäßiges Englisch) |
_tesseract.RecognizeTextAsync(imagePath) | ocr.Read(input) |
result.RecognizedText | result.Text |
result.Success | Ausnahmebasiert; kein boolesches Flag |
result.Status | catch (Exception ex) Nachricht |
result.Confidence | result.Confidence (auch pro-Wort) |
TesseractOcrMaui.Results.RecognitionResult | IronOcr.OcrResult |
<MauiAsset> traineddata-Bundle | dotnet add package IronOcr.Languages.French |
Resources/Raw/tessdata/eng.traineddata | Entfernen – Sprachdaten befinden sich im NuGet-Paket |
FileSystem.OpenAppPackageFileAsync() (für traineddata) | Entfernen – nicht erforderlich |
| Keine PDF-Unterstützung | input.LoadPdf(path) oder input.LoadPdf(stream) |
| Keine Vorverarbeitung | input.Deskew(), input.DeNoise(), input.Binarize(), input.Contrast() |
| Keine durchsuchbare PDF-Ausgabe | result.SaveAsSearchablePdf(outputPath) |
| Keine Wortkoordinaten | result.Pages[0].Words[i].X, .Y, .Width, .Height |
| Keine Wort-für-Wort-Übersetzung | result.Pages[0].Words[i].Confidence |
net8.0-ios Nur-Ziel | net8.0 + IronOcr.iOS Paket |
net8.0-android Nur-Ziel | net8.0 + IronOcr.Android Paket |
Gängige Migrationsprobleme und Lösungen
Problem 1: AddTesseractOcr kann nicht entfernt werden, ohne abhängige Klassen zu beeinträchtigen
TesseractOcrMaui: Jede Klasse, die OCR durchführt, erhält ITesseract durch Konstruktorinjektion. Das Entfernen von AddTesseractOcr() bricht sofort diese Konstruktoren mit einer DI-Auflösungs-Ausnahme.
Lösung: Entfernen Sie den Konstruktorparameter und ersetzen Sie ihn durch direkte IronTesseract Instanziierung. Wenn das Projekt einen DI-Container verwendet und Sie das injizierbare Muster beibehalten möchten, registrieren Sie IronTesseract manuell:
// 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;
}
}
Problem 2: Fehlende Trainingsdatendateien nach der Deinstallation des Pakets
TesseractOcrMaui: Der Resources/Raw/tessdata/ Ordner, die .traineddata Dateien darin und die <MauiAsset> Deklarationen in der .csproj müssen alle entfernt werden. Werden sie nicht entfernt, führt dies zu Build-Warnungen und vergrößert das App-Bundle durch ungenutzte Dateien.
Lösung: Löschen Sie den tessdata-Ordner, entfernen Sie die <MauiAsset> Einträge und deinstallieren Sie alle Sprachen, die manuell heruntergeladen wurden. Installieren Sie stattdessen das entsprechende IronOCR-Sprachpaket:
# 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
Sprachpakete von IronOCR werden zur Erstellungszeit aufgelöst und ohne manuelle Dateiverwaltung gebündelt. Der Leitfaden für mehrere Sprachen dokumentiert alle verfügbaren Pakete und die Konfiguration für mehrere Sprachen gleichzeitig.
Problem 3: InitAsync muss vor jedem RecognizeTextAsync aufgerufen werden
TesseractOcrMaui: Der ITesseract.InitAsync(language) Aufruf muss jedem RecognizeTextAsync Aufruf vorausgehen. Teams fügen oft _isInitialized Schutzflaggen, doppelt überprüfte Verriegelung oder Semaphoren hinzu, um wiederholte initialisierungen zu vermeiden. All dieser Code wird nach der Migration zu totem Code.
Lösung: IronTesseract hat keinen Initialisierungsschritt. Sprache wird einmal auf der Instanz festgelegt. Entfernen Sie alle InitAsync Aufrufe, alle _isInitialized Flaggen und alle Initialisierungsschutzlogik:
// 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;
}
Problem 4: Das Muster "result.Success Check" muss ersetzt werden
TesseractOcrMaui: Der RecognizeTextAsync Rückgabewert trägt einen Success Boolean und einen Status String. Code, der if (!result.Success) überprüft und result.Status für Fehlerinformationen liest, muss umgeschrieben werden.
**Lösung:**IronOCR verwendet die Standard-Ausnahmesemantik von .NET. Ersetzen Sie die Erfolgsprüfungen durch try/catch. Bei Erfolg wird .Text immer gefüllt (leerer String, wenn kein Text gefunden wurde):
// 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;
}
Thema 5: MAUI-exklusives Ziel-Framework in Shared-Library-Projekten
TesseractOcrMaui: Eine Klassenbibliothek, die TesseractOcrMaui referenziert, erbt automatisch ihre Plattformbeschränkung. Die <TargetFramework> der Bibliothek muss auf einen MAUI-Moniker gesetzt werden (net8.0-android, net8.0-ios oder net8.0-windows), was verhindert, dass sie von Serverprojekten referenziert wird.
Lösung: Ändern Sie das Klassenbibliotheksziel auf net8.0 oder netstandard2.1 und referenzieren Sie stattdessen IronOcr. Die Bibliothek wird nun von jedem aufrufenden Projekt korrekt aufgelöst:
<!-- Before: locked to MAUI target because TesseractOcrMauihas 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="*" />
Problem 6: Für die PDF-Verarbeitung muss eine zweite Bibliothek entfernt werden
TesseractOcrMaui: Teams, die PDF-Unterstützung implementiert haben, fügten eine zweite Bibliothek (PDFium, PdfPig oder ein Cloud-Rendierer) hinzu, um PDF-Seiten in Bilder zu konvertieren, bevor sie an RecognizeTextAsync übergeben werden. Nach der Migration zu IronOCR können diese zweite Bibliothek und der gesamte Code zur Seitenrendering gelöscht werden.
Lösung: Entfernen Sie die PDF-Rendering-Bibliothek und ersetzen Sie die gesamte Seitenauszugspipeline durch 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;
Das PDF-Eingabehandbuch behandelt die Auswahl von Seitenbereichen, passwortgeschützte PDFs und das stream-basierte Laden.
TesseractOcrMaui-Migrationscheckliste
Vor der Migration
Überprüfen Sie den Code, um alle Verwendungen von TesseractOcrMauizu erfassen, bevor Sie Änderungen am Code vornehmen:
# Find all files that reference TesseractOcrMauinamespaces
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" .
Beachten Sie jede Klasse, die ITesseract in einem Konstruktor verwendet — diese Konstruktoren werden sich ändern. Beachten Sie jede Projektdatei, die <MauiAsset> für traineddata deklariert — diese Deklarationen werden gelöscht. Stellen Sie fest, ob eine PDF-Rendering-Bibliothek vorhanden ist und ob diese ausschließlich für die OCR-Vorverarbeitung verwendet wird.
Code-Migration
- Führen Sie
dotnet remove package TesseractOcrMauiin jedem Projekt aus, das es referenziert - Führen Sie
dotnet add package IronOcrin jedem Projekt aus, das OCR durchführen wird - Führen Sie
dotnet add package IronOcr.Androidin MAUI-Projekten aus, die auf Android abzielen - Führen Sie
dotnet add package IronOcr.iOSin MAUI-Projekten aus, die auf iOS abzielen - Führen Sie
dotnet add package IronOcr.Languages.*für jede nicht-englische Sprache aus, die zuvor als traineddata gebündelt war - Fügen Sie
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";beim Anwendungsstart in jedem Einstiegspunktprojekt hinzu - Löschen Sie
Resources/Raw/tessdata/und alle.traineddataDateien aus MAUI-Projekten - Entfernen Sie alle
<MauiAsset Include="Resources\Raw\tessdata\*.traineddata" />Zeilen aus.csprojDateien - Entfernen Sie
builder.Services.AddTesseractOcr()aus allenMauiProgram.csDateien - Ersetzen Sie alle
using TesseractOcrMaui;undusing TesseractOcrMaui.Results;durchusing IronOcr; - Entfernen Sie
ITesseractKonstruktorparameter aus allen Dienst- und View-Model-Klassen - Ersetzen Sie
await _tesseract.InitAsync("eng")Aufrufe durchocr.Language = OcrLanguage.English;, wenn nötig (Standard ist Englisch) - Ersetzen Sie
await _tesseract.RecognizeTextAsync(imagePath)durchocr.Read(input)mithilfe einerOcrInputInstanz - Ersetzen Sie
result.RecognizedTextdurchresult.Text - Ersetzen Sie
if (!result.Success)Prüfungen durch try/catch Blöcke - Wenn eine PDF-Rendering-Bibliothek lediglich zur Unterstützung von TesseractOcrMauihinzugefügt wurde, entfernen Sie sie und ersetzen Sie den Seitenauszugscode mit
input.LoadPdf() - Ändern Sie jedes MAUI-exklusive Ziel-Framework in Klassenbibliotheken, die OCR-Logik enthalten, auf
net8.0odernetstandard2.1
Nach der Migration
- Überprüfen Sie, ob die OCR-Funktion Text aus einem JPEG-Bild erzeugt, das mit der Kamera des Geräts sowohl auf iOS- als auch auf Android-Zielgeräten aufgenommen wurde
- Überprüfen Sie, dass OCR Text aus dem gleichen Bild erzeugt, das über
byte[]im serverseitigen API-Endpunkt geladen wurde - Stellen Sie sicher, dass die gemeinsam genutzte Klassenbibliothek identisch kompiliert und ausgeführt wird, wenn sie sowohl von MAUI- als auch von .NET Core-Projekten referenziert wird
- Testen Sie, ob die PDF-Eingabe durchgängig funktioniert, ohne dass temporäre Dateien erstellt werden
- Überprüfen Sie, dass
SaveAsSearchablePdfAusgabe im PDF-Viewer durchsuchbar ist - Bestätigen Sie, dass Vertrauenswerte auf
result.Confidenceund aufpage.Words[i].Confidencevorhanden sind - Überprüfen Sie, ob die MAUI-App ein fehlerfreies Startprotokoll ohne Ausnahmen wegen nicht gefundener trainierter Datendateien erzeugt
- Überprüfen Sie, dass der
Resources/Raw/tessdata/Ordner in MAUI-App-Paket in Release-Builds nicht vorhanden ist - Führen Sie einen parallelen Batch-Job mit 10 oder mehr Dokumenten durch, um die Thread-Sicherheit zu überprüfen
- Bestätigen Sie, dass
InitAsyncEntfernung keine aufgehobenen Semaphore oder_isInitializedZustandsvariablen in einer Dienstklasse hinterlässt
Wichtigste Vorteile der Migration zu IronOCR
Eine Codebasis über das gesamte Produkt hinweg. Nach der Migration ruft jedes Projekt in der Lösung — MAUI mobile App, ASP.NET CoreAPI, Azure-Funktion, Hintergrund-Worker — die gleiche DocumentOcrService Klasse aus der gleichen geteilten Bibliothek auf. Die Sprachkonfiguration, die Einstellungen für die Vorverarbeitung und die Feinabstimmung der Genauigkeit erfolgen an einem Ort. Wenn ein neuer Dokumenttyp einen neuen Vorverarbeitungsfilter erfordert, wird die Änderung einmalig vorgenommen und gilt dann überall.
**Serverseitige Bereitstellung ohne Neuprogrammierung.**IronOCR lässt sich ohne Änderungen auf Linux-Containern, Windows Server, Azure App Service, AWS Lambdaund jeder anderen .NET 8-Laufzeitumgebung bereitstellen. Die gleiche IronTesseract Instanz, die mobile Kamera-Erfassungen verarbeitet, verarbeitet auch serverseitige PDF-Uploads. Der Azure-Bereitstellungsleitfaden und der AWS-Bereitstellungsleitfaden dokumentieren die plattformspezifischen Konfigurationsschritte.
PDF-Verarbeitung ohne zweite Bibliothek. Native PDF-Eingabe über input.LoadPdf() eliminiert die PDF-Rendering-Bibliothek, die Seiten-für-Seiten-Bilderfassungs-Schleife, die temporäre Dateiverwaltung und den Bereinigungscode, den TesseractOcrMauierfordert. Gescanntes PDF-Verträge, Rechnungen und Identitätsdokumente werden in einem einzigen Schritt geladen. Der gleiche OCR-Durchgang, der Text extrahiert, kann ein durchsuchbares PDF mit result.SaveAsSearchablePdf() erstellen — eine Fähigkeit, die TesseractOcrMauiauf keiner Ebene bieten kann.
Vorverarbeitung, die echte mobile Bilder behandelt. input.Deskew(), input.DeNoise(), input.Binarize() und input.Sharpen() sind Einzelmethodenaufrufe, die kalibrierte Bildkorrekturen anwenden, bevor die Tesseract-Engine die Daten sieht. Teams, die bei mobilen Aufnahmen bei schlechten Lichtverhältnissen ohne Vorverarbeitung eine Genauigkeit von 40–60 % akzeptierten, erreichen nach Hinzufügen einer Pipeline mit drei Filtern üblicherweise 85–90 %+. Kein SkiaSharp, kein ImageSharp, keine Algorithmus-Implementierung erforderlich. Der Leitfaden zur Bildqualitätskorrektur dokumentiert jeden verfügbaren Filter und wann dieser anzuwenden ist.
Kommerzieller Support mit festgelegten Eskalationsstufen. Iron Software bietet E-Mail-Support für alle IronOCR-Lizenzstufen sowie priorisierten Telefon- und Chat-Support auf den Stufen "Professional" und "Enterprise". Wenn ein Plattform-Update die Auflösung nativer Bibliotheken auf einer bestimmten Android-API-Ebene unterbricht – eine Art von Fehler, die TesseractOcrMauis GitHub-Issue-Queue in der Freizeit von Freiwilligen bearbeitet –, gibt es ein echtes Entwicklerteam, das zur Reaktion verpflichtet ist. Unbefristete Lizenz beginnt bei $999 für die Lite-Stufe; Auf der Lizenzseite sind alle Tarife und die darin enthaltenen Support-Leistungen aufgeführt.
Über 125 Sprachen über NuGet ohne Aufblähung des App-Bundles. TesseractOcrMauibündelt trainierte Datendateien innerhalb der MAUI-App – jede Sprache erhöht die Downloadgröße der App um 10–50 MB. IronOCR-Sprachpakete werden über NuGet installiert und sind nur in serverseitigen Builds oder in Plattform-Builds enthalten, in denen sie explizit referenziert werden. Mobile App-Pakete bleiben schlank; Serverseitige Builds erhalten den vollständigen Sprachsatz. Das Hinzufügen einer neuen Sprache ist ein dotnet add package Befehl ohne Änderungen an der Projektdatei und ohne Dateiverwaltung. Der vollständige Sprachkatalog listet alle über 125 verfügbaren Pakete auf.
