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")
// 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()
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>
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
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"
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")
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
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
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
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)
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
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
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
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
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
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
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
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
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}}
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"))
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)
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
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
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" .
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
- Entfernen Sie den
FREngine.dllVerweis aus allen.csprojDateien - Führen Sie
dotnet add package IronOcrin jedem Projekt aus, das ABBYY verwendet hat - Fügen Sie
IronOcr.License.LicenseKey = ...beim Start der Anwendung hinzu (Program.csoder Startklasse) - Installieren Sie Sprach-NuGet-Pakete für jede nicht-englische Sprache (
dotnet add package IronOcr.Languages.French, etc.) - Löschen Sie alle
EngineLoader,GetEngineObjectundLoadPredefinedProfile-Aufrufe - Löschen Sie alle
CreateLanguageParamsundlangParams.Languages.Add-Aufrufe - Ersetzen Sie
engine.CreateFRDocument()+document.AddImageFile()+document.Process()mitnew IronTesseract().Read(path) - Ersetzen Sie mehrrahmige TIFF-Schleifen durch
input.LoadImageFrames(tiffPath) - Ersetzen Sie
document.PlainText.Textdurchresult.Text - Ersetzen Sie
frDocument.Pages[i].PlainText.Textdurchresult.Pages[i].Text - Ersetzen Sie
document.Export(..., FEF_PDF, pdfParams)durchresult.SaveAsSearchablePdf(path) - Ersetzen Sie alle
document.Close()-Aufrufe durchusingBlöcke aufOcrInput - Löschen Sie
SemaphoreSlimund den Sperrcode, der den Zugriff auf die ABBYY-Engine serialisierte - Ersetzen Sie
engine.CreateZone()/zone.SetBounds()/page.Zones.Add()mitnew CropRectangle(x, y, width, height), das aninput.LoadImage()übergeben wird - Schritte zum Kopieren der Lizenzdatei aus den CI/CD-Pipelines entfernen
- Aktualisieren Sie Docker-Images — Entfernen Sie die SDK-Installationsschicht, fügen Sie
libgdiplusfü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.Confidenceauf 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 dieusingPlatzierung)
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.
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.

