Zum Fußzeileninhalt springen
VIDEOS

Umstellung von ABBYY FineReader auf IronOCR

Dieser Leitfaden führt .NET -Entwickler Schritt für Schritt durch den Austausch des ABBYY FineReader EngineSDK durch IronOCR . Es beschreibt die mechanischen Schritte zum Entfernen von COM-Abhängigkeiten und SDK-Installationsartefakten, ordnet die ABBYY-API den IronOCR Äquivalenten zu und bietet Vorher-/Nachher-Codebeispiele für die in ABBYY-Produktionsintegrationen am häufigsten vorkommenden Muster. Die Migration richtet sich an Teams, die entschieden haben, dass die Enterprise-Kosten und die Bereitstellungskomplexität von ABBYY nicht mehr mit ihren Projektanforderungen übereinstimmen.

Warum von ABBYY FineReader migrieren?

Die ABBYY FineReader Engineist eine leistungsfähige OCR-Plattform, deren Architektur jedoch für Windows- Enterprise mit dedizierten Infrastrukturteams konzipiert wurde. Wenn die eigentliche Arbeitslast eines .NET Teams in der Rechnungsverarbeitung, der Digitalisierung von Verträgen oder der Extraktion gescannter Formulare besteht, wird diese Architektur eher zu einer Belastung als zu einem Vorteil.

Die Kosten für COM-Interop-Integrationen steigen mit der Zeit. Jede ABBYY-Integration in .NET durchläuft eine COM-Interop-Schicht. COM-Objekte erfordern explizites Lebenszyklusmanagement: erstellen, initialisieren, verarbeiten, dann in einem finally-Block schließen, oder der Prozess leckt Speicher. Jeder Codepfad, der ABBYY berührt, folgt diesem Muster. Im Laufe von zwei oder drei Jahren, in denen Funktionen hinzugefügt werden, breitet sich diese Lebenszykluszeremonie über Serviceklassen, Hintergrundprozesse und Anforderungsbehandler aus. Das Ergebnis sind 30-50 % Boilerplate in jeder OCR-bezogenen Klasse, die vollständig verschwinden, wenn Sie zu IronTesseract wechseln.

Der SDK-Installer blockiert moderne Bereitstellungsmuster. ABBYY stellt seine Produkte über einen Windows SDK-Installer bereit, der Binärdateien, Sprachdaten, Laufzeitdateien und Lizenzdateien in fest codierten Pfaden ablegt. Die Containerisierung eines Dienstes, der ABBYY verwendet, erfordert entweder das Einbetten eines 300+ MB großen benutzerdefinierten Basisbildes aus diesem Installations-Ausgang oder das Einhängen von Volumes mit Lizenzdateien beim Start. Keine der Ansätze passt zu einer Standard-Kubernetes- oder Cloud-nativen Pipeline.IronOCR ist ein NuGet-Paket: das gleiche dotnet restore, das jede andere Abhängigkeit zieht, zieht die gesamte OCR-Engine.

Die seitenbasierte Lizenzierung macht das Volumen zu einem Kostenfaktor. Die volumenbasierten Lizenzmodelle von ABBYY berechnen die Kosten pro verarbeiteter Seite oberhalb der festgelegten Schwellenwerte. Bei einer Anwendung, die zum Start 50.000 Dokumente pro Monat verarbeitet und zwei Jahre später 500.000 erreicht, steigen die OCR-Kosten proportional zum Erfolg.IronOCR berechnet eine Pauschalgebühr für die Lizenz – ein Team, das zwei Millionen Seiten pro Monat verarbeitet, zahlt genau die gleichen Lizenzkosten wie ein Team, das zweitausend Seiten verarbeitet.

Sprachdaten erfordern eine manuelle Bereitstellungskoordination. ABBYY-Sprachpakete befinden sich als Dateien im SDK-Laufzeitverzeichnis. Das Hinzufügen einer Sprache bedeutet, die richtigen Datendateien zu identifizieren, sie auf jedem Bereitstellungsziel in den richtigen Pfad zu kopieren und die CI/CD-Skripte entsprechend zu aktualisieren. Bei IronOCR ist das Hinzufügen von Französisch dotnet add package IronOcr.Languages.French — der Paketmanager übernimmt den Rest.

Lizenzdateiausfälle treffen die Produktion ohne Vorwarnung. ABBYY-Lizenzen sind als .lic und .key-Dateien vorhanden, die an bestimmten Speicherorten auf der Festplatte vorhanden sein müssen, wenn loader.GetEngineObject() ausgeführt wird. Fehlen diese Dateien auf einem neuen Produktionsserver – beispielsweise aufgrund eines fehlerhaften Bereitstellungsskripts, eines fehlgeschlagenen Dateikopiervorgangs oder eines Berechtigungsproblems –, wird beim Start ein Fehler ausgelöst. Dasselbe gilt für eine abgelaufene Lizenz. IronOCRs Lizenzierung ist ein Zeichenfolgen-Schlüssel, der im Startcode zugewiesen wird, in jedem Geheimnismanager gespeichert werden kann und von IronOcr.License.IsValidLicense überprüft wird, bevor die Anwendung Verkehr akzeptiert.

Threadsicherheit erfordert eine einzige gemeinsam genutzte Engine-Instanz. ABBYYs Engine ist nicht trivial threadsicher bei gleichzeitigen CreateFRDocument-Aufrufen von mehreren Threads. In Produktionsumgebungen werden Sperrstrategien oder Prozessorpools verwendet. IronOCRs IronTesseract ist zustandslos: eine Instanz pro Thread hochfahren, Erkennung parallel ohne Sperren ausführen, bei Fertigstellung entsorgen.

Das grundsätzliche Problem

// ABBYY: COM loader + license path validation + profile load — before a single pixel of OCR runs
var loader = new EngineLoader();
var engine = loader.GetEngineObject(
    @"C:\Program Files\ABBYY SDK\FineReader Engine\Bin",  // Breaks on every new machine
    @"C:\Program Files\ABBYY SDK\License"                 // Fails if .lic file is missing
);
engine.LoadPredefinedProfile("DocumentConversion_Accuracy");
var langParams = engine.CreateLanguageParams();
langParams.Languages.Add("English");
// ABBYY: COM loader + license path validation + profile load — before a single pixel of OCR runs
var loader = new EngineLoader();
var engine = loader.GetEngineObject(
    @"C:\Program Files\ABBYY SDK\FineReader Engine\Bin",  // Breaks on every new machine
    @"C:\Program Files\ABBYY SDK\License"                 // Fails if .lic file is missing
);
engine.LoadPredefinedProfile("DocumentConversion_Accuracy");
var langParams = engine.CreateLanguageParams();
langParams.Languages.Add("English");
' ABBYY: COM loader + license path validation + profile load — before a single pixel of OCR runs
Dim loader As New EngineLoader()
Dim engine = loader.GetEngineObject(
    "C:\Program Files\ABBYY SDK\FineReader Engine\Bin",  ' Breaks on every new machine
    "C:\Program Files\ABBYY SDK\License"                 ' Fails if .lic file is missing
)
engine.LoadPredefinedProfile("DocumentConversion_Accuracy")
Dim langParams = engine.CreateLanguageParams()
langParams.Languages.Add("English")
$vbLabelText   $csharpLabel
// IronOCR: the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var ocr = new IronTesseract();
// IronOCR: the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var ocr = new IronTesseract();
Imports IronOcr

' IronOCR: the entire initialization
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim ocr As New IronTesseract()
$vbLabelText   $csharpLabel

IronOCR vs. ABBYY FineReader: Funktionsvergleich

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

Feature ABBYY FineReader Engine IronOCR
Installation SDK-Installer (Windows) dotnet add package IronOcr
Akquisition Kontaktieren Sie den Vertrieb (4-12 Wochen) NuGet-Selbstbedienung
Lizenzierungsmodell Enterprise, pro Server oder pro Seite Unbefristet, $999-$2.999 einmalig
Lizenzverwaltung .lic + .key Dateien auf der Festplatte Zeichenkettenschlüssel im Code oder in der Umgebungsvariablen
.NET-Integration COM-Interoperabilität Native .NET
COM-Abhängigkeit Ja Nein
Thread-Sicherheit Erfordert eine Sperrstrategie Voll (eine IronTesseract pro Thread)
Unterstützte Sprachen 190+ 125+
Sprachinstallation Laufzeitdatendateien im SDK-Pfad NuGet Sprachpakete
PDF-Eingabe Ja (über CreatePDFFile) Ja (nativ, input.LoadPdf())
Durchsuchbare PDF-Ausgabe Ja (Exportpipeline) Ja (result.SaveAsSearchablePdf())
Automatische Vorverarbeitung Profilbasiert Integrierte Funktionen (Entzerren, Rauschen entfernen, Kontrast, Binarisieren, Schärfen)
Regionsbasierte OCR Zonenobjekte (CreateZone, SetBounds) CropRectangle Parameter
Barcode-Lesung Ja Ja (ocr.Configuration.ReadBarCodes = true)
Plattformübergreifend Windows, Linux, macOS Windows, Linux, macOS, Docker, Azure, AWS
Docker-Bereitstellung Benutzerdefiniertes Basisimage erforderlich Standard .NET Basisbild + libgdiplus
Konfidenzbewertung Ja Ja (result.Confidence)
Zeit bis zum ersten OCR-Ergebnis 4–12 Wochen (Beschaffung) Am selben Tag

Schnellstart: Migration von ABBYY FineReader zu IronOCR

Schritt 1: Ersetzen des NuGet-Pakets

Für die ABBYY FineReader Enginegibt es kein NuGet Paket. Entfernen Sie es, indem Sie das SDK deinstallieren und den manuellen Assemblyverweis aus Ihrer Projektdatei entfernen:


<Reference Include="FREngine">
  <HintPath>C:\Program Files\ABBYY SDK\FineReader Engine\Bin\FREngine.dll</HintPath>
</Reference>

<Reference Include="FREngine">
  <HintPath>C:\Program Files\ABBYY SDK\FineReader Engine\Bin\FREngine.dll</HintPath>
</Reference>
XML

Entfernen Sie dann den FREngine.dll COM-Interop-Verweis aus dem Verzeichnisknoten 'Verweise' in Visual Studio oder löschen Sie den entsprechenden Eintrag direkt aus Ihrer Projektdatei. Installieren Sie IronOCR über NuGet :

dotnet add package IronOcr

Schritt 2: Namespaces aktualisieren

// Before (ABBYY)
using FREngine;
using ABBYY.FineReader;

// After (IronOCR)
using IronOcr;
// Before (ABBYY)
using FREngine;
using ABBYY.FineReader;

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

Schritt 3: Lizenz initialisieren

Fügen Sie dies einmalig beim Start der Anwendung hinzu, bevor OCR-Aufrufe erfolgen:

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

Speichern Sie den Schlüssel für Produktionsumgebungen in einer Umgebungsvariablen oder einem Geheimnismanager:

IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY");
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY");
Imports System

IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
$vbLabelText   $csharpLabel

Beispiele für die Code-Migration

Engine-Lebenszyklus in einem Windows-Dienst im Vergleich zu Stateless IronTesseract

ABBYYs Engine-Initialisierungszeremonie gehört in einen Dienst-Wrapper, weil die EngineLoader und IEngine-Objekte teuer zu erstellen sind. Die meisten Produktionsintegrationen kapseln die Engine in einen Singleton-Service mit expliziten Start- und Beendigungsmethoden.

ABBYY FineReader-Ansatz:

using FREngine;

public class DocumentOcrService : IHostedService, IDisposable
{
    private IEngine _engine;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // Step 1: Create loader — requires COM-Interoperabilität registration
        var loader = new EngineLoader();

        // Step 2: Load engine from SDK path — throws if license files are missing
        _engine = loader.GetEngineObject(
            @"C:\Program Files\ABBYY SDK\FineReader Engine\Bin",
            @"C:\Program Files\ABBYY SDK\License"
        );

        // Step 3: Load profile before any recognition work
        _engine.LoadPredefinedProfile("DocumentConversion_Accuracy");

        return Task.CompletedTask;
    }

    public string ProcessDocument(string imagePath)
    {
        // Document must be created and destroyed per call
        var document = _engine.CreateFRDocument();
        try
        {
            document.AddImageFile(imagePath, null, null);
            document.Process(null);
            return document.PlainText.Text;
        }
        finally
        {
            document.Close(); // Memory leaks if omitted
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _engine = null; // COM cleanup
        return Task.CompletedTask;
    }

    public void Dispose() => _engine = null;
}
using FREngine;

public class DocumentOcrService : IHostedService, IDisposable
{
    private IEngine _engine;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // Step 1: Create loader — requires COM-Interoperabilität registration
        var loader = new EngineLoader();

        // Step 2: Load engine from SDK path — throws if license files are missing
        _engine = loader.GetEngineObject(
            @"C:\Program Files\ABBYY SDK\FineReader Engine\Bin",
            @"C:\Program Files\ABBYY SDK\License"
        );

        // Step 3: Load profile before any recognition work
        _engine.LoadPredefinedProfile("DocumentConversion_Accuracy");

        return Task.CompletedTask;
    }

    public string ProcessDocument(string imagePath)
    {
        // Document must be created and destroyed per call
        var document = _engine.CreateFRDocument();
        try
        {
            document.AddImageFile(imagePath, null, null);
            document.Process(null);
            return document.PlainText.Text;
        }
        finally
        {
            document.Close(); // Memory leaks if omitted
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _engine = null; // COM cleanup
        return Task.CompletedTask;
    }

    public void Dispose() => _engine = null;
}
Imports FREngine
Imports System.Threading
Imports System.Threading.Tasks

Public Class DocumentOcrService
    Implements IHostedService, IDisposable

    Private _engine As IEngine

    Public Function StartAsync(cancellationToken As CancellationToken) As Task Implements IHostedService.StartAsync
        ' Step 1: Create loader — requires COM-Interoperabilität registration
        Dim loader As New EngineLoader()

        ' Step 2: Load engine from SDK path — throws if license files are missing
        _engine = loader.GetEngineObject(
            "C:\Program Files\ABBYY SDK\FineReader Engine\Bin",
            "C:\Program Files\ABBYY SDK\License"
        )

        ' Step 3: Load profile before any recognition work
        _engine.LoadPredefinedProfile("DocumentConversion_Accuracy")

        Return Task.CompletedTask
    End Function

    Public Function ProcessDocument(imagePath As String) As String
        ' Document must be created and destroyed per call
        Dim document = _engine.CreateFRDocument()
        Try
            document.AddImageFile(imagePath, Nothing, Nothing)
            document.Process(Nothing)
            Return document.PlainText.Text
        Finally
            document.Close() ' Memory leaks if omitted
        End Try
    End Function

    Public Function StopAsync(cancellationToken As CancellationToken) As Task Implements IHostedService.StopAsync
        _engine = Nothing ' COM cleanup
        Return Task.CompletedTask
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        _engine = Nothing
    End Sub
End Class
$vbLabelText   $csharpLabel

IronOCR Ansatz:

using IronOcr;

public class DocumentOcrService
{
    //Neinstartup, no shutdown, no COM lifecycle
    // IronTesseract is stateless — create per call or reuse per thread

    public string ProcessDocument(string imagePath)
    {
        return new IronTesseract().Read(imagePath).Text;
    }
}
using IronOcr;

public class DocumentOcrService
{
    //Neinstartup, no shutdown, no COM lifecycle
    // IronTesseract is stateless — create per call or reuse per thread

    public string ProcessDocument(string imagePath)
    {
        return new IronTesseract().Read(imagePath).Text;
    }
}
Imports IronOcr

Public Class DocumentOcrService
    'Neinstartup, no shutdown, no COM lifecycle
    ' IronTesseract is stateless — create per call or reuse per thread

    Public Function ProcessDocument(imagePath As String) As String
        Return New IronTesseract().Read(imagePath).Text
    End Function
End Class
$vbLabelText   $csharpLabel

IronTesseract hat keinen Engine-Lebenszyklus. Es initialisiert sich bei der ersten Verwendung intern und erfordert kein explizites Herunterfahren. Der gehostete Dienst-Wrapper, das IEngine-Feld und die StopAsync-Methoden verschwinden alle. Wenn die Anwendung Dokumente gleichzeitig verarbeitet, erstellt jeder Thread seine eigene IronTesseract Instanz — keine Sperre erforderlich. Der IronTesseract Einrichtungs-Leitfaden behandelt Konfigurationsoptionen, einschließlich TesseractVersion und Configuration Eigenschaften.

Einrichtung der Erkennungssprache

Die Sprachkonfiguration von ABBYY erfordert das Erstellen eines LanguageParams-Objektes, das Hinzufügen von Sprachnamen-Zeichenfolgen, die mit installierten Datendateien übereinstimmen müssen, und das Verknüpfen dieser Parameter mit der Engine, bevor ein Dokument verarbeitet wird. Für jede zusätzliche Sprache werden die entsprechenden Datendateien benötigt, die im Laufzeitpfad bereitgestellt werden.

ABBYY FineReader-Ansatz:

using FREngine;

// Engine must already be initialized with sdkPath and licensePath
private void ConfigureLanguages(IEngine engine, string[] languageCodes)
{
    // Create language parameters object
    var langParams = engine.CreateLanguageParams();

    // Add each language — string names must match installed data file names
    // Missing data file causes runtime failure
    foreach (var lang in languageCodes)
    {
        langParams.Languages.Add(lang);  // e.g., "English", "French", "German"
    }

    // Language params are associated at the profile level, not per-document
    // Changing languages requires reloading profile or reinitializing engine
    engine.LoadPredefinedProfile("DocumentConversion_Accuracy");
}

public string RecognizeFrenchDocument(IEngine engine, string imagePath)
{
    var langParams = engine.CreateLanguageParams();
    langParams.Languages.Add("French");  // Requires FrenchLanguage data files at runtime path

    var document = engine.CreateFRDocument();
    try
    {
        document.AddImageFile(imagePath, null, null);
        document.Process(null);
        return document.PlainText.Text;
    }
    finally
    {
        document.Close();
    }
}
using FREngine;

// Engine must already be initialized with sdkPath and licensePath
private void ConfigureLanguages(IEngine engine, string[] languageCodes)
{
    // Create language parameters object
    var langParams = engine.CreateLanguageParams();

    // Add each language — string names must match installed data file names
    // Missing data file causes runtime failure
    foreach (var lang in languageCodes)
    {
        langParams.Languages.Add(lang);  // e.g., "English", "French", "German"
    }

    // Language params are associated at the profile level, not per-document
    // Changing languages requires reloading profile or reinitializing engine
    engine.LoadPredefinedProfile("DocumentConversion_Accuracy");
}

public string RecognizeFrenchDocument(IEngine engine, string imagePath)
{
    var langParams = engine.CreateLanguageParams();
    langParams.Languages.Add("French");  // Requires FrenchLanguage data files at runtime path

    var document = engine.CreateFRDocument();
    try
    {
        document.AddImageFile(imagePath, null, null);
        document.Process(null);
        return document.PlainText.Text;
    }
    finally
    {
        document.Close();
    }
}
Imports FREngine

' Engine must already be initialized with sdkPath and licensePath
Private Sub ConfigureLanguages(engine As IEngine, languageCodes As String())
    ' Create language parameters object
    Dim langParams = engine.CreateLanguageParams()

    ' Add each language — string names must match installed data file names
    ' Missing data file causes runtime failure
    For Each lang In languageCodes
        langParams.Languages.Add(lang)  ' e.g., "English", "French", "German"
    Next

    ' Language params are associated at the profile level, not per-document
    ' Changing languages requires reloading profile or reinitializing engine
    engine.LoadPredefinedProfile("DocumentConversion_Accuracy")
End Sub

Public Function RecognizeFrenchDocument(engine As IEngine, imagePath As String) As String
    Dim langParams = engine.CreateLanguageParams()
    langParams.Languages.Add("French")  ' Requires FrenchLanguage data files at runtime path

    Dim document = engine.CreateFRDocument()
    Try
        document.AddImageFile(imagePath, Nothing, Nothing)
        document.Process(Nothing)
        Return document.PlainText.Text
    Finally
        document.Close()
    End Try
End Function
$vbLabelText   $csharpLabel

IronOCR Ansatz:

using IronOcr;

// Single language — install IronOcr.Languages.French via NuGet first
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.French;
var result = ocr.Read("french-document.jpg");
Console.WriteLine(result.Text);

// Multiple simultaneous languages — operator overload, no data file management
var multiOcr = new IronTesseract();
multiOcr.Language = OcrLanguage.French + OcrLanguage.German + OcrLanguage.English;
var multiResult = multiOcr.Read("multilingual-contract.jpg");
Console.WriteLine(multiResult.Text);
using IronOcr;

// Single language — install IronOcr.Languages.French via NuGet first
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.French;
var result = ocr.Read("french-document.jpg");
Console.WriteLine(result.Text);

// Multiple simultaneous languages — operator overload, no data file management
var multiOcr = new IronTesseract();
multiOcr.Language = OcrLanguage.French + OcrLanguage.German + OcrLanguage.English;
var multiResult = multiOcr.Read("multilingual-contract.jpg");
Console.WriteLine(multiResult.Text);
Imports IronOcr

' Single language — install IronOcr.Languages.French via NuGet first
Dim ocr As New IronTesseract()
ocr.Language = OcrLanguage.French
Dim result = ocr.Read("french-document.jpg")
Console.WriteLine(result.Text)

' Multiple simultaneous languages — operator overload, no data file management
Dim multiOcr As New IronTesseract()
multiOcr.Language = OcrLanguage.French + OcrLanguage.German + OcrLanguage.English
Dim multiResult = multiOcr.Read("multilingual-contract.jpg")
Console.WriteLine(multiResult.Text)
$vbLabelText   $csharpLabel

Sprachpakete installieren sich als Standard-NuGet-Pakete (dotnet add package IronOcr.Languages.French). Keine manuell bereitzustellenden Datendateien, keine Pfadkonfiguration, keine Neuinitialisierung der Engine beim Sprachwechsel. Der Leitfaden für mehrere Sprachen behandelt das Kombinieren von Sprachen, und im Sprachenindex sind alle über 125 verfügbaren Pakete aufgeführt.

Mehrbild-TIFF-Verarbeitung

ABBYY verarbeitet mehrseitige TIFF-Dateien, indem es die Einzelbilder durchläuft und jedes Einzelbild als separate Dokumentseite hinzufügt. Die Anzahl der Einzelbilder muss aus dem TIFF-Objekt abgerufen werden, anschließend wird jedes Einzelbild einzeln dem Dokumentcontainer hinzugefügt.

ABBYY FineReader-Ansatz:

using FREngine;

public string ProcessMultiFrameTiff(IEngine engine, string tiffPath)
{
    var document = engine.CreateFRDocument();

    try
    {
        // Must add each frame individually — no automatic multi-frame handling
        // Page count requires reading the TIFF metadata before processing
        var imageInfo = engine.CreateImageInfo();
        imageInfo.LoadImageFile(tiffPath);
        int frameCount = imageInfo.FrameCount;

        for (int i = 0; i < frameCount; i++)
        {
            // Each frame added with its frame index via image processing params
            var imgParams = engine.CreateImageProcessingParams();
            imgParams.FrameIndex = i;
            document.AddImageFile(tiffPath, imgParams, null);
        }

        document.Process(null);
        return document.PlainText.Text;
    }
    finally
    {
        document.Close();
    }
}
using FREngine;

public string ProcessMultiFrameTiff(IEngine engine, string tiffPath)
{
    var document = engine.CreateFRDocument();

    try
    {
        // Must add each frame individually — no automatic multi-frame handling
        // Page count requires reading the TIFF metadata before processing
        var imageInfo = engine.CreateImageInfo();
        imageInfo.LoadImageFile(tiffPath);
        int frameCount = imageInfo.FrameCount;

        for (int i = 0; i < frameCount; i++)
        {
            // Each frame added with its frame index via image processing params
            var imgParams = engine.CreateImageProcessingParams();
            imgParams.FrameIndex = i;
            document.AddImageFile(tiffPath, imgParams, null);
        }

        document.Process(null);
        return document.PlainText.Text;
    }
    finally
    {
        document.Close();
    }
}
Imports FREngine

Public Function ProcessMultiFrameTiff(engine As IEngine, tiffPath As String) As String
    Dim document = engine.CreateFRDocument()

    Try
        ' Must add each frame individually — no automatic multi-frame handling
        ' Page count requires reading the TIFF metadata before processing
        Dim imageInfo = engine.CreateImageInfo()
        imageInfo.LoadImageFile(tiffPath)
        Dim frameCount As Integer = imageInfo.FrameCount

        For i As Integer = 0 To frameCount - 1
            ' Each frame added with its frame index via image processing params
            Dim imgParams = engine.CreateImageProcessingParams()
            imgParams.FrameIndex = i
            document.AddImageFile(tiffPath, imgParams, Nothing)
        Next

        document.Process(Nothing)
        Return document.PlainText.Text
    Finally
        document.Close()
    End Try
End Function
$vbLabelText   $csharpLabel

IronOCR Ansatz:

using IronOcr;

// LoadImageFrames handles multi-frame TIFF automatically
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff");

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

// Per-page results accessible directly
foreach (var page in result.Pages)
{
    Console.WriteLine($"Frame {page.PageNumber}: {page.Text.Length} characters");
    Console.WriteLine(page.Text);
}
using IronOcr;

// LoadImageFrames handles multi-frame TIFF automatically
using var input = new OcrInput();
input.LoadImageFrames("scanned-batch.tiff");

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

// Per-page results accessible directly
foreach (var page in result.Pages)
{
    Console.WriteLine($"Frame {page.PageNumber}: {page.Text.Length} characters");
    Console.WriteLine(page.Text);
}
Imports IronOcr

' LoadImageFrames handles multi-frame TIFF automatically
Using input As New OcrInput()
    input.LoadImageFrames("scanned-batch.tiff")

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

    ' Per-page results accessible directly
    For Each page In result.Pages
        Console.WriteLine($"Frame {page.PageNumber}: {page.Text.Length} characters")
        Console.WriteLine(page.Text)
    Next
End Using
$vbLabelText   $csharpLabel

OcrInput.LoadImageFrames liest jeden Frame in einem mehrseitigen TIFF ohne manuelle Iteration. Das Ergebnis bietet pro Seite Zugriff durch result.Pages, einschließlich Text-, Koordinatendaten und Vertrauen pro Rahmen. Der Leitfaden zur TIFF-Eingabe behandelt sowohl die Verarbeitung von Mehrbild-TIFFs als auch von animierten GIFs.

Parallele Stapelverarbeitung

ABBYYs COM-basierte Engine ist nicht sicher, um CreateFRDocument zu gleichzeitigen Aufrufen von mehreren Threads ohne Synchronisationsstrategie aufzurufen. Produktionsbasierte Batch-Prozessoren verwalten typischerweise einen Pool von Engine-Instanzen oder serialisieren den Zugriff durch eine Sperre. Beide Ansätze fügen eine Infrastruktur hinzu, die IronOCR überflüssig macht.

ABBYY FineReader-Ansatz:

using FREngine;
using System.Collections.Concurrent;
using System.Threading;

public class AbbyyBatchProcessor
{
    // Pool required because engine is not safely concurrent
    private readonly SemaphoreSlim _engineLock = new SemaphoreSlim(1, 1);
    private IEngine _engine;

    public async Task<Dictionary<string, string>> ProcessBatchAsync(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // Must serialize — one document at a time through single engine
        foreach (var imagePath in imagePaths)
        {
            await _engineLock.WaitAsync();
            try
            {
                var document = _engine.CreateFRDocument();
                try
                {
                    document.AddImageFile(imagePath, null, null);
                    document.Process(null);
                    results[imagePath] = document.PlainText.Text;
                }
                finally
                {
                    document.Close();
                }
            }
            finally
            {
                _engineLock.Release();
            }
        }

        return new Dictionary<string, string>(results);
    }
}
using FREngine;
using System.Collections.Concurrent;
using System.Threading;

public class AbbyyBatchProcessor
{
    // Pool required because engine is not safely concurrent
    private readonly SemaphoreSlim _engineLock = new SemaphoreSlim(1, 1);
    private IEngine _engine;

    public async Task<Dictionary<string, string>> ProcessBatchAsync(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // Must serialize — one document at a time through single engine
        foreach (var imagePath in imagePaths)
        {
            await _engineLock.WaitAsync();
            try
            {
                var document = _engine.CreateFRDocument();
                try
                {
                    document.AddImageFile(imagePath, null, null);
                    document.Process(null);
                    results[imagePath] = document.PlainText.Text;
                }
                finally
                {
                    document.Close();
                }
            }
            finally
            {
                _engineLock.Release();
            }
        }

        return new Dictionary<string, string>(results);
    }
}
Imports FREngine
Imports System.Collections.Concurrent
Imports System.Threading

Public Class AbbyyBatchProcessor
    ' Pool required because engine is not safely concurrent
    Private ReadOnly _engineLock As New SemaphoreSlim(1, 1)
    Private _engine As IEngine

    Public Async Function ProcessBatchAsync(imagePaths As String()) As Task(Of Dictionary(Of String, String))
        Dim results As New ConcurrentDictionary(Of String, String)()

        ' Must serialize — one document at a time through single engine
        For Each imagePath In imagePaths
            Await _engineLock.WaitAsync()
            Try
                Dim document = _engine.CreateFRDocument()
                Try
                    document.AddImageFile(imagePath, Nothing, Nothing)
                    document.Process(Nothing)
                    results(imagePath) = document.PlainText.Text
                Finally
                    document.Close()
                End Try
            Finally
                _engineLock.Release()
            End Try
        Next

        Return New Dictionary(Of String, String)(results)
    End Function
End Class
$vbLabelText   $csharpLabel

IronOCR Ansatz:

using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class OcrBatchProcessor
{
    public Dictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // IronTesseract is thread-safe — one instance per thread, fully parallel
        Parallel.ForEach(imagePaths, imagePath =>
        {
            var ocr = new IronTesseract();  // Each thread owns its instance
            var result = ocr.Read(imagePath);
            results[imagePath] = result.Text;
        });

        return new Dictionary<string, string>(results);
    }
}
using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class OcrBatchProcessor
{
    public Dictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // IronTesseract is thread-safe — one instance per thread, fully parallel
        Parallel.ForEach(imagePaths, imagePath =>
        {
            var ocr = new IronTesseract();  // Each thread owns its instance
            var result = ocr.Read(imagePath);
            results[imagePath] = result.Text;
        });

        return new Dictionary<string, string>(results);
    }
}
Imports IronOcr
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Public Class OcrBatchProcessor
    Public Function ProcessBatch(imagePaths As String()) As Dictionary(Of String, String)
        Dim results = New ConcurrentDictionary(Of String, String)()

        ' IronTesseract is thread-safe — one instance per thread, fully parallel
        Parallel.ForEach(imagePaths, Sub(imagePath)
                                         Dim ocr = New IronTesseract() ' Each thread owns its instance
                                         Dim result = ocr.Read(imagePath)
                                         results(imagePath) = result.Text
                                     End Sub)

        Return New Dictionary(Of String, String)(results)
    End Function
End Class
$vbLabelText   $csharpLabel

Jede IronTesseract-Instanz ist unabhängig. Parallel.ForEach sättigt verfügbare CPU-Kerne ohne gemeinsamen Zustand, Sperren oder Serialisierung. Die ABBYY-Version verarbeitet Dokumente trotz des asynchronen Wrappers sequenziell; Die IronOCR Version verarbeitet sie tatsächlich parallel. Das Beispiel mit Multithreading veranschaulicht dieses Muster anhand von Zeitvergleichen. Für eine übergeordnete Durchsatzsteuerung siehe den Leitfaden zur Geschwindigkeitsoptimierung .

Dokumentenexportpipeline

ABBYY unterstützt mehrere Exportformate über seine Export Methode mit FileExportFormatEnum Werten. Der Export nach DOCX, RTF oder Klartext erfordert das Erstellen von format-spezifischen Exportparameter-Objekten und dann den Aufruf von document.Export mit dem entsprechenden Enum-Wert und Parameterobjekt.

ABBYY FineReader-Ansatz:

using FREngine;

public class AbbyyExporter
{
    private IEngine _engine;

    public void ExportToMultipleFormats(string imagePath, string outputDir)
    {
        var document = _engine.CreateFRDocument();

        try
        {
            document.AddImageFile(imagePath, null, null);
            document.Process(null);

            string baseName = Path.GetFileNameWithoutExtension(imagePath);

            // Export as plain text
            document.Export(
                Path.Combine(outputDir, baseName + ".txt"),
                FileExportFormatEnum.FEF_TextUnicodeDefaults,
                null
            );

            // Export as searchable PDF (requires PDF export params)
            var pdfParams = _engine.CreatePDFExportParams();
            pdfParams.Scenario = PDFExportScenarioEnum.PDES_Balanced;
            pdfParams.UseOriginalPaperSize = true;
            document.Export(
                Path.Combine(outputDir, baseName + ".pdf"),
                FileExportFormatEnum.FEF_PDF,
                pdfParams
            );

            // Export as DOCX
            var docxParams = _engine.CreateDOCXExportParams();
            document.Export(
                Path.Combine(outputDir, baseName + ".docx"),
                FileExportFormatEnum.FEF_DOCX,
                docxParams
            );
        }
        finally
        {
            document.Close();
        }
    }
}
using FREngine;

public class AbbyyExporter
{
    private IEngine _engine;

    public void ExportToMultipleFormats(string imagePath, string outputDir)
    {
        var document = _engine.CreateFRDocument();

        try
        {
            document.AddImageFile(imagePath, null, null);
            document.Process(null);

            string baseName = Path.GetFileNameWithoutExtension(imagePath);

            // Export as plain text
            document.Export(
                Path.Combine(outputDir, baseName + ".txt"),
                FileExportFormatEnum.FEF_TextUnicodeDefaults,
                null
            );

            // Export as searchable PDF (requires PDF export params)
            var pdfParams = _engine.CreatePDFExportParams();
            pdfParams.Scenario = PDFExportScenarioEnum.PDES_Balanced;
            pdfParams.UseOriginalPaperSize = true;
            document.Export(
                Path.Combine(outputDir, baseName + ".pdf"),
                FileExportFormatEnum.FEF_PDF,
                pdfParams
            );

            // Export as DOCX
            var docxParams = _engine.CreateDOCXExportParams();
            document.Export(
                Path.Combine(outputDir, baseName + ".docx"),
                FileExportFormatEnum.FEF_DOCX,
                docxParams
            );
        }
        finally
        {
            document.Close();
        }
    }
}
Imports FREngine

Public Class AbbyyExporter
    Private _engine As IEngine

    Public Sub ExportToMultipleFormats(imagePath As String, outputDir As String)
        Dim document = _engine.CreateFRDocument()

        Try
            document.AddImageFile(imagePath, Nothing, Nothing)
            document.Process(Nothing)

            Dim baseName As String = Path.GetFileNameWithoutExtension(imagePath)

            ' Export as plain text
            document.Export(
                Path.Combine(outputDir, baseName & ".txt"),
                FileExportFormatEnum.FEF_TextUnicodeDefaults,
                Nothing
            )

            ' Export as searchable PDF (requires PDF export params)
            Dim pdfParams = _engine.CreatePDFExportParams()
            pdfParams.Scenario = PDFExportScenarioEnum.PDES_Balanced
            pdfParams.UseOriginalPaperSize = True
            document.Export(
                Path.Combine(outputDir, baseName & ".pdf"),
                FileExportFormatEnum.FEF_PDF,
                pdfParams
            )

            ' Export as DOCX
            Dim docxParams = _engine.CreateDOCXExportParams()
            document.Export(
                Path.Combine(outputDir, baseName & ".docx"),
                FileExportFormatEnum.FEF_DOCX,
                docxParams
            )
        Finally
            document.Close()
        End Try
    End Sub
End Class
$vbLabelText   $csharpLabel

IronOCR Ansatz:

using IronOcr;

public class OcrExporter
{
    public void ExportToMultipleFormats(string imagePath, string outputDir)
    {
        var ocr = new IronTesseract();
        var result = ocr.Read(imagePath);
        string baseName = Path.GetFileNameWithoutExtension(imagePath);

        // Plain text — direct property access
        File.WriteAllText(
            Path.Combine(outputDir, baseName + ".txt"),
            result.Text
        );

        // Searchable PDF — one method call, no parameter objects
        result.SaveAsSearchablePdf(
            Path.Combine(outputDir, baseName + ".pdf")
        );

        // hOCR format — for document management systems
        result.SaveAsHocrFile(
            Path.Combine(outputDir, baseName + ".hocr")
        );
    }
}
using IronOcr;

public class OcrExporter
{
    public void ExportToMultipleFormats(string imagePath, string outputDir)
    {
        var ocr = new IronTesseract();
        var result = ocr.Read(imagePath);
        string baseName = Path.GetFileNameWithoutExtension(imagePath);

        // Plain text — direct property access
        File.WriteAllText(
            Path.Combine(outputDir, baseName + ".txt"),
            result.Text
        );

        // Searchable PDF — one method call, no parameter objects
        result.SaveAsSearchablePdf(
            Path.Combine(outputDir, baseName + ".pdf")
        );

        // hOCR format — for document management systems
        result.SaveAsHocrFile(
            Path.Combine(outputDir, baseName + ".hocr")
        );
    }
}
Imports IronOcr
Imports System.IO

Public Class OcrExporter
    Public Sub ExportToMultipleFormats(imagePath As String, outputDir As String)
        Dim ocr As New IronTesseract()
        Dim result = ocr.Read(imagePath)
        Dim baseName As String = Path.GetFileNameWithoutExtension(imagePath)

        ' Plain text — direct property access
        File.WriteAllText(
            Path.Combine(outputDir, baseName & ".txt"),
            result.Text
        )

        ' Searchable PDF — one method call, no parameter objects
        result.SaveAsSearchablePdf(
            Path.Combine(outputDir, baseName & ".pdf")
        )

        ' hOCR format — for document management systems
        result.SaveAsHocrFile(
            Path.Combine(outputDir, baseName & ".hocr")
        )
    End Sub
End Class
$vbLabelText   $csharpLabel

IronOCRs OcrResult stellt .Text direkt bereit und bietet Ausgabemethoden ohne Parameterobjekte oder Format-Enums. Der SaveAsSearchablePdf-Aufruf verarbeitet den PDF-Export in einer Zeile im Gegensatz zu ABBYYs dreistufiger Parameter/Export-Sequenz. Der durchsuchbare PDF-Leitfaden behandelt Seitenbereichsoptionen und Komprimierungseinstellungen. Der hOCR-Exportleitfaden behandelt das HOCR-Format für Systeme, die positionsbezogene OCR-Ausgabe verarbeiten.

ABBYY FineReader API zu IronOCR Mapping-Referenz

ABBYY FineReader Engine IronOCR-Äquivalent
new EngineLoader() Nicht erforderlich
loader.GetEngineObject(sdkPath, licensePath) new IronTesseract()
engine.LoadPredefinedProfile("...") Nicht erforderlich (wird intern bearbeitet)
engine.CreateLanguageParams() Nicht erforderlich
langParams.Languages.Add("French") ocr.Language = OcrLanguage.French
langParams.Languages.Add("English") + langParams.Languages.Add("German") ocr.Language = OcrLanguage.English + OcrLanguage.German
engine.CreateFRDocument() new OcrInput()
engine.CreateFRDocumentFromImage(path, null) ocr.Read(path)
document.AddImageFile(path, null, null) input.LoadImage(path)
imageInfo.LoadImageFile(tiff) + frameCount Schleife input.LoadImageFrames(tiff)
engine.CreatePDFFile() dann pdfFile.Open(path, null, null) input.LoadPdf(path)
document.Process(null) ocr.Read(input)
document.PlainText.Text result.Text
frDocument.Pages[i].PlainText.Text result.Pages[i].Text
page.Layout.Blocks + BlockTypeEnum.BT_Table Prüfung result.Pages + Wort-Koordinaten-Daten
block.GetAsTableBlock() result.Pages[i].Lines (mit Koordinaten)
engine.CreatePDFExportParams() Nicht erforderlich
document.Export(path, FEF_PDF, params) result.SaveAsSearchablePdf(path)
document.Export(path, FEF_TextUnicodeDefaults, null) File.WriteAllText(path, result.Text)
engine.CreateDOCXExportParams() + Export Nicht direkt unterstützt
document.Close() Verarbeitet von using auf OcrInput
_engine.GetLicenseInfo().ExpirationDate IronOcr.License.IsValidLicense
Lizenzdateien (ABBYY.lic, ABBYY.key) IronOcr.License.LicenseKey = "key"
engine.CreateZone() + zone.SetBounds(x, y, w, h) new CropRectangle(x, y, width, height)

Gängige Migrationsprobleme und Lösungen

Problem 1: COM-Registrierungsfehler nach Entfernung des SDK

ABBYY: Nach dem Entfernen von FREngine.dll aus den Projektverweisen kann der Build immer noch mit Could not load type 'FREngine.EngineLoader' oder COM-Interop-Fehlern aus Klassen, die den alten Namensraum beibehalten haben, fehlschlagen.

Lösung: Suchen Sie nach allen FREngine und ABBYY.FineReader Nutzungen, bevor Sie den Verweis entfernen. Jede Klasse, die IDisposable spezifisch implementiert, um ein IEngine Feld zu nullen, muss ihre Entsorgungslogik durch using Blöcke auf OcrInput ersetzen:

// Before: explicit Close in finally
var document = _engine.CreateFRDocument();
try { document.Process(null); }
finally { document.Close(); }

// After: using pattern on OcrInput
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = new IronTesseract().Read(input);
// Before: explicit Close in finally
var document = _engine.CreateFRDocument();
try { document.Process(null); }
finally { document.Close(); }

// After: using pattern on OcrInput
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = new IronTesseract().Read(input);
Option Strict On



' Before: explicit Close in finally
Dim document = _engine.CreateFRDocument()
Try
    document.Process(Nothing)
Finally
    document.Close()
End Try

' After: using pattern on OcrInput
Using input As New OcrInput()
    input.LoadImage(imagePath)
    Dim result = New IronTesseract().Read(input)
End Using
$vbLabelText   $csharpLabel

Problem 2: Das Erkennungsprofil hat kein Äquivalent

ABBYY: Code, der engine.LoadPredefinedProfile("DocumentConversion_Speed") oder engine.LoadPredefinedProfile("FieldLevelRecognition") aufruft, verwendet ABBYY-spezifische Profile, um die Genauigkeit gegen den Durchsatz auszubalancieren. Es gibt keine gleichwertige IronOCR-Eigenschaft namens Profile.

Lösung:IronOCR stellt die gleichen Kompromisse durch IronTesseract.Configuration bereit. Für Geschwindigkeitsoptimierung setzen Sie ocr.Configuration.TesseractVersion = TesseractVersion.Tesseract5 (Standard) und reduzieren Sie Vorverarbeitungsfilter. Für maximale Genauigkeit fügen Sie die vollständige Vorverarbeitungspipeline hinzu:

// Speed-optimized
var ocr = new IronTesseract();
//Neinpreprocessing — fastest path
var result = ocr.Read("clean-document.jpg");

// Accuracy-optimized for difficult inputs
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage("degraded-scan.jpg");
input.Deskew();
input.DeNoise();
input.Contrast();
input.Binarize();
var result = ocr.Read(input);
// Speed-optimized
var ocr = new IronTesseract();
//Neinpreprocessing — fastest path
var result = ocr.Read("clean-document.jpg");

// Accuracy-optimized for difficult inputs
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage("degraded-scan.jpg");
input.Deskew();
input.DeNoise();
input.Contrast();
input.Binarize();
var result = ocr.Read(input);
Imports IronTesseract

' Speed-optimized
Dim ocr As New IronTesseract()
' Neinpreprocessing — fastest path
Dim result = ocr.Read("clean-document.jpg")

' Accuracy-optimized for difficult inputs
Dim ocr As New IronTesseract()
Using input As New OcrInput()
    input.LoadImage("degraded-scan.jpg")
    input.Deskew()
    input.DeNoise()
    input.Contrast()
    input.Binarize()
    Dim result = ocr.Read(input)
End Using
$vbLabelText   $csharpLabel

Der Leitfaden zur Bildqualitätskorrektur erklärt, welche Filter welche Probleme mit der Eingangsqualität beheben. Der Leitfaden zur Geschwindigkeitsoptimierung beschreibt Konfigurationseigenschaften, die die Verarbeitungszeit bei sauberen Dokumenten verkürzen.

Problem 3: Der Schritt zur Bereitstellung der Lizenzdatei verbleibt in CI/CD

ABBYY: Build-Pipelines enthalten typischerweise einen Schritt, der ABBYY.lic und ABBYY.key aus einem sicheren Store auf das Bereitstellungsziel kopiert. Nach der Migration vergessen die Teams manchmal, diesen Schritt zu entfernen, wodurch toter Bereitstellungscode zurückbleibt, der auf nicht mehr existierende Pfade verweist.

Lösung: Den Schritt des Kopierens der Lizenzdatei vollständig entfernen. Ersetzen Sie dies durch einen Schritt mit Umgebungsvariablen-Injektion:

# Remove these CI/CD steps after migration:
# - name: Copy ABBYY license files
#   run: |
#     cp $SECRETS_PATH/ABBYY.lic $DEPLOY_PATH/License/
#     cp $SECRETS_PATH/ABBYY.key $DEPLOY_PATH/License/

# Add this instead (environment variable injection):
# - name: Set IronOCR license
#   env:
#     IRONOCR_LICENSE_KEY: ${{secrets.IRONOCR_LICENSE}}
# Remove these CI/CD steps after migration:
# - name: Copy ABBYY license files
#   run: |
#     cp $SECRETS_PATH/ABBYY.lic $DEPLOY_PATH/License/
#     cp $SECRETS_PATH/ABBYY.key $DEPLOY_PATH/License/

# Add this instead (environment variable injection):
# - name: Set IronOCR license
#   env:
#     IRONOCR_LICENSE_KEY: ${{secrets.IRONOCR_LICENSE}}
YAML

Und beim Anwendungsstart:

IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
    ?? throw new InvalidOperationException("IRONOCR_LICENSE_KEY not set");
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
    ?? throw new InvalidOperationException("IRONOCR_LICENSE_KEY not set");
Imports System

IronOcr.License.LicenseKey = If(Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY"), Throw New InvalidOperationException("IRONOCR_LICENSE_KEY not set"))
$vbLabelText   $csharpLabel

Problem 4: Motor nicht threadsicher – Vorhandener Sperrcode

ABBYY: Anwendungen, die ABBYY aus mehreren Threads aufrufen, enthalten typischerweise SemaphoreSlim, lock-Anweisungen oder thread-lokale Engine-Instanzen, um COM-Threading-Problemen zu vermeiden. Dieser Synchronisierungscode ist spezifisch für das Threading-Modell von ABBYY.

Lösung: Löschen Sie den gesamten Synchronisierungscode, der ABBYY-Aufrufe umschließt. IronOCRs IronTesseract kann sicher pro Thread instanziiert werden:

// Remove all of this:
// private readonly SemaphoreSlim _engineLock = new SemaphoreSlim(1, 1);
// await _engineLock.WaitAsync();
// try { ... } finally { _engineLock.Release(); }

// Replace with:
Parallel.ForEach(documents, doc =>
{
    var ocr = new IronTesseract(); // One per thread — no lock needed
    results[doc.Id] = ocr.Read(doc.Path).Text;
});
// Remove all of this:
// private readonly SemaphoreSlim _engineLock = new SemaphoreSlim(1, 1);
// await _engineLock.WaitAsync();
// try { ... } finally { _engineLock.Release(); }

// Replace with:
Parallel.ForEach(documents, doc =>
{
    var ocr = new IronTesseract(); // One per thread — no lock needed
    results[doc.Id] = ocr.Read(doc.Path).Text;
});
Imports System.Threading.Tasks

Parallel.ForEach(documents, Sub(doc)
    Dim ocr = New IronTesseract() ' One per thread — no lock needed
    results(doc.Id) = ocr.Read(doc.Path).Text
End Sub)
$vbLabelText   $csharpLabel

Problem 5: CreateImageInfo / FrameCount Muster für TIFF

ABBYY: Code, der Frame-Anzahlen aus TIFF-Dateien mit engine.CreateImageInfo() und imageInfo.LoadImageFile() liest, bevor durch Frameworks iteriert wird, hat kein direktes Äquivalent in IronOCR, da OcrInput.LoadImageFrames die Rahmenaufzählung intern behandelt.

Lösung: Die Frame-Zählschleife vollständig entfernen:

// Remove:
// var imageInfo = engine.CreateImageInfo();
// imageInfo.LoadImageFile(tiffPath);
// for (int i = 0; i < imageInfo.FrameCount; i++) { document.AddImageFile(...) }

// Replace with:
using var input = new OcrInput();
input.LoadImageFrames("multi-page-scan.tiff");
var result = new IronTesseract().Read(input);
// result.Pages contains one entry per TIFF frame
// Remove:
// var imageInfo = engine.CreateImageInfo();
// imageInfo.LoadImageFile(tiffPath);
// for (int i = 0; i < imageInfo.FrameCount; i++) { document.AddImageFile(...) }

// Replace with:
using var input = new OcrInput();
input.LoadImageFrames("multi-page-scan.tiff");
var result = new IronTesseract().Read(input);
// result.Pages contains one entry per TIFF frame
Imports IronOcr

' Remove:
' Dim imageInfo = engine.CreateImageInfo()
' imageInfo.LoadImageFile(tiffPath)
' For i As Integer = 0 To imageInfo.FrameCount - 1
'     document.AddImageFile(...)
' Next

' Replace with:
Using input As New OcrInput()
    input.LoadImageFrames("multi-page-scan.tiff")
    Dim result = New IronTesseract().Read(input)
    ' result.Pages contains one entry per TIFF frame
End Using
$vbLabelText   $csharpLabel

Problem 6: DOCX-Export hat kein direktes Äquivalent

ABBYY: document.Export(path, FileExportFormatEnum.FEF_DOCX, docxParams) produziert ein Word-Dokument.IronOCR erzeugt keine direkte DOCX-Ausgabe.

Lösung:IronOCR erzeugt durchsuchbare PDFs und strukturierte Textdaten. Für Workflows, die eine DOCX-Ausgabe erfordern, besteht der praktische Migrationspfad darin, ein durchsuchbares PDF zu erstellen und es nachgelagert zu konvertieren oder strukturierten Text zu extrahieren und ihn mithilfe einer Bibliothek wie dem Open XML SDK in ein DOCX zu schreiben:

//IronOCR to searchable PDF (closest equivalent)
var result = new IronTesseract().Read(inputPath);
result.SaveAsSearchablePdf(outputPath.Replace(".docx", ".pdf"));

// Or extract structured text for downstream DOCX generation
foreach (var paragraph in result.Paragraphs)
{
    Console.WriteLine(paragraph.Text);
    // Write to DOCX via Open XML SDK or similar
}
//IronOCR to searchable PDF (closest equivalent)
var result = new IronTesseract().Read(inputPath);
result.SaveAsSearchablePdf(outputPath.Replace(".docx", ".pdf"));

// Or extract structured text for downstream DOCX generation
foreach (var paragraph in result.Paragraphs)
{
    Console.WriteLine(paragraph.Text);
    // Write to DOCX via Open XML SDK or similar
}
Imports IronOcr

' IronOCR to searchable PDF (closest equivalent)
Dim result = New IronTesseract().Read(inputPath)
result.SaveAsSearchablePdf(outputPath.Replace(".docx", ".pdf"))

' Or extract structured text for downstream DOCX generation
For Each paragraph In result.Paragraphs
    Console.WriteLine(paragraph.Text)
    ' Write to DOCX via Open XML SDK or similar
Next
$vbLabelText   $csharpLabel

Der Leitfaden zu den Leseergebnissen beschreibt den Zugriff auf Absätze, Zeilen, Wörter und Koordinatendaten auf Zeichenebene für die Weiterverarbeitung.

ABBYY FineReader Migrations-Checkliste

Vor der Migration anfallende Aufgaben

Prüfen Sie den Quellcode, bevor Sie Änderungen vornehmen:

# Find all files using ABBYY namespaces
grep -r "using FREngine" --include="*.cs" .
grep -r "using ABBYY" --include="*.cs" .

# Find engine lifecycle patterns
grep -r "EngineLoader\|GetEngineObject\|LoadPredefinedProfile" --include="*.cs" .

# Find document lifecycle patterns
grep -r "CreateFRDocument\|document\.Close\|AddImageFile\|document\.Process" --include="*.cs" .

# Find language configuration
grep -r "CreateLanguageParams\|langParams\.Languages" --include="*.cs" .

# Find export calls
grep -r "FileExportFormatEnum\|CreatePDFExportParams\|document\.Export" --include="*.cs" .

# Find license file references in CI/CD and deployment scripts
grep -r "ABBYY\.lic\|ABBYY\.key" .
# Find all files using ABBYY namespaces
grep -r "using FREngine" --include="*.cs" .
grep -r "using ABBYY" --include="*.cs" .

# Find engine lifecycle patterns
grep -r "EngineLoader\|GetEngineObject\|LoadPredefinedProfile" --include="*.cs" .

# Find document lifecycle patterns
grep -r "CreateFRDocument\|document\.Close\|AddImageFile\|document\.Process" --include="*.cs" .

# Find language configuration
grep -r "CreateLanguageParams\|langParams\.Languages" --include="*.cs" .

# Find export calls
grep -r "FileExportFormatEnum\|CreatePDFExportParams\|document\.Export" --include="*.cs" .

# Find license file references in CI/CD and deployment scripts
grep -r "ABBYY\.lic\|ABBYY\.key" .
SHELL

Dokumentieren Sie jede Klasse, die ein IEngine oder IFRDocument Feld enthält. Beachten Sie, welche Exportformate verwendet werden – für die DOCX-Ausgabe ist ein alternativer Ansatz erforderlich (siehe Punkt 6 oben).

Aufgaben der Code-Aktualisierung

  1. Entfernen Sie den FREngine.dll Verweis aus allen .csproj Dateien
  2. Führen Sie dotnet add package IronOcr in jedem Projekt aus, das ABBYY verwendet hat
  3. Fügen Sie IronOcr.License.LicenseKey = ... beim Start der Anwendung hinzu (Program.cs oder Startklasse)
  4. Installieren Sie Sprach-NuGet-Pakete für jede nicht-englische Sprache (dotnet add package IronOcr.Languages.French, etc.)
  5. Löschen Sie alle EngineLoader, GetEngineObject und LoadPredefinedProfile-Aufrufe
  6. Löschen Sie alle CreateLanguageParams und langParams.Languages.Add-Aufrufe
  7. Ersetzen Sie engine.CreateFRDocument() + document.AddImageFile() + document.Process() mit new IronTesseract().Read(path)
  8. Ersetzen Sie mehrrahmige TIFF-Schleifen durch input.LoadImageFrames(tiffPath)
  9. Ersetzen Sie document.PlainText.Text durch result.Text
  10. Ersetzen Sie frDocument.Pages[i].PlainText.Text durch result.Pages[i].Text
  11. Ersetzen Sie document.Export(..., FEF_PDF, pdfParams) durch result.SaveAsSearchablePdf(path)
  12. Ersetzen Sie alle document.Close()-Aufrufe durch using Blöcke auf OcrInput
  13. Löschen Sie SemaphoreSlim und den Sperrcode, der den Zugriff auf die ABBYY-Engine serialisierte
  14. Ersetzen Sie engine.CreateZone() / zone.SetBounds() / page.Zones.Add() mit new CropRectangle(x, y, width, height), das an input.LoadImage() übergeben wird
  15. Schritte zum Kopieren der Lizenzdatei aus den CI/CD-Pipelines entfernen
  16. Aktualisieren Sie Docker-Images — Entfernen Sie die SDK-Installationsschicht, fügen Sie libgdiplus für Linux-Ziele hinzu

Post-Migrationstests

  • Überprüfen Sie die Ergebnisse der Textextraktion anhand einer repräsentativen Stichprobe jedes Dokumenttyps (Rechnungen, Verträge, gescannte Formulare).
  • Bestätigen Sie, dass die Verarbeitung mehrseitiger TIFF-Dateien die gleiche Anzahl an Seiten liefert wie die von ABBYY erzeugten Frames.
  • Testen Sie mehrsprachige Dokumente anhand derselben Eingaben, die für den ABBYY-Baseline-Vergleich verwendet wurden.
  • Überprüfen Sie, ob die durchsuchbare PDF-Ausgabe in Adobe Reader und Browser-PDF-Viewern textdurchsuchbar ist.
  • Führen Sie den parallelen Batch-Prozessor mit dem Produktions-Parallelitätsgrad aus und bestätigen Sie, dass keine Ausnahmen auftreten.
  • Überprüfen Sie result.Confidence auf gut bekannte Dokumente, um einen Grundschwellenwert für Qualitätskontrollen festzulegen
  • Testen der Lizenzschlüsselinitialisierung aus der Umgebungsvariablen in der Staging-Bereitstellungsumgebung
  • Überprüfen, ob das Docker-Image OCR ohne die Einbindung des ABBYY SDK-Volumes erstellt und ausführt.
  • Bestätigen, dass die CI/CD-Pipeline ohne den Schritt zum Kopieren der Lizenzdatei abgeschlossen wird.
  • Führen Sie einen Speicherprofiler auf dem Batch-Prozessor aus, um zu bestätigen, dass keine OcrInput-Objekte auslaufen (überprüfen Sie die using Platzierung)

Wichtigste Vorteile der Migration zu IronOCR

Der Bereitstellungsaufwand sinkt um eine Größenordnung. Jede ABBYY-Bereitstellung erforderte die Installation des SDKs, das Platzieren der Lizenzdatei, die Konfiguration des Laufzeitpfads und die Überprüfung, ob sich die Dateien an den richtigen Pfaden befanden, bevor die Anwendung gestartet werden konnte.IronOCR wird als NuGet Abhängigkeit bereitgestellt. dotnet publish produziert ein eigenständiges Artefakt mit der enthaltenen OCR-Engine. Der Docker-Bereitstellungsleitfaden und der Azure-Einrichtungsleitfaden zeigen die vollständige Konfiguration – beide passen auf eine einzige Seite.

COM-Interop ist weg. Das Entfernen der COM-Schicht beseitigt eine ganze Kategorie von Laufzeitfehlern: COM-Registrierungsfehler auf neuen Maschinen, Apartment-Threading-Mismatches, RCW-Lebenszyklus-Bugs und die 15-25 Zeilen von try/finally Boilerplate, die jeder ABBYY-Dokumentenverarbeitungsaufruf erforderte. Die Codebasis wird kleiner. Die Fehlerfläche verkleinert sich damit.

Zunehmendes Dokumentenvolumen führt nicht mehr zu Budgetüberprüfungen. Die unbefristete Lizenz von IronOCR deckt unbegrenztes Dokumentenvolumen ab. Eine Anwendung, die im ersten Jahr 10.000 Dokumente pro Monat und im dritten Jahr 2.000.000 Dokumente pro Monat verarbeitet, verursacht die gleichen OCR-Lizenzkosten. Es gibt keine Seitenzähler, keine Rechnungen für Mehrverbrauch und keine Neuverhandlung von Mengenrabatten. Auf der Lizenzseite werden alle Stufen angezeigt – die Professional -Lizenz für 2.999 US-Dollar deckt zehn Entwickler ab, die ein beliebiges Volumen auf einer beliebigen Anzahl von Bereitstellungszielen verarbeiten.

Plattformübergreifende Bereitstellung eröffnet neue Infrastrukturoptionen. Die ABBYY COM-Schicht erfordert Windows. Teams, die die Dokumentenverarbeitung aus Kosten- oder Dichtegründen auf Linux-Container verlagern wollten, wurden daran gehindert.IronOCR läuft auf Windows, Linux und macOS identisch und wird aus demselben NuGet Paket bereitgestellt. Durch die Migration von ABBYY wird die Windows-Beschränkung auf der OCR-Ebene des Anwendungsstacks beseitigt. Der Linux-Bereitstellungsleitfaden und der AWS-Bereitstellungsleitfaden beschreiben die vollständige Einrichtung für jede Umgebung.

Paralleler Durchsatz ist ohne Infrastrukturaufwand verfügbar. Die Sperrstrategien, die den Zugriff auf die serialisierte ABBYY-Engine bisher eingeschränkt haben, gehören der Vergangenheit an. IronTesseract Instanzen sind unabhängig: eine pro Thread hochfahren, Parallel.ForEach über einen Dokumentenstapel laufen lassen, Ergebnisse erhalten. Der Durchsatz skaliert mit den verfügbaren CPU-Kernen ohne zusätzlichen Code. Das Beispiel mit Multithreading demonstriert Verbesserungen der Wandzeit auf Mehrkernhardware.

Die Sprachkonfiguration ist eine Paketreferenz. Das Hinzufügen von deutscher oder japanischer OCR-Unterstützung zu einer ABBYY-Integration erforderte das Identifizieren von Datendateien, deren Bereitstellung in Laufzeitpfaden auf jedem Zielrechner und die Behandlung von Fehlern, wenn Dateien fehlten. Mit IronOCR fügt dotnet add package IronOcr.Languages.German das Sprachpaket als versionierte, reproduzierbare NuGet-Abhängigkeit hinzu. Der Paketmanager stellt sicher, dass die Daten bei jedem Build vorhanden sind. Der Leitfaden für benutzerdefinierte Sprachpakete behandelt das Training und die Bereitstellung benutzerdefinierter Sprachmodelle für spezialisierte Domänen.

Hinweis:ABBYY FineReader und Tesseract sind eingetragene Marken ihrer jeweiligen Eigentümer. Diese Seite ist weder mit, noch unterstützt, noch gesponsert von ABBYY oder Google. 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 ABBYY FineReader Engine 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 ABBYY FineReader Engine zu IronOCR?

Ersetzen Sie ABBYY FineReader-Initialisierungssequenzen durch IronTesseract-Instanziierung, entfernen Sie COM-Lebenszyklusmanagement (explizite Create/Load/Close-Muster) und aktualisieren Sie die Namen von 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.

Kann IronOCR die OCR-Genauigkeit von ABBYY FineReader Engine für Standardgeschäftsdokumente erreichen?

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 von ABBYY FineReader Engine separat installiert werden?

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 ABBYY FineReader Engine zu IronOCR Änderungen an der Bereitstellungsinfrastruktur?

IronOCR erfordert weniger Änderungen an der Infrastruktur als ABBYY FineReader Engine. Es gibt keine SDK-Binärpfade, Lizenzdateiplätze oder Lizenzserverkonfigurationen. Das NuGet-Paket enthält die komplette OCR-Engine, und der Lizenzschlüssel ist ein String, der im Anwendungscode festgelegt wird.

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 ABBYY FineReader?

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 bei der Skalierung von Workloads berechenbarer als die von ABBYY FineReader Engine?

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 nach der Migration von ABBYY FineReader Engine zu IronOCR?

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