Zum Fußzeileninhalt springen
VIDEOS

Umstellung von Charlesw Tesseract auf IronOCR

Diese Anleitung führt .NET-Entwickler durch die Migration vom charlesw/tesseract NuGet-Paket (Tesseract) zu IronOCR. Die Migration konzentriert sich auf ein spezifisches Problem: das native Binärbereitstellungsmodell, das der charlesw-Wrapper auferlegt, und den plattformabhängigen Code, den dieses Modell Entwickler zwingen kann zu schreiben. Teams, die in CI mit DllNotFoundException gekämpft haben, sich mit Leptonica-Bibliothekspfaden unter Linux auseinandersetzen mussten oder Betriebssystem-Erkennungsblöcke geschrieben haben, die nichts mit OCR zu tun hatten, werden feststellen, dass diese Anleitung genau zeigt, was nach dem Wechsel verschwindet.

Warum von Charles Tesserakt migrieren?

Das archivierte charlesw/tesseract Paket bringt neue Projekte in Schwierigkeiten, nicht weil die API schlecht ist, sondern weil das erforderliche Bereitstellungsmodell auf Annahmen basiert, die in moderner .NET-Infrastruktur nicht mehr gültig sind. Folgendes beeinflusst Migrationsentscheidungen:

Native Binärbereitstellung pro Plattform. Das Tesseract NuGet-Paket enthält plattformspezifische native Binärdaten: tesseract50.dll für Windows x64, ein separates Build für x86, libtesseract.so für Linux x64. Diese Binärdaten müssen zur Laufzeit am richtigen Ort landen, damit die P/Invoke-Aufrufe erfolgreich sind. Auf einer Entwickler-Workstation kopiert das SDK sie automatisch. In einem Docker-Container, einem ARM64-Build-Agent oder einem Azure App Service mit einem nicht standardmäßigen Anwendungsstammverzeichnis ist dies nicht der Fall. Jedes neue Bereitstellungsziel wird zu einer Debugging-Sitzung.

Leptonica als versteckte Abhängigkeit. Das Laden von Bildern durch Tesseract wird von der Leptonica-Bibliothek übernommen, die als eigener Satz nativer DLLs zusammen mit den Tesseract-Binärdateien ausgeliefert wird. Unter Windows muss leptonica-1.82.0.dll im Ausgabeverzeichnis vorhanden sein. Unter Linux muss die Leptonica-Shared-Library entweder als Paket mitgeliefert oder als Systempaket installiert werden. Debian-basierte Docker-Images ohne libleptonica-dev schlagen bei Pix.LoadFromFile() mit einer wenig hilfreichen nativen Ausnahme fehl, und die Behebung erfordert das Wissen, welches Systempaket die Abhängigkeit auflöst.

Plattformabhängiger Code in der Anwendungslogik. Die Kombination aus nativem Binärladen und der Lösung des Tessdata-Pfads zwingt Entwickler, RuntimeInformation.IsOSPlatform() Überprüfungen zu schreiben, Umgebungsvariablen für Containerkontexte zu erkennen und eine Pfadlogik zu erstellen, die je nach Ziel variiert. Keiner dieser Codeabschnitte ist OCR-Logik. Es handelt sich um eine Bereitstellungsinfrastruktur, die nur deshalb existiert, weil die Binärverwaltung des Pakets unvollständig ist.

Archiviertes Paket ohne Aktualisierungsmöglichkeit. Das Repository ist seit 2021 archiviert. Wenn ein Systempaket-Update auf einem Linux-Host die Leptonica-ABI ändert oder eine neue .NET Laufzeitumgebung das Verhalten beim Laden nativer Binärdateien ändert, steht keine Version zum Aktualisieren zur Verfügung. Die einzigen Optionen sind entweder das Forken der nativen Build-Pipeline oder das Ersetzen der Bibliothek.

Tesseract 4.1.1 Engine-Absturz. Das Paket enthält Tesseract 4.1.1. Das neu geschriebene LSTM-Modell von Tesseract 5 liefert eine deutlich höhere Genauigkeit bei Dokumenten mit Qualitätsverlust. Dieses Upgrade ist nicht über das charlesw-Paket verfügbar – es erfordert einen Bibliothekswechsel.

Vertrauensbehandlung ohne einen Standardmuster. Der charlesw-Wrapper stellt page.GetMeanConfidence() als Float zwischen 0 und 1 bereit, aber die Anwendung von Vertrauensschwellenwerten auf Wort- oder Zeichenebene erfordert das Iteratormuster mit iter.GetConfidence(PageIteratorLevel.Word). Es gibt keine standardisierte Filter-API; Jedes Team implementiert seine eigene Schwellenwertlogik auf unterschiedliche Weise.

Das grundsätzliche Problem

Der CharlesW-Wrapper benötigt eine plattformspezifische native Binärkonfiguration, bevor die OCR-Funktion ausgeführt werden kann:

// charlesw Tesseract: OS detection required just to find native DLLs
// DllNotFoundException on any platform where binaries do not resolve
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
    Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib");
}
var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath); // Requires leptonica native DLL
using var page = engine.Process(img);
return page.GetText();
// charlesw Tesseract: OS detection required just to find native DLLs
// DllNotFoundException on any platform where binaries do not resolve
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
    Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib");
}
var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
using var img = Pix.LoadFromFile(imagePath); // Requires leptonica native DLL
using var page = engine.Process(img);
return page.GetText();
Imports System
Imports System.Runtime.InteropServices
Imports Tesseract

' charlesw Tesseract: OS detection required just to find native DLLs
' DllNotFoundException on any platform where binaries do not resolve
If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
    Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", "/app/lib")
End If

Dim engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
Using img As Pix = Pix.LoadFromFile(imagePath) ' Requires leptonica native DLL
    Using page As Page = engine.Process(img)
        Return page.GetText()
    End Using
End Using
$vbLabelText   $csharpLabel

IronOCR verfügt über keine native Binärkonfiguration:

// IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
// IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read(imagePath).Text;
' IronOCR: no path management, no OS detection, no leptonica dependency
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim text As String = New IronTesseract().Read(imagePath).Text
$vbLabelText   $csharpLabel

IronOCR vs. Charles Tesseract: Funktionsvergleich

Die folgende Tabelle beschreibt die für Teams, die diese Migration bewerten, relevanten Funktionen:

Feature Charles Tesserakt IronOCR
Wartungsstatus Archiviert (keine Aktualisierungen seit 2021) Aktiv gepflegt
Tesseract-Engine-Version 4.1.1 (eingefroren) 5 (aktuell, optimiert)
Lizenz Apache 2.0 (kostenlos) Kommerziell ($999–$2.999 unbefristet)
NuGet -Installation Tesseract IronOcr
Native Binärverwaltung Manuelle DLL-Bereitstellung pro Plattform Komplett ausgestattet, keine Konfiguration erforderlich
Leptonica-Abhängigkeit Erfordert leptonica-1.82.0.dll / libleptonica-dev Nicht zutreffend (wird intern bearbeitet)
Tessdata-Management Manueller Download und .csproj Kopieren-Eintrag NuGet Sprachpakete
Plattformbedingter Code Erforderlich für die Bereitstellung auf mehreren Zielplattformen Nicht erforderlich
Docker-Bereitstellung Erfordert explizite Tessdata COPY + Leptonica apt-get Nur Standardanforderungen an .NET Container
ARM64-Unterstützung Unbestätigter Post-Archiv-Beitrag Gebündelt, validiert
Bildeingabeformate TIFF, PNG, BMP, JPG (über Leptonica) JPG, PNG, BMP, TIFF, GIF und mehr
Mehrseitiges TIFF Manuelle Frame-Iteration input.LoadImageFrames()
Native PDF-Eingabe Nein (erfordert eine zusätzliche Bibliothek) Ja
Durchsuchbare PDF-Ausgabe Nein Ja (result.SaveAsSearchablePdf())
Eingebaute Vorverarbeitung None Entzerren, Rauschen entfernen, Kontrast erhöhen, Binärisierung, Schärfen, Skalieren, Dilatieren, Erodieren, Invertieren
API für Konfidenzfilterung Manueller Iterator mit GetConfidence() result.Confidence, word.Confidence
Strukturierte Ergebnisse Iterator-Muster (ResultIterator) Direkte Sammlungen (Seiten, Absätze, Zeilen, Wörter)
Barcode-Lesung Nein Ja (während der OCR-Durchführung)
Regionsbasierte OCR Nein Ja (CropRectangle)
Thread-Sicherheit Verantwortung des Anrufers Eingebaut
Mehr als 125 Sprachpakete Manuelle Tessdata-Downloads dotnet add package IronOcr.Languages.*
Plattformübergreifendes .NET Ja (.NET Standard 2.0) Ja (.NET Framework 4.6.2+, .NET 5/6/7/8/9)
Sicherheitspatch-Kadenz Keine (archiviert) Regelmäßige Veröffentlichungen

Schnellstart: Charles Tesserakt zu IronOCR Migration

Schritt 1: Ersetzen des NuGet-Pakets

Entfernen Sie das Paket "charlesw Tesseract":

dotnet remove package Tesseract
dotnet remove package Tesseract
SHELL

Installieren Sie IronOCR über NuGet :

dotnet add package IronOcr

Schritt 2: Namespaces aktualisieren

// Before (charlesw Tesseract)
using Tesseract;

// After (IronOCR)
using IronOcr;
// Before (charlesw Tesseract)
using Tesseract;

// After (IronOCR)
using IronOcr;
Imports IronOcr
$vbLabelText   $csharpLabel

Schritt 3: Lizenz initialisieren

Fügen Sie diesen Aufruf einmalig beim Start der Anwendung hinzu, bevor OCR-Operationen ausgeführt werden:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

Auf der IronOCR -Lizenzseite ist eine kostenlose Testlizenz erhältlich. Die Testversion entfernt das Wasserzeichen aus der Ausgabe und ermöglicht den vollen API-Zugriff.

Beispiele für die Code-Migration

Entfernen der Konfiguration des nativen Binärpfads

Das am häufigsten verwendete Initialisierungsmuster in charlesw/tesseract-Projekten ist eine Factory- oder Hilfsklasse, die den tessdata-Pfad erstellt und das Laden nativer Bibliotheken pro Umgebung konfiguriert. Dieser Code existiert ausschließlich aufgrund des Bereitstellungsmodells des Wrappers.

Charlesw Tesseract-Ansatz:

// A realistic factory found in production charlesw/Tesseract projects
public static class OcrEngineFactory
{
    private static string GetTessDataPath()
    {
        // Different path per environment — all wrong until explicitly configured
        if (Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true")
            return "/app/tessdata";                                    // Docker
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            return Path.Combine(AppContext.BaseDirectory, "tessdata"); // Linux bare metal
        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            return "/usr/local/share/tessdata";                        // macOS Homebrew install
        return @".\tessdata";                                          // Windows dev machine
    }

    public static TesseractEngine Create(string language = "eng")
    {
        // If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
        // If tessdata folder is missing: TesseractException at engine construction
        return new TesseractEngine(GetTessDataPath(), language, EngineMode.Default);
    }
}

// Call site
using var engine = OcrEngineFactory.Create();
using var img = Pix.LoadFromFile("invoice.jpg");
using var page = engine.Process(img);
Console.WriteLine(page.GetText());
// A realistic factory found in production charlesw/Tesseract projects
public static class OcrEngineFactory
{
    private static string GetTessDataPath()
    {
        // Different path per environment — all wrong until explicitly configured
        if (Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") == "true")
            return "/app/tessdata";                                    // Docker
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            return Path.Combine(AppContext.BaseDirectory, "tessdata"); // Linux bare metal
        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            return "/usr/local/share/tessdata";                        // macOS Homebrew install
        return @".\tessdata";                                          // Windows dev machine
    }

    public static TesseractEngine Create(string language = "eng")
    {
        // If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
        // If tessdata folder is missing: TesseractException at engine construction
        return new TesseractEngine(GetTessDataPath(), language, EngineMode.Default);
    }
}

// Call site
using var engine = OcrEngineFactory.Create();
using var img = Pix.LoadFromFile("invoice.jpg");
using var page = engine.Process(img);
Console.WriteLine(page.GetText());
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports Tesseract

Public Module OcrEngineFactory
    Private Function GetTessDataPath() As String
        ' Different path per environment — all wrong until explicitly configured
        If Environment.GetEnvironmentVariable("DOTNET_RUNNING_IN_CONTAINER") = "true" Then
            Return "/app/tessdata"                                    ' Docker
        End If
        If RuntimeInformation.IsOSPlatform(OSPlatform.Linux) Then
            Return Path.Combine(AppContext.BaseDirectory, "tessdata") ' Linux bare metal
        End If
        If RuntimeInformation.IsOSPlatform(OSPlatform.OSX) Then
            Return "/usr/local/share/tessdata"                        ' macOS Homebrew install
        End If
        Return ".\tessdata"                                           ' Windows dev machine
    End Function

    Public Function Create(Optional language As String = "eng") As TesseractEngine
        ' If leptonica-1.82.0.dll is not in output directory: DllNotFoundException at this line
        ' If tessdata folder is missing: TesseractException at engine construction
        Return New TesseractEngine(GetTessDataPath(), language, EngineMode.Default)
    End Function
End Module

' Call site
Using engine As TesseractEngine = OcrEngineFactory.Create()
    Using img As Pix = Pix.LoadFromFile("invoice.jpg")
        Using page As Page = engine.Process(img)
            Console.WriteLine(page.GetText())
        End Using
    End Using
End Using
$vbLabelText   $csharpLabel

IronOCR Ansatz:

// IronOCR: no factory, no path logic, no OS detection
// Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var result = new IronTesseract().Read("invoice.jpg");
Console.WriteLine(result.Text);
// IronOCR: no factory, no path logic, no OS detection
// Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var result = new IronTesseract().Read("invoice.jpg");
Console.WriteLine(result.Text);
' IronOCR: no factory, no path logic, no OS detection
' Runs identically on Windows, Linux, macOS, and ARM64
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim result = New IronTesseract().Read("invoice.jpg")
Console.WriteLine(result.Text)
$vbLabelText   $csharpLabel

Die gesamte OcrEngineFactory Klasse wird gelöscht. Die plattformabhängige Pfadlogik, der DOTNET_RUNNING_IN_CONTAINER Check und die Leptonica-DLL-Abhängigkeit verschwinden ebenfalls. In jeder Umgebung – Entwickler-Workstation, CI-Agent, Docker-Container, Cloud-VM – werden die gleichen zwei Zeilen ausgeführt. Die IronTesseract-Einrichtungsanleitung beschreibt Konfigurationsoptionen, wenn Standardeinstellungen angepasst werden müssen, für die meisten Einsatzszenarien ist dies jedoch nicht erforderlich.

Leptonica-Bildkonvertierung – Ersatz

Der charlesw-Wrapper verwendet Leptonicas Pix Typ als seine bildliche Darstellung. Jeder Code, der Bilder vor der OCR-Manipulation bearbeitet, muss durch Pix konvertiert werden, was erfordert, dass die Leptonica native DLL geladen und funktionsfähig ist. Das Ersetzen dieses Musters durch OcrInput eliminiert die Leptonica-Abhängigkeit vollständig.

Charlesw Tesseract-Ansatz:

// Pix is Leptonica's image type — requires leptonica native DLL
// Converting from System.Drawing.Bitmap requires a temp file round-trip
public string ProcessInMemoryImage(Bitmap bitmap)
{
    //Neindirect Bitmap → Pix conversion; must write to temp file
    var tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png");
    try
    {
        bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);

        using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
        using var pix = Pix.LoadFromFile(tempPath);   // Leptonica file I/O
        using var page = engine.Process(pix);

        return page.GetText();
    }
    finally
    {
        if (File.Exists(tempPath)) File.Delete(tempPath);
    }
}
// Pix is Leptonica's image type — requires leptonica native DLL
// Converting from System.Drawing.Bitmap requires a temp file round-trip
public string ProcessInMemoryImage(Bitmap bitmap)
{
    //Neindirect Bitmap → Pix conversion; must write to temp file
    var tempPath = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png");
    try
    {
        bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);

        using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
        using var pix = Pix.LoadFromFile(tempPath);   // Leptonica file I/O
        using var page = engine.Process(pix);

        return page.GetText();
    }
    finally
    {
        if (File.Exists(tempPath)) File.Delete(tempPath);
    }
}
Imports System
Imports System.Drawing
Imports System.IO
Imports Tesseract

Public Class ImageProcessor
    ' Pix is Leptonica's image type — requires leptonica native DLL
    ' Converting from System.Drawing.Bitmap requires a temp file round-trip
    Public Function ProcessInMemoryImage(bitmap As Bitmap) As String
        ' Neindirect Bitmap → Pix conversion; must write to temp file
        Dim tempPath As String = Path.Combine(Path.GetTempPath(), $"ocr_{Guid.NewGuid()}.png")
        Try
            bitmap.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png)

            Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
                Using pix As Pix = Pix.LoadFromFile(tempPath) ' Leptonica file I/O
                    Using page As Page = engine.Process(pix)
                        Return page.GetText()
                    End Using
                End Using
            End Using
        Finally
            If File.Exists(tempPath) Then File.Delete(tempPath)
        End Try
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Ansatz:

// OcrInput accepts byte arrays and streams — no temp file, no Leptonica
public string ProcessInMemoryImage(byte[] imageBytes)
{
    using var input = new OcrInput();
    input.LoadImage(imageBytes);   // Direct byte array loading

    var result = new IronTesseract().Read(input);
    return result.Text;
}

// Or from a stream — same pattern
public string ProcessFromStream(Stream imageStream)
{
    using var input = new OcrInput();
    input.LoadImage(imageStream);

    var result = new IronTesseract().Read(input);
    return result.Text;
}
// OcrInput accepts byte arrays and streams — no temp file, no Leptonica
public string ProcessInMemoryImage(byte[] imageBytes)
{
    using var input = new OcrInput();
    input.LoadImage(imageBytes);   // Direct byte array loading

    var result = new IronTesseract().Read(input);
    return result.Text;
}

// Or from a stream — same pattern
public string ProcessFromStream(Stream imageStream)
{
    using var input = new OcrInput();
    input.LoadImage(imageStream);

    var result = new IronTesseract().Read(input);
    return result.Text;
}
Imports System.IO

' OcrInput accepts byte arrays and streams — no temp file, no Leptonica
Public Function ProcessInMemoryImage(imageBytes As Byte()) As String
    Using input As New OcrInput()
        input.LoadImage(imageBytes)   ' Direct byte array loading

        Dim result = New IronTesseract().Read(input)
        Return result.Text
    End Using
End Function

' Or from a stream — same pattern
Public Function ProcessFromStream(imageStream As Stream) As String
    Using input As New OcrInput()
        input.LoadImage(imageStream)

        Dim result = New IronTesseract().Read(input)
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

Der temporäre Dateiaustausch entfällt. Keine Datei wird auf die Festplatte geschrieben, keine Leptonica-DLL wird für die Konvertierung aufgerufen, und es gibt keinen finally Block zum Aufräumen. Der Eingabe-Bilder-Leitfaden und der Stream-Eingabe-Leitfaden dokumentieren alle unterstützten Eingabequellen, einschließlich des Ladens von URLs und speicherabbildeten Dateien.

Konfidenzschwellenfilterung

Der charlesw-Wrapper zeigt das Vertrauen auf zwei Ebenen: page.GetMeanConfidence() für die gesamte Seite und iter.GetConfidence(PageIteratorLevel.Word) für einzelne Wörter. Das Herausfiltern von Wörtern mit geringer Konfidenz aus der Ausgabe erfordert die manuelle Steuerung einer Iterationsschleife.IronOCR stellt die Konfidenz direkt in den Ergebnisobjekten dar, wodurch die Schwellenwertlogik zu einem LINQ-Ausdruck wird.

Charlesw Tesseract-Ansatz:

// Word-level confidence filtering requires iterator boilerplate
public List<string> ExtractHighConfidenceWords(string imagePath, float minConfidence = 0.8f)
{
    var highConfidenceWords = new List<string>();

    using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
    using var img = Pix.LoadFromFile(imagePath);
    using var page = engine.Process(img);

    // Page-level confidence only: fine-grained requires the iterator
    Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}");

    using var iter = page.GetIterator();
    iter.Begin();
    do
    {
        if (iter.IsAtBeginningOf(PageIteratorLevel.Word))
        {
            var wordText = iter.GetText(PageIteratorLevel.Word)?.Trim();
            var wordConf  = iter.GetConfidence(PageIteratorLevel.Word) / 100f; // Returns 0-100
            if (!string.IsNullOrEmpty(wordText) && wordConf >= minConfidence)
                highConfidenceWords.Add(wordText);
        }
    } while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word));

    return highConfidenceWords;
}
// Word-level confidence filtering requires iterator boilerplate
public List<string> ExtractHighConfidenceWords(string imagePath, float minConfidence = 0.8f)
{
    var highConfidenceWords = new List<string>();

    using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
    using var img = Pix.LoadFromFile(imagePath);
    using var page = engine.Process(img);

    // Page-level confidence only: fine-grained requires the iterator
    Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}");

    using var iter = page.GetIterator();
    iter.Begin();
    do
    {
        if (iter.IsAtBeginningOf(PageIteratorLevel.Word))
        {
            var wordText = iter.GetText(PageIteratorLevel.Word)?.Trim();
            var wordConf  = iter.GetConfidence(PageIteratorLevel.Word) / 100f; // Returns 0-100
            if (!string.IsNullOrEmpty(wordText) && wordConf >= minConfidence)
                highConfidenceWords.Add(wordText);
        }
    } while (iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word));

    return highConfidenceWords;
}
Imports System
Imports Tesseract

Public Class WordExtractor
    Public Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Single = 0.8F) As List(Of String)
        Dim highConfidenceWords As New List(Of String)()

        Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
            Using img As Pix = Pix.LoadFromFile(imagePath)
                Using page As Page = engine.Process(img)
                    ' Page-level confidence only: fine-grained requires the iterator
                    Console.WriteLine($"Page confidence: {page.GetMeanConfidence():P1}")

                    Using iter As ResultIterator = page.GetIterator()
                        iter.Begin()
                        Do
                            If iter.IsAtBeginningOf(PageIteratorLevel.Word) Then
                                Dim wordText As String = iter.GetText(PageIteratorLevel.Word)?.Trim()
                                Dim wordConf As Single = iter.GetConfidence(PageIteratorLevel.Word) / 100.0F ' Returns 0-100
                                If Not String.IsNullOrEmpty(wordText) AndAlso wordConf >= minConfidence Then
                                    highConfidenceWords.Add(wordText)
                                End If
                            End If
                        Loop While iter.Next(PageIteratorLevel.Para, PageIteratorLevel.Word)
                    End Using
                End Using
            End Using
        End Using

        Return highConfidenceWords
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Ansatz:

// Confidence is a property on each result object — no iterator required
public List<string> ExtractHighConfidenceWords(string imagePath, double minConfidence = 80.0)
{
    var result = new IronTesseract().Read(imagePath);

    Console.WriteLine($"Page confidence: {result.Confidence}%");

    // LINQ directly on the word collection — no iterator state management
    return result.Pages
        .SelectMany(p => p.Lines)
        .SelectMany(l => l.Words)
        .Where(w => w.Confidence >= minConfidence && !string.IsNullOrWhiteSpace(w.Text))
        .Select(w => w.Text)
        .ToList();
}
// Confidence is a property on each result object — no iterator required
public List<string> ExtractHighConfidenceWords(string imagePath, double minConfidence = 80.0)
{
    var result = new IronTesseract().Read(imagePath);

    Console.WriteLine($"Page confidence: {result.Confidence}%");

    // LINQ directly on the word collection — no iterator state management
    return result.Pages
        .SelectMany(p => p.Lines)
        .SelectMany(l => l.Words)
        .Where(w => w.Confidence >= minConfidence && !string.IsNullOrWhiteSpace(w.Text))
        .Select(w => w.Text)
        .ToList();
}
Imports System
Imports System.Collections.Generic
Imports System.Linq

Public Function ExtractHighConfidenceWords(imagePath As String, Optional minConfidence As Double = 80.0) As List(Of String)
    Dim result = New IronTesseract().Read(imagePath)

    Console.WriteLine($"Page confidence: {result.Confidence}%")

    ' LINQ directly on the word collection — no iterator state management
    Return result.Pages _
        .SelectMany(Function(p) p.Lines) _
        .SelectMany(Function(l) l.Words) _
        .Where(Function(w) w.Confidence >= minConfidence AndAlso Not String.IsNullOrWhiteSpace(w.Text)) _
        .Select(Function(w) w.Text) _
        .ToList()
End Function
$vbLabelText   $csharpLabel

Der Iterator-Zustandsautomat ist verschwunden. Die Konfidenzwerte in IronOCR liegen durchgehend auf einer Skala von 0 bis 100, eine Division durch 100 ist nicht erforderlich. Der Leitfaden zu den Konfidenzwerten umfasst Konfidenzmuster pro Wort, pro Zeile und pro Seite. Der Leitfaden zu den Leseergebnissen zeigt, wie man durch die vollständige strukturierte Ergebnishierarchie navigiert.

Stapelverarbeitung von mehrseitigen TIFF-Dateien

TIFF-Dateien mit mehreren Einzelbildern sind in Dokumentenscanning-Workflows üblich. Der charlesw-Wrapper verfügt über keine integrierte Unterstützung für Multi-Frame-TIFF; Jedes Einzelbild muss vor der Weiterverarbeitung manuell extrahiert werden.IronOCR verarbeitet Mehrbild-TIFFs nativ mit einem einzigen Ladeaufruf.

Charlesw Tesseract-Ansatz:

// charlesw/Tesseract has no multi-frame TIFF support
// Each frame must be extracted via System.Drawing before OCR can run
public string ProcessMultiFrameTiff(string tiffPath)
{
    var fullText = new StringBuilder();

    using var tiffImage = Image.FromFile(tiffPath);
    var frameCount = tiffImage.GetFrameCount(FrameDimension.Page);

    using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);

    for (int i = 0; i < frameCount; i++)
    {
        tiffImage.SelectActiveFrame(FrameDimension.Page, i);

        // Must save each frame as a temp file for Pix to load
        var tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png");
        try
        {
            tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);

            using var pix  = Pix.LoadFromFile(tempPath);
            using var page = engine.Process(pix);
            fullText.AppendLine(page.GetText());
        }
        finally
        {
            if (File.Exists(tempPath)) File.Delete(tempPath);
        }
    }

    return fullText.ToString();
}
// charlesw/Tesseract has no multi-frame TIFF support
// Each frame must be extracted via System.Drawing before OCR can run
public string ProcessMultiFrameTiff(string tiffPath)
{
    var fullText = new StringBuilder();

    using var tiffImage = Image.FromFile(tiffPath);
    var frameCount = tiffImage.GetFrameCount(FrameDimension.Page);

    using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);

    for (int i = 0; i < frameCount; i++)
    {
        tiffImage.SelectActiveFrame(FrameDimension.Page, i);

        // Must save each frame as a temp file for Pix to load
        var tempPath = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png");
        try
        {
            tiffImage.Save(tempPath, System.Drawing.Imaging.ImageFormat.Png);

            using var pix  = Pix.LoadFromFile(tempPath);
            using var page = engine.Process(pix);
            fullText.AppendLine(page.GetText());
        }
        finally
        {
            if (File.Exists(tempPath)) File.Delete(tempPath);
        }
    }

    return fullText.ToString();
}
Imports System.Drawing
Imports System.Drawing.Imaging
Imports Tesseract
Imports System.IO
Imports System.Text

Public Function ProcessMultiFrameTiff(tiffPath As String) As String
    Dim fullText As New StringBuilder()

    Using tiffImage As Image = Image.FromFile(tiffPath)
        Dim frameCount As Integer = tiffImage.GetFrameCount(FrameDimension.Page)

        Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
            For i As Integer = 0 To frameCount - 1
                tiffImage.SelectActiveFrame(FrameDimension.Page, i)

                ' Must save each frame as a temp file for Pix to load
                Dim tempPath As String = Path.Combine(Path.GetTempPath(), $"tiff_frame_{i}.png")
                Try
                    tiffImage.Save(tempPath, Imaging.ImageFormat.Png)

                    Using pix As Pix = Pix.LoadFromFile(tempPath)
                        Using page As Page = engine.Process(pix)
                            fullText.AppendLine(page.GetText())
                        End Using
                    End Using
                Finally
                    If File.Exists(tempPath) Then File.Delete(tempPath)
                End Try
            Next
        End Using
    End Using

    Return fullText.ToString()
End Function
$vbLabelText   $csharpLabel

IronOCR Ansatz:

// LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
public string ProcessMultiFrameTiff(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath);   // All frames loaded in one call

    var result = new IronTesseract().Read(input);

    // Pages maps directly to TIFF frames
    foreach (var page in result.Pages)
        Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words");

    return result.Text;
}
// LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
public string ProcessMultiFrameTiff(string tiffPath)
{
    using var input = new OcrInput();
    input.LoadImageFrames(tiffPath);   // All frames loaded in one call

    var result = new IronTesseract().Read(input);

    // Pages maps directly to TIFF frames
    foreach (var page in result.Pages)
        Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words");

    return result.Text;
}
Imports System
Imports IronOcr

Public Class TiffProcessor
    ' LoadImageFrames handles multi-frame TIFFs natively — no frame extraction loop
    Public Function ProcessMultiFrameTiff(tiffPath As String) As String
        Using input As New OcrInput()
            input.LoadImageFrames(tiffPath) ' All frames loaded in one call

            Dim result = New IronTesseract().Read(input)

            ' Pages maps directly to TIFF frames
            For Each page In result.Pages
                Console.WriteLine($"Frame {page.PageNumber}: {page.Words.Count()} words")
            Next

            Return result.Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Die Schleife zum Extrahieren temporärer Dateien und die Entsorgungskette pro Frame wurden entfernt. Die Erkennung der Bildanzahl über FrameDimension.Page verschwindet.IronOCR mappt TIFF-Frames zu OcrResult.Pages, sodass für den Zugriff auf Einzelbild-Text keine zusätzliche Iterationslogik erforderlich ist. Der Leitfaden zur TIFF/GIF-Eingabe beschreibt zusätzliche Optionen zur Einzelbildauswahl und zur partiellen TIFF-Verarbeitung.

durchsuchbare PDF-Generierung

Der charlesw-Wrapper erzeugt nur Textausgabe. Das Konvertieren eines gescannten Dokuments in ein durchsuchbares PDF — ein häufiges Erfordernis für Dokumentenverwaltungssysteme — benötigt eine sekundäre PDF-Bibliothek (IronPDF, PDFSharp oder Ähnliches), um den extrahierten Text auf die Originalbilderseiten zu überlagern.IronOCR erzeugt durchsuchbare PDFs mit nur einem Methodenaufruf, ohne dass eine zusätzliche Bibliothek benötigt wird.

Charlesw Tesseract-Ansatz:

// charlesw/Tesseract produces text only.
// Creating a searchable PDF requires a second library and significant code.
// The pattern below is representative — actual implementation varies by PDF library.
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
    // Step 1: Extract text from image
    string extractedText;
    using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
    using var img = Pix.LoadFromFile(imagePath);
    using var page = engine.Process(img);
    extractedText = page.GetText();

    // Step 2: Build a PDF with the image as background and text overlay
    // Requires a separate PDF library (not shown — 50-100+ additional lines)
    // The text layer must be positioned to match the original image layout
    // Word-level coordinates from the iterator are needed for accurate alignment
    throw new NotImplementedException(
        "Searchable PDF generation requires a separate PDF library. " +
        "Add PdfSharp, IronPDF, or similar, then implement text layer overlay.");
}
// charlesw/Tesseract produces text only.
// Creating a searchable PDF requires a second library and significant code.
// The pattern below is representative — actual implementation varies by PDF library.
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
    // Step 1: Extract text from image
    string extractedText;
    using var engine = new TesseractEngine(@"./tessdata", "eng", EngineMode.Default);
    using var img = Pix.LoadFromFile(imagePath);
    using var page = engine.Process(img);
    extractedText = page.GetText();

    // Step 2: Build a PDF with the image as background and text overlay
    // Requires a separate PDF library (not shown — 50-100+ additional lines)
    // The text layer must be positioned to match the original image layout
    // Word-level coordinates from the iterator are needed for accurate alignment
    throw new NotImplementedException(
        "Searchable PDF generation requires a separate PDF library. " +
        "Add PdfSharp, IronPDF, or similar, then implement text layer overlay.");
}
Imports Tesseract

Public Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
    ' Step 1: Extract text from image
    Dim extractedText As String
    Using engine As New TesseractEngine("./tessdata", "eng", EngineMode.Default)
        Using img As Pix = Pix.LoadFromFile(imagePath)
            Using page As Page = engine.Process(img)
                extractedText = page.GetText()
            End Using
        End Using
    End Using

    ' Step 2: Build a PDF with the image as background and text overlay
    ' Requires a separate PDF library (not shown — 50-100+ additional lines)
    ' The text layer must be positioned to match the original image layout
    ' Word-level coordinates from the iterator are needed for accurate alignment
    Throw New NotImplementedException("Searchable PDF generation requires a separate PDF library. " & _
                                      "Add PdfSharp, IronPDF, or similar, then implement text layer overlay.")
End Sub
$vbLabelText   $csharpLabel

IronOCR Ansatz:

// SaveAsSearchablePdf produces a PDF/A-compatible searchable document
//Neinsecondary library, no text overlay code, no coordinate mapping
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
    var result = new IronTesseract().Read(imagePath);
    result.SaveAsSearchablePdf(outputPdfPath);
    Console.WriteLine($"Searchable PDF saved: {outputPdfPath}");
}

// Same API works for multi-page TIFF or existing PDF input
public void MakePdfSearchable(string scannedPdfPath, string outputPdfPath)
{
    var result = new IronTesseract().Read(scannedPdfPath);
    result.SaveAsSearchablePdf(outputPdfPath);
}
// SaveAsSearchablePdf produces a PDF/A-compatible searchable document
//Neinsecondary library, no text overlay code, no coordinate mapping
public void CreateSearchablePdf(string imagePath, string outputPdfPath)
{
    var result = new IronTesseract().Read(imagePath);
    result.SaveAsSearchablePdf(outputPdfPath);
    Console.WriteLine($"Searchable PDF saved: {outputPdfPath}");
}

// Same API works for multi-page TIFF or existing PDF input
public void MakePdfSearchable(string scannedPdfPath, string outputPdfPath)
{
    var result = new IronTesseract().Read(scannedPdfPath);
    result.SaveAsSearchablePdf(outputPdfPath);
}
Imports System

' SaveAsSearchablePdf produces a PDF/A-compatible searchable document
' Neinsecondary library, no text overlay code, no coordinate mapping
Public Sub CreateSearchablePdf(imagePath As String, outputPdfPath As String)
    Dim result = New IronTesseract().Read(imagePath)
    result.SaveAsSearchablePdf(outputPdfPath)
    Console.WriteLine($"Searchable PDF saved: {outputPdfPath}")
End Sub

' Same API works for multi-page TIFF or existing PDF input
Public Sub MakePdfSearchable(scannedPdfPath As String, outputPdfPath As String)
    Dim result = New IronTesseract().Read(scannedPdfPath)
    result.SaveAsSearchablePdf(outputPdfPath)
End Sub
$vbLabelText   $csharpLabel

SaveAsSearchablePdf() bettet den OCR-Text als unsichtbare Schicht ein, die an den erkannten Wörtern ausgerichtet ist, wodurch das Dokument volltextdurchsuchbar wird, ohne das visuelle Erscheinungsbild zu verändern. Die durchsuchbare PDF-Anleitung behandelt die Auswahl des Seitenbereichs und die Komprimierungsoptionen. Ein funktionierendes Beispiel finden Sie auf der durchsuchbaren PDF-Beispielseite .

Charles Tesserakt API zu IronOCR Mapping-Referenz

Charles Tesserakt IronOCR-Äquivalent
new TesseractEngine(tessDataPath, "eng", EngineMode.Default) new IronTesseract()
Pix.LoadFromFile(imagePath) input.LoadImage(imagePath)
Pix.LoadFromMemory(bytes) input.LoadImage(imageBytes)
engine.Process(pix) ocr.Read(input)
page.GetText() result.Text
page.GetMeanConfidence() result.Confidence (0–100 Skala)
page.GetIterator() result.Pages, result.Words (direkte Sammlungen)
iter.GetText(PageIteratorLevel.Word) word.Text
iter.GetConfidence(PageIteratorLevel.Word) word.Confidence
iter.TryGetBoundingBox(PageIteratorLevel.Word, out var b) word.X, word.Y, word.Width, word.Height
iter.GetText(PageIteratorLevel.Para) paragraph.Text
iter.IsAtBeginningOf(PageIteratorLevel.Block) page.Paragraphs (direkt iterieren)
EngineMode.Default Automatisch (Tesseract 5 LSTM-Standard)
EngineMode.TesseractOnly ocr.Configuration.PageSegmentationMode
Manuelle Tessdata .traineddata Datei dotnet add package IronOcr.Languages.French
TessDataPath Konstante + .csproj Kopieren-Eintrag Nicht zutreffend – gebündelt
Pix.LoadFromFile() über Leptonica DLL input.LoadImage() — keine native DLL erforderlich
Plattform GetTessDataPath() Methode Nicht zutreffend – gestrichen
leptonica-1.82.0.dll / libleptonica-dev Nicht zutreffend – keine Abhängigkeit von Leptonica
Manuelle Extraktion von temporären Frames aus TIFF-Dateien input.LoadImageFrames(tiffPath)
Keine durchsuchbare PDF-Ausgabe result.SaveAsSearchablePdf(outputPath)
new TesseractEngine() pro Thread Ein IronTesseract — thread-sicher

Gängige Migrationsprobleme und Lösungen

Problem 1: DllNotFoundException für Leptonica- oder Tesseract-Binärdateien

Charlesw Tesseract: System.DllNotFoundException: Unable to load DLL 'leptonica-1.82.0': The specified module could not be found. Diese Ausnahme tritt auf, wenn die Leptonica native DLL nicht am erwarteten Ort ist. Dies ist in neuen Docker-Containern, CI-Agenten oder in jeder Umgebung üblich, in der der runtimes/ Ordner des NuGet-Pakets nicht korrekt kopiert wurde.

Lösung: Entfernen Sie das Tesseract Paket. Installieren Sie IronOcr.IronOCR bündelt alle nativen Binärdateien intern und ruft das System-Leptonica nicht per P/Invoke auf. Die Ausnahme kann nicht auftreten, da keine externe Leptonica-Abhängigkeit besteht:

dotnet remove package Tesseract
:InstallCmd dotnet add package IronOcr
dotnet remove package Tesseract
:InstallCmd dotnet add package IronOcr
SHELL

Keine apt-get install libleptonica-dev erforderlich. Keine <CopyToOutputDirectory> Einträge für native DLLs.

Problem 2: Tessdata-Pfadfehler nach der Bereitstellung

Charlesw Tesseract: Tesseract.TesseractException: Failed to initialise tesseract engine. Dies tritt auf, wenn TessDataPath zur Laufzeit nicht aufgelöst wird. Es kompiliert ohne Fehler, schlägt nur zur Laufzeit fehl, und der Fehlerpfad hängt von der Bereitstellungsumgebung ab.

Lösung: Das Konzept des tessdata-Pfads existiert in IronOCR nicht. Löschen Sie die Konstante, löschen Sie die CopyToOutputDirectory XML in .csproj, und löschen Sie die Fabrikmethode, die sie erstellt. Sprachdaten werden als NuGet Pakete verteilt:

# Replace this manual tessdata file management:
#   tessdata/eng.traineddata  (15 MB, manually downloaded)
#   tessdata/fra.traineddata  (15 MB, manually downloaded)
#   .csproj <CopyToOutputDirectory> entry

# With NuGet packages:
dotnet add package IronOcr.Languages.French
# Replace this manual tessdata file management:
#   tessdata/eng.traineddata  (15 MB, manually downloaded)
#   tessdata/fra.traineddata  (15 MB, manually downloaded)
#   .csproj <CopyToOutputDirectory> entry

# With NuGet packages:
dotnet add package IronOcr.Languages.French
SHELL

Der Leitfaden für mehrere Sprachen zeigt, wie die Mehrsprachenerkennung nach dem Hinzufügen von Sprachpaketen konfiguriert wird.

Problem 3: Container-Build schlägt fehl, wenn Basisimage aktualisiert wird

Charlesw Tesseract: Das Dockerfile enthält apt-get install -y libleptonica-dev, um die Leptonica native Abhängigkeit zu befriedigen. Wenn das Basis-Image von Debian Bullseye auf Bookworm umgestellt wird oder sich der Paketname von Leptonica in verschiedenen Distributionen ändert, schlägt der Build mit einem apt-Fehler fehl. Um das Problem zu beheben, muss man wissen, welcher Paketname in der neuen Distribution verwendet werden muss.

Lösung: Entfernen Sie die Leptonica apt-get Zeile vollständig.IronOCR unter Linux erfordert nur das Standard libgdiplus Paket, das jede .NET-Anwendung benötigt, die System.Drawing bereits verwendet:

# Before: Leptonica explicit install — breaks on base image updates
RUN apt-get update && apt-get install -y libleptonica-dev

# After: standard .NET Linux requirement only
RUN apt-get update && apt-get install -y libgdiplus

Der Docker-Bereitstellungsleitfaden bietet getestete Dockerfile-Vorlagen für gängige Basis-Images. Es ist kein charlesw-spezifischer Infrastrukturcode erforderlich.

Problem 4: Iterator-Musterbrüche auf leeren Seiten oder Seiten mit Leerzeichen

Charlesw Tesseract: Der ResultIterator gibt null von iter.GetText() auf einigen Seitensegmenten zurück, was explizite Null-Überprüfungen in der gesamten Schleife erfordert. Ein Fehlen einer Null-Überprüfung verursacht NullReferenceException auf leeren Seiten oder Bildern ohne erkennbaren Text.

Lösung:IronOCR-Ergebnissammlungen sind niemals null. Leere Seiten liefern leere Sammlungen. Prüfen Sie den Textinhalt anstatt Nullreferenzen:

// Before: null checks required at every iterator level
var wordText = iter.GetText(PageIteratorLevel.Word);
if (wordText != null && wordText.Trim().Length > 0)
    results.Add(wordText.Trim());

// After: collection is safe to enumerate; check content as needed
foreach (var word in result.Pages.SelectMany(p => p.Lines).SelectMany(l => l.Words))
{
    if (!string.IsNullOrWhiteSpace(word.Text))
        results.Add(word.Text);
}
// Before: null checks required at every iterator level
var wordText = iter.GetText(PageIteratorLevel.Word);
if (wordText != null && wordText.Trim().Length > 0)
    results.Add(wordText.Trim());

// After: collection is safe to enumerate; check content as needed
foreach (var word in result.Pages.SelectMany(p => p.Lines).SelectMany(l => l.Words))
{
    if (!string.IsNullOrWhiteSpace(word.Text))
        results.Add(word.Text);
}
' Before: null checks required at every iterator level
Dim wordText = iter.GetText(PageIteratorLevel.Word)
If wordText IsNot Nothing AndAlso wordText.Trim().Length > 0 Then
    results.Add(wordText.Trim())
End If

' After: collection is safe to enumerate; check content as needed
For Each word In result.Pages.SelectMany(Function(p) p.Lines).SelectMany(Function(l) l.Words)
    If Not String.IsNullOrWhiteSpace(word.Text) Then
        results.Add(word.Text)
    End If
Next
$vbLabelText   $csharpLabel

Problem 5: Gewindesicherheitsverletzungen unter Last

Charlesw Tesseract: TesseractEngine is not thread-safe. Die gemeinsame Nutzung einer Instanz durch mehrere gleichzeitige Anfragen in einer ASP.NET Anwendung führt zu Zugriffsverletzungen oder fehlerhaften Ergebnissen. Die übliche Lösung besteht darin, für jeden Thread eine eigene Engine zu erstellen. Dies ist jedoch aus der API nicht ersichtlich, und die Fehlermeldungen im Fehlerfall sind kryptische native Ausnahmen.

Lösung: IronTesseract ist thread-sicher. Eine Instanz kann gleichzeitigen Anfragen dienen, oder für maximalen Durchsatz erstellen Sie eine pro Thread in einem Parallel.ForEach — beide Muster funktionieren ohne Modifikation:

// Thread-safe parallel processing — IronTesseract handles concurrent access
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(imageFiles, imagePath =>
{
    var ocr    = new IronTesseract();
    var result = ocr.Read(imagePath);
    results.Add(result.Text);
});
// Thread-safe parallel processing — IronTesseract handles concurrent access
var results = new System.Collections.Concurrent.ConcurrentBag<string>();
Parallel.ForEach(imageFiles, imagePath =>
{
    var ocr    = new IronTesseract();
    var result = ocr.Read(imagePath);
    results.Add(result.Text);
});
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

' Thread-safe parallel processing — IronTesseract handles concurrent access
Dim results As New ConcurrentBag(Of String)()
Parallel.ForEach(imageFiles, Sub(imagePath)
    Dim ocr As New IronTesseract()
    Dim result = ocr.Read(imagePath)
    results.Add(result.Text)
End Sub)
$vbLabelText   $csharpLabel

Der Leitfaden zur asynchronen OCR behandelt asynchrone Muster für ASP.NET Core Controller, bei denen Thread-Blockierung nicht akzeptabel ist.

Problem 6: ARM64-Binärdatei fehlt zur Laufzeit

Charlesw Tesseract: Auf AWS Graviton (Linux ARM64) oder Apple Silicon CI-Agenten wird das archivierte Paket möglicherweise nicht als native ARM64-Binärdatei ausgeliefert. Der Fehler ist ein DllNotFoundException oder ein BadImageFormatException bei der Engine-Erstellung — ein Laufzeitfehler auf einer Plattform, die das Paket nicht unterstützt.

Lösung:IronOCR liefert validierte ARM64-Binärdateien sowohl für Linux als auch für macOS. Bereitstellung auf ARM64 ohne Codeänderungen. Die Bereitstellungsanleitung für Linux und die Bereitstellungsanleitung für macOS bestätigen die unterstützten Laufzeitkennungen.

Charles Tesserakt Migrations-Checkliste

Vor der Migration

Überprüfen Sie den Quellcode, um alle sich ändernden Muster zu identifizieren:

# Find all references to Tesseract namespace (engine creation, Pix usage, iterator usage)
grep -rn "using Tesseract" --include="*.cs" .

# Find TesseractEngine instantiation points
grep -rn "TesseractEngine" --include="*.cs" .

# Find Pix usage (Leptonica image type)
grep -rn "Pix\." --include="*.cs" .

# Find tessdata path constants and methods
grep -rn "tessdata\|TessDataPath\|traineddata" --include="*.cs" .

# Find platform-conditional deployment code
grep -rn "IsOSPlatform\|DOTNET_RUNNING_IN_CONTAINER\|LD_LIBRARY_PATH" --include="*.cs" .

# Find iterator pattern usage
grep -rn "GetIterator\|ResultIterator\|PageIteratorLevel" --include="*.cs" .

# Find confidence calls
grep -rn "GetMeanConfidence\|GetConfidence" --include="*.cs" .

# Find .csproj tessdata copy entries
grep -rn "tessdata" --include="*.csproj" .
# Find all references to Tesseract namespace (engine creation, Pix usage, iterator usage)
grep -rn "using Tesseract" --include="*.cs" .

# Find TesseractEngine instantiation points
grep -rn "TesseractEngine" --include="*.cs" .

# Find Pix usage (Leptonica image type)
grep -rn "Pix\." --include="*.cs" .

# Find tessdata path constants and methods
grep -rn "tessdata\|TessDataPath\|traineddata" --include="*.cs" .

# Find platform-conditional deployment code
grep -rn "IsOSPlatform\|DOTNET_RUNNING_IN_CONTAINER\|LD_LIBRARY_PATH" --include="*.cs" .

# Find iterator pattern usage
grep -rn "GetIterator\|ResultIterator\|PageIteratorLevel" --include="*.cs" .

# Find confidence calls
grep -rn "GetMeanConfidence\|GetConfidence" --include="*.cs" .

# Find .csproj tessdata copy entries
grep -rn "tessdata" --include="*.csproj" .
SHELL

Beachten Sie, auf welche Bereitstellungsumgebungen das Projekt abzielt (Docker, Linux, ARM64, Azure, AWS) – dies sind die Umgebungen, in denen charlesw/tesseract die meisten Konfigurationen erfordert, die IronOCR überflüssig macht.

Code-Migration

  1. Führen Sie dotnet remove package Tesseract aus, um den charlesw-Wrapper zu deinstallieren
  2. Führen Sie dotnet add package IronOcr aus, um IronOCR zu installieren
  3. Fügen Sie IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; beim Anwendungsstart hinzu
  4. Ersetzen Sie alle using Tesseract; Anweisungen durch using IronOcr;
  5. Löschen Sie die Tessdata-Pfadkonstante und alle Methoden, die den Pfad pro Umgebung erstellen.
  6. Entfernen Sie alle RuntimeInformation.IsOSPlatform() Blöcke, die für die Auswahl des Tessdata-Pfads geschrieben wurden
  7. Entfernen Sie <CopyToOutputDirectory> Einträge für Tessdata-Dateien aus allen .csproj Dateien
  8. Löschen Sie Tessdata .traineddata Dateien aus der Versionskontrolle oder den Bereitstellungs-Artefaktspeichern
  9. Fügen Sie dotnet add package IronOcr.Languages.* für jede Sprache hinzu, die zuvor als .traineddata Datei bereitgestellt wurde
  10. Ersetzen Sie TesseractEngine + Pix.LoadFromFile() + engine.Process() Ketten durch new IronTesseract().Read()
  11. Ersetzen Sie alle Pix.LoadFromFile() und Pix.LoadFromMemory() Aufrufe durch input.LoadImage()
  12. Ersetzen Sie alle page.GetText() Aufrufe durch result.Text
  13. Ersetzen Sie die Iterator-basierte Wort-/Zeilenausgabe durch den direkten Sammlungszugriff auf result.Pages
  14. Ersetzen Sie die iter.GetConfidence() Schwellenwertlogik durch LINQ auf result.Words oder result.Lines
  15. Entfernen Sie libleptonica-dev / leptonica-1.82.0.dll aus Dockerfiles und Bereitstellungsskripten

Nach der Migration

Bitte überprüfen Sie nach Abschluss der Codeaktualisierungen Folgendes:

  • Die OCR-Funktion läuft unter Windows erfolgreich ohne native DLL-Fehler.
  • OCR läuft erfolgreich in einem Docker Linux-Container ohne jegliche apt-get Änderungen über libgdiplus hinaus
  • OCR erzeugt Textausgabe auf ARM64, wenn diese Plattform in der Bereitstellungsmatrix enthalten ist.
  • Mehrseitige TIFF-Dateien enthalten den Text aller Frames, nicht nur des ersten.
  • Die Konfidenzfilterung liefert dieselbe logische Menge von Wörtern mit hoher Konfidenz wie die vorherige Iteratorimplementierung.
  • Sprachspezifische Dokumente (Französisch, Deutsch usw.) werden nach der Installation der sprachspezifischen NuGet Pakete korrekt erkannt.
  • Parallele OCR-Operationen werden ohne Ausnahmen oder fehlerhafte Ausgabe abgeschlossen.
  • Es wird nun eine durchsuchbare PDF-Datei generiert, wo die vorherige Implementierung nur Text zurückgegeben hat.
  • CI/CD-Pipeline-Builds ohne Tessdata-Download-Schritte oder Leptonica-Installationsbefehle
  • Funktionstest anhand desselben Bildkorpus, der zur Validierung der vorherigen Implementierung verwendet wurde

Wichtigste Vorteile der Migration zu IronOCR

Eigenständiges Bereitstellungsmodell. Nach der Migration wird die OCR-Abhängigkeit vollständig durch einen einzigen NuGet -Paketverweis beschrieben. Keine Tessdata-Dateien in der Versionskontrolle, keine CopyToOutputDirectory Einträge, keine nativen DLL-Bereitstellungsschritte, keine Leptonica-Systempakete. CI/CD-Pipelines, die zuvor eine mehrstufige Artefaktverwaltung erforderten, reduzieren sich auf dotnet publish. Der für die Bereitstellung benötigte Code, der sich zur Unterstützung des CharlesWrappers angesammelt hatte, ist endgültig verschwunden.

Plattformunabhängigkeit ohne bedingte Logik. Dieselbe Anwendungsdatei läuft ohne Änderungen unter Windows x64, Linux x64, Linux ARM64, macOS x64 und macOS ARM64. Teams, die ein ARM64-Bereitstellungsziel hinzufügen – sei es AWS Graviton, Apple Silicon CI oder Raspberry Pi – schreiben keinen neuen Code zur Plattformerkennung. Die Linux-Bereitstellungsanleitung und die AWS-Bereitstellungsanleitung bestätigen die getesteten Konfigurationen.

Tesseract 5: Höhere Genauigkeit dank integrierter Vorverarbeitung. Der Sprung von Tesseract 4.1.1 zu Tesseract 5 verbessert die Erkennung auch bei beschädigten Dokumenten.IronOCR bietet zusätzlich zum Engine-Upgrade eine automatische Vorverarbeitung, bei der Entzerrung, Rauschunterdrückung, Kontrastnormalisierung und Binarisierung angewendet werden, bevor die Engine jedes Bild verarbeitet. Dokumente, für deren Erreichen akzeptabler Genauigkeitsschwellenwerte bisher eine benutzerdefinierte Vorverarbeitungspipeline erforderlich war, erreichen diese Schwellenwerte nun ohne zusätzlichen Code. Der Leitfaden zur Bildqualitätskorrektur dokumentiert explizite Vorverarbeitungsoptionen für Fälle, die über die Standardeinstellungen hinaus angepasst werden müssen.

Direkte Ergebnisnavigation ersetzt Iterator-Boilerplate. Das charlesw Iteratormuster — GetIterator(), Begin(), Next(), IsAtBeginningOf(), Null-Überprüfungen überall — wird durch einfache Sammlungen ersetzt. Wörter, Zeilen, Absätze und Seiten sind Eigenschaften des Ergebnisobjekts. Konfidenzbasierte Filterung ist ein LINQ-Ausdruck. Code, der zuvor Daten auf Wortebene extrahierte, erforderte 15–30 Zeilen Iteratorverwaltung; Das IronOCR Äquivalent sind 2–3 Zeilen. Die Seite mit den OCR-Ergebnissen fasst das vollständige strukturierte Ausgabemodell zusammen.

Suchbare PDF-Ausgabe ohne eine sekundäre Bibliothek. result.SaveAsSearchablePdf() erzeugt ein PDF mit einer Textschicht, die an erkannte Wörter ausgerichtet ist, und erfordert keine sekundäre PDF-Bibliothek. Dokumentenmanagementsysteme, die durchsuchbare PDFs verarbeiten, benötigen keinen separaten PDF-Generierungsschritt mehr. Das Ergebnisobjekt, das den extrahierten Text liefert, erstellt auch die durchsuchbare Datei, wodurch die Dokumentenverarbeitungspipelines auf eine einzige Bibliotheksabhängigkeit beschränkt bleiben.

Aktive Wartung und Abdeckung von Sicherheitspatches.IronOCR erhält regelmäßige Updates, die Verbesserungen am Tesseract-5-Modell, die Validierung der .NET Laufzeitkompatibilität und die Abdeckung von Sicherheitspatches für die zugrunde liegende C++-Engine dokumentieren. Die Abhängigkeit birgt nicht mehr das Risikoprofil eines archivierten Pakets – Compliance-Prüfungen führen nicht mehr zu Beanstandungen aufgrund fehlender Sicherheitspatches. Da .NET 10 bis 2026 allgemein verfügbar sein wird, wird das IronOCR Dokumentationsportal die aktuelle Kompatibilität widerspiegeln, ohne dass Umwege oder Abspaltungen erforderlich sind.

Hinweis:PDFSharp und Tesseract sind eingetragene Marken ihrer jeweiligen Eigentümer. Diese Seite ist nicht mit Google oder empira Software GmbH verbunden, genehmigt oder gesponsert. Alle Produktnamen, Logos und Marken sind Eigentum ihrer jeweiligen Eigentümer. Vergleiche dienen nur zu Informationszwecken und spiegeln öffentlich zugängliche Informationen zum Zeitpunkt des Schreibens wider.

Häufig gestellte Fragen

Warum sollte ich von charlesw/tesseract (.NET Tesseract Wrapper) zu IronOCR migrieren?

Zu den häufigsten Gründen gehören die Beseitigung der Komplexität der COM-Interoperabilität, die Ablösung der dateibasierten Lizenzverwaltung, die Vermeidung der seitenweisen Abrechnung, die Ermöglichung der Docker-/Container-Bereitstellung und die Einführung eines NuGet-nativen Workflows, der sich in die Standard-.NET-Werkzeuge integriert.

Was sind die wichtigsten Code-Änderungen bei der Migration von charlesw/tesseract (.NET Tesseract Wrapper) zu IronOCR?

Ersetzen Sie die charlesw/tesseract-Initialisierungssequenzen durch IronTesseract-Instanziierung, entfernen Sie das COM-Lebenszyklusmanagement (explizite Create/Load/Close-Muster) und aktualisieren Sie die Namen der Ergebniseigenschaften. Das Ergebnis sind deutlich weniger Boilerplate-Zeilen.

Wie installiere ich IronOCR, um die Migration zu beginnen?

Führen Sie 'Install-Package IronOcr' in der Paketmanager-Konsole oder 'dotnet add package IronOcr' in der CLI aus. Sprachpakete sind separate Pakete: 'dotnet add package IronOcr.Languages.French' für Französisch, zum Beispiel.

Erreicht IronOCR die OCR-Genauigkeit von charlesw/tesseract (.NET Tesseract Wrapper) für Standardgeschäftsdokumente?

IronOCR erzielt eine hohe Genauigkeit bei Standardgeschäftsinhalten wie Rechnungen, Verträgen, Quittungen und getippten Formularen. Bildvorverarbeitungsfilter (Schräglagenkorrektur, Rauschunterdrückung, Kontrastverbesserung) verbessern die Erkennungsgenauigkeit bei verschlechterten Eingaben weiter.

Wie geht IronOCR mit den Sprachdaten um, die charlesw/tesseract (.NET Tesseract Wrapper) separat installiert?

Die Sprachdaten in IronOCR werden als NuGet-Pakete verteilt. mit 'dotnet add package IronOcr.Languages.German' wird die deutsche Unterstützung installiert. Es sind keine manuellen Dateiplatzierungen oder Verzeichnispfade erforderlich.

Erfordert die Migration von charlesw/tesseract (.NET Tesseract Wrapper) zu IronOCR Änderungen an der Bereitstellungsinfrastruktur?

IronOCR erfordert weniger Änderungen an der Infrastruktur als charlesw/tesseract (.NET Tesseract Wrapper). Es gibt keine SDK-Binärpfade, keine Platzierung von Lizenzdateien oder Lizenzserverkonfigurationen. Das NuGet-Paket enthält die komplette OCR-Engine, und der Lizenzschlüssel ist eine im Anwendungscode festgelegte Zeichenfolge.

Wie konfiguriere ich die IronOCR-Lizenzierung nach der Migration?

Weisen Sie IronOcr.License.LicenseKey = "YOUR-KEY" im Startup-Code der Anwendung zu. In Docker oder Kubernetes speichern Sie den Schlüssel als Umgebungsvariable und lesen ihn beim Starten aus. Verwenden Sie License.IsValidLicense zur Validierung, bevor Sie den Datenverkehr akzeptieren.

Kann IronOCR PDFs auf die gleiche Weise verarbeiten wie charlesw/tesseract?

Ja, IronOCR liest sowohl native als auch gescannte PDFs. Instanziieren Sie IronTesseract, rufen Sie ocr.Read(input) auf, wobei input ein PDF-Pfad oder OcrPdfInput ist, und iterieren Sie die OcrResult-Seiten. Es ist keine separate PDF-Rendering-Pipeline erforderlich.

Wie handhabt IronOCR das Threading bei der Verarbeitung großer Datenmengen?

IronTesseract kann sicher pro Thread instanziiert werden. Sie können eine Instanz pro Thread in einem Parallel.ForEach- oder Task-Pool aufsetzen, OCR gleichzeitig ausführen und jede Instanz nach Abschluss entsorgen. Es ist kein globaler Zustand oder Sperren erforderlich.

Welche Ausgabeformate unterstützt IronOCR nach der Textextraktion?

IronOCR liefert strukturierte Ergebnisse mit Text, Wortkoordinaten, Konfidenzwerten und Seitenstruktur. Zu den Exportoptionen gehören reiner Text, durchsuchbare PDF-Dateien und strukturierte Ergebnisobjekte für die nachgeschaltete Verarbeitung.

Ist die Preisgestaltung von IronOCR für die Skalierung von Workloads vorhersehbarer als die von charlesw/tesseract (.NET Tesseract Wrapper)?

IronOCR verwendet eine pauschale, unbefristete Lizenzierung ohne Seiten- oder Volumengebühren. Egal, ob Sie 10.000 oder 10 Millionen Seiten verarbeiten, die Lizenzkosten bleiben konstant. Optionen für Volumen- und Teamlizenzen finden Sie auf der IronOCR-Preisseite.

Was passiert mit meinen bestehenden Tests, nachdem ich von charlesw/tesseract (.NET Tesseract Wrapper) zu IronOCR migriert habe?

Tests, die extrahierte Textinhalte überprüfen, sollten auch nach der Migration bestehen. Tests, die API-Aufrufmuster oder den Lebenszyklus von COM-Objekten validieren, müssen aktualisiert werden, um das einfachere Initialisierungs- und Ergebnismodell von IronOCR widerzuspiegeln.

Kannaopat Udonpant
Software Ingenieur
Bevor er Software-Ingenieur wurde, absolvierte Kannapat ein PhD in Umweltressourcen an der Hokkaido University in Japan. Während seines Studiums wurde Kannapat auch Mitglied des Vehicle Robotics Laboratory, das Teil der Fakultät für Bioproduktionstechnik ist. Im Jahr 2022 nutzte er seine C#-Kenntnisse, um dem Engineering-Team von Iron Software ...
Weiterlesen

Iron-Support-Team

Wir sind 24 Stunden am Tag, 5 Tage die Woche online.
Chat
E-Mail
Rufen Sie mich an