Wie man arabischen Text aus Bildern mit OCR-Tools extrahiert
Dieser Leitfaden führt .NET -Entwickler durch eine vollständige Migration von GdPicture .NET OCR zu IronOCR . Es behandelt den Pakettausch, Namensraumänderungen und praktische Vorher/Nachher-Codemuster für jeden wichtigen OCR-Workflow, mit besonderem Fokus auf die Eliminierung des ganzzahligen Bild-ID-Lebenszyklus, der das Ressourcenverwaltungsmodell von GdPicture definiert. Das vorherige Lesen des Vergleichsartikels ist nicht erforderlich.
Warum von GdPicture .NET migrieren?
GdPicture .NET ist eine Dokumentenverarbeitungsplattform, die für Teams entwickelt wurde, die Scannerintegration, DICOM-Unterstützung, PDF-Bearbeitung, Annotation und OCR von einem einzigen Anbieter benötigen. Wenn OCR die einzige Anforderung ist, erzeugen die Preisgestaltung und die API-Architektur der Plattform Reibungsverluste, die sich im Laufe der Zeit summieren.
Kosten für ein einfaches OCR-Workflow-Plugin. Um Text aus gescannten PDFs zu extrahieren und durchsuchbare Ergebnisse zu generieren, werden drei separate Lizenzkomponenten benötigt: das Core SDK für ca. 4.000 US-Dollar, das OCR-Plugin für ca. 2.000 US-Dollar und das PDF-Plugin für ca. 2.000 US-Dollar. Die Einstiegskosten belaufen sich somit auf 8.000 US-Dollar Plus 20 % jährlicher Wartungsgebühren. Teams, die lediglich OCR benötigen, tragen die volle Preisstruktur einer Dokumentenverarbeitungsplattform.IronOCR umfasst denselben Workflow – Bild-OCR, PDF-OCR, Vorverarbeitung, durchsuchbare PDF-Ausgabe – aus einem einzigen Paket zu $999 bis $2.999 unbefristet, ohne Entscheidungen zur Lizenzierung einzelner Funktionen. Eine vollständige Aufschlüsselung der Lizenzstufen finden Sie auf der IronOCR -Lizenzseite .
Der Lebenszyklus der Ganzzahl-Bild-ID. Jedes über GdPicture geladene Bild gibt eine int zurück. Sie übergeben diese Ganzzahl an OCR-Operationen und rufen dann ReleaseGdPictureImage auf, wenn Sie fertig sind. Dieses Muster ist älter als IDisposable. Es funktioniert, wenn man es richtig befolgt; Es verursacht Speicherlecks, wenn es nicht erkannt wird. Bei Produktionsdiensten, die täglich Hunderte von Dokumenten verarbeiten, führt ein einziger verpasster Freigabeaufruf in einem Fehlerzweig zu einem Speicheranstieg, der sich nur schwer diagnostizieren lässt. IronOCR's OcrInput implementiert IDisposable — eine using-Anweisung eliminiert die gesamte Reinigungsbelastung.
Versionsspezifisches Namespace. GdPicture bettet die Hauptversionsnummer in sein Namespace ein: using GdPicture14. Ein Upgrade auf die nächste Hauptversion erfordert die Aktualisierung dieser using Direktive in jeder Quelldatei, die auf GdPicture-Klassen verweist. Bei einer großen Anwendung, bei der OCR über Dutzende von Diensten verteilt ist, wird daraus eine mehrstündige Such- und Ersetzungsaufgabe, die keine funktionale Verbesserung bringt. IronOCRs Namespace wurde bei allen Hauptversionen IronOcr.
Anforderung an den externen Ressourcenordner. GdPicture OCR erfordert eine ResourceFolder Eigenschaft, die zur Laufzeit auf ein Verzeichnis von .traineddata Sprachdateien verweist. Dieser Pfad funktioniert auf einer Entwicklungsmaschine, bricht jedoch auf Linux-Servern, Docker-Containern und Azure App Service-Bereitstellungen, wo die Verzeichnisstruktur nicht existiert.IronOCR bündelt den englischen Sprachsupport im NuGet-Paket; Zusätzliche Sprachen werden als NuGet Pakete installiert, die mit dem Build-Output übertragen werden.
Drei-Komponenten-Initialisierung. Ein PDF-OCR-Workflow in GdPicture erfordert die Instanziierung von GdPictureImaging, GdPictureOCR und GdPicturePDF — drei separate Komponenten mit individuellen Entsorgungsanforderungen — sowie die Lizenzmanagerregistrierung und die Zuweisung des Ressourcenordners.IronOCR benötigt beim Start eine Zeile und bei jedem Aufruf eine Klasse.
Keine native Thread-Sicherheit. GdPicture OCR-Instanzen sind nicht threadsicher. Die parallele Dokumentenverarbeitung erfordert ein sorgfältiges Instanzmanagement und eine präzise Synchronisierung, um Datenbeschädigungen zu vermeiden.IronOCR ist für den gleichzeitigen Gebrauch konzipiert: Erstellen Sie einen IronTesseract pro Thread oder teilen Sie eine einzelne Instanz unter Last — beide Muster funktionieren ohne zusätzlichen Synchronisationscode.
Das grundsätzliche Problem
GdPicture reserviert für jedes Bild einen Speicherwert als Laufzeit-verwalteten Integer-Handle. Jeder RenderPageToGdPictureImage-Aufruf in einer TIFF-Verarbeitungsschleife erstellt eine neue Zuweisung, die manuell freigegeben werden muss:
// GdPicture: every frame = new integer ID = manual release required
using var pdf = new GdPicturePDF();
pdf.LoadFromFile("multi-page.tiff", false);
var frameIds = new List<int>();
try
{
for (int i = 1; i <= pdf.GetPageCount(); i++)
{
pdf.SelectPage(i);
int frameId = pdf.RenderPageToGdPictureImage(200, false); // new allocation
if (frameId != 0) frameIds.Add(frameId);
// ... OCR call here ...
}
}
finally
{
foreach (var id in frameIds) _imaging.ReleaseGdPictureImage(id); // manual per-frame release
}
// GdPicture: every frame = new integer ID = manual release required
using var pdf = new GdPicturePDF();
pdf.LoadFromFile("multi-page.tiff", false);
var frameIds = new List<int>();
try
{
for (int i = 1; i <= pdf.GetPageCount(); i++)
{
pdf.SelectPage(i);
int frameId = pdf.RenderPageToGdPictureImage(200, false); // new allocation
if (frameId != 0) frameIds.Add(frameId);
// ... OCR call here ...
}
}
finally
{
foreach (var id in frameIds) _imaging.ReleaseGdPictureImage(id); // manual per-frame release
}
Imports System.Collections.Generic
' GdPicture: every frame = new integer ID = manual release required
Using pdf As New GdPicturePDF()
pdf.LoadFromFile("multi-page.tiff", False)
Dim frameIds As New List(Of Integer)()
Try
For i As Integer = 1 To pdf.GetPageCount()
pdf.SelectPage(i)
Dim frameId As Integer = pdf.RenderPageToGdPictureImage(200, False) ' new allocation
If frameId <> 0 Then frameIds.Add(frameId)
' ... OCR call here ...
Next
Finally
For Each id In frameIds
_imaging.ReleaseGdPictureImage(id) ' manual per-frame release
Next
End Try
End Using
IronOCR eliminiert den Lebenszyklus vollständig. OcrInput behandelt die Rahmennummerierung und -bereinigung:
// IronOCR: the using statement handles everything
using var input = new OcrInput();
input.LoadImageFrames("multi-page.tiff");
var result = new IronTesseract().Read(input);
// IronOCR: the using statement handles everything
using var input = new OcrInput();
input.LoadImageFrames("multi-page.tiff");
var result = new IronTesseract().Read(input);
Imports IronOcr
Dim input As New OcrInput()
Using input
input.LoadImageFrames("multi-page.tiff")
Dim result = New IronTesseract().Read(input)
End Using
IronOCR vs. GdPicture .NET: Funktionsvergleich
Die folgende Tabelle vergleicht die Funktionsabdeckung der beiden Bibliotheken für OCR-orientierte Arbeitsabläufe.
| Feature | GdPicture.NET | IronOCR |
|---|---|---|
| Installation | Mehrere NuGet Pakete | dotnet add package IronOcr |
| Lizenzaktivierung | LicenseManager.RegisterKEY() |
IronOcr.License.LicenseKey = "..." |
| Namespace bei größerem Upgrade | Erfordert Suchen-und-Ersetzen (GdPicture14 → weiter) |
Unverändert (IronOcr) |
| Komponenteninitialisierung | GdPictureImaging + GdPictureOCR + GdPicturePDF |
new IronTesseract() |
| Ressourcenspeichermodell | Manuelle Verfolgung und Freigabe von Ganzzahl-IDs | IDisposable / using Anweisung |
| Risiko eines Speicherlecks | Hoch (fehlend ReleaseGdPictureImage) |
Keine (compiler-erzwungen über using) |
| Externer Ressourcenordner | Erforderlich (_ocr.ResourceFolder = path) |
Nicht erforderlich – im Paket enthalten |
| Bild-OCR | Ja | Ja |
| PDF-OCR | Ja (PDF-Plugin erforderlich) | Integriert, keine zusätzliche Lizenz erforderlich |
| Mehrseitiges TIFF | Manuelle Frame-Schleife + Bereinigung der Frame-ID | input.LoadImageFrames() |
| Stream-Eingabe | Über GdPictureImaging Strom überladen |
input.LoadImage(stream) |
| Durchsuchbare PDF-Ausgabe | pdf.OcrPage() + pdf.SaveToFile() |
result.SaveAsSearchablePdf() |
| Vorverarbeitung des Entzerrens | Plugin für Dokumentenverarbeitung erforderlich | input.Deskew() — eingebaut |
| Geräuschentfernung | Plugin für Dokumentenverarbeitung erforderlich | input.DeNoise() — eingebaut |
| Sprachen | Tesseract-basierte Trainingsdatendateien im Ordner | Mehr als 125 über NuGet -Pakete |
| Mehrsprachige OCR | Ja | OcrLanguage.French + OcrLanguage.German |
| Thread-Sicherheit | Manuelle Instanzverwaltung | Thread-sicher durch Design |
| Asynchrone OCR | Nicht eingebaut | ReadAsync() |
| Barcode-Lesung | Separates Barcode-Plugin | ocr.Configuration.ReadBarCodes = true |
| Strukturierte Ausgabe | Indexbasierter Block-/Zeilen-/Wortzugriff | Typisiert .Pages, .Words, .Characters |
| Konfidenzbewertung | GetOCRResultConfidence(resultId) |
result.Confidence |
| Plattformübergreifend | Windows, Linux, macOS | Windows, Linux, macOS, Docker, AWS, Azure |
| Eingabekosten (OCR aus PDFs) | ~8.000 $ (Kernsoftware + OCR + PDF-Plugins) | $999–$2.999 |
| Preismodell | Plugin-basierte, unbefristete Lizenz + 20 %/Jahr Wartung | Feste, unbefristete Gebühr, optionale jährliche Aktualisierungen |
| Kommerzielle Unterstützung | Ja | Ja |
Schnellstart: Migration von GdPicture .NET zu IronOCR
Schritt 1: Ersetzen des NuGet-Pakets
Entfernen Sie die GdPicture-Pakete:
dotnet remove package GdPicture.NET
dotnet remove package GdPicture.NET.OCR
dotnet remove package GdPicture.NET.PDF
dotnet remove package GdPicture.NET
dotnet remove package GdPicture.NET.OCR
dotnet remove package GdPicture.NET.PDF
Installieren Sie IronOCR von der NuGet Paketseite :
dotnet add package IronOcr
Für weitere Sprachen als Englisch installieren Sie bitte das entsprechende Sprachpaket:
dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
Schritt 2: Namespaces aktualisieren
Ersetzen Sie den GdPicture-Namensraum durch den IronOCR Namensraum:
// Before (GdPicture)
using GdPicture14;
// After (IronOCR)
using IronOcr;
// Before (GdPicture)
using GdPicture14;
// After (IronOCR)
using IronOcr;
Imports IronOcr
Schritt 3: Lizenz initialisieren
Platzieren Sie diese Zeile in Program.cs oder Startup.cs, vor allen OCR-Aufrufen:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Entfernen Sie die GdPicture-Lizenzregistrierungssperre vollständig:
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
Auf der IronOCR -Produktseite ist ein kostenloser Testschlüssel zum Ausprobieren vor dem Kauf erhältlich.
Beispiele für die Code-Migration
Verarbeitung mehrseitiger TIFF-Frames
Die Verarbeitung mehrseitiger TIFF-Dateien in GdPicture erfordert die Auswahl jedes einzelnen Frames über die PDF/imaging-API, das Rendern zu einer neuen Bild-ID, die Durchführung der OCR-Texterkennung und die Freigabe der ID. Ein einzelner Rahmen, der im finally-Block nicht freigegeben wird, leckt 10–50 MB, je nach DPI.
GdPicture .NET -Ansatz:
using GdPicture14;
public class GdPictureTiffProcessor
{
private readonly GdPictureImaging _imaging;
private readonly GdPictureOCR _ocr;
public string ExtractTextFromTiff(string tiffPath)
{
var text = new StringBuilder();
// Load TIFF through the imaging component
int tiffId = _imaging.CreateGdPictureImageFromFile(tiffPath);
if (tiffId == 0)
throw new Exception($"TIFF load failed: {_imaging.GetStat()}");
// Outer try: release the original TIFF handle
try
{
int frameCount = _imaging.GetPageCount(tiffId);
for (int i = 1; i <= frameCount; i++)
{
// Switch to frame — modifies the existing ID in place
_imaging.SelectPage(tiffId, i);
// Clone frame to a new image ID for OCR
int frameId = _imaging.CloneImage(tiffId);
if (frameId == 0) continue;
// Inner try: release each cloned frame ID
try
{
_ocr.SetImage(frameId);
_ocr.Language = "eng";
string resultId = _ocr.RunOCR();
if (!string.IsNullOrEmpty(resultId))
{
text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}");
}
}
finally
{
// Release cloned frame — critical for each iteration
_imaging.ReleaseGdPictureImage(frameId);
}
}
}
finally
{
// Release original TIFF handle
_imaging.ReleaseGdPictureImage(tiffId);
}
return text.ToString();
}
}
using GdPicture14;
public class GdPictureTiffProcessor
{
private readonly GdPictureImaging _imaging;
private readonly GdPictureOCR _ocr;
public string ExtractTextFromTiff(string tiffPath)
{
var text = new StringBuilder();
// Load TIFF through the imaging component
int tiffId = _imaging.CreateGdPictureImageFromFile(tiffPath);
if (tiffId == 0)
throw new Exception($"TIFF load failed: {_imaging.GetStat()}");
// Outer try: release the original TIFF handle
try
{
int frameCount = _imaging.GetPageCount(tiffId);
for (int i = 1; i <= frameCount; i++)
{
// Switch to frame — modifies the existing ID in place
_imaging.SelectPage(tiffId, i);
// Clone frame to a new image ID for OCR
int frameId = _imaging.CloneImage(tiffId);
if (frameId == 0) continue;
// Inner try: release each cloned frame ID
try
{
_ocr.SetImage(frameId);
_ocr.Language = "eng";
string resultId = _ocr.RunOCR();
if (!string.IsNullOrEmpty(resultId))
{
text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}");
}
}
finally
{
// Release cloned frame — critical for each iteration
_imaging.ReleaseGdPictureImage(frameId);
}
}
}
finally
{
// Release original TIFF handle
_imaging.ReleaseGdPictureImage(tiffId);
}
return text.ToString();
}
}
Imports GdPicture14
Imports System.Text
Public Class GdPictureTiffProcessor
Private ReadOnly _imaging As GdPictureImaging
Private ReadOnly _ocr As GdPictureOCR
Public Function ExtractTextFromTiff(tiffPath As String) As String
Dim text As New StringBuilder()
' Load TIFF through the imaging component
Dim tiffId As Integer = _imaging.CreateGdPictureImageFromFile(tiffPath)
If tiffId = 0 Then
Throw New Exception($"TIFF load failed: {_imaging.GetStat()}")
End If
' Outer try: release the original TIFF handle
Try
Dim frameCount As Integer = _imaging.GetPageCount(tiffId)
For i As Integer = 1 To frameCount
' Switch to frame — modifies the existing ID in place
_imaging.SelectPage(tiffId, i)
' Clone frame to a new image ID for OCR
Dim frameId As Integer = _imaging.CloneImage(tiffId)
If frameId = 0 Then Continue For
' Inner try: release each cloned frame ID
Try
_ocr.SetImage(frameId)
_ocr.Language = "eng"
Dim resultId As String = _ocr.RunOCR()
If Not String.IsNullOrEmpty(resultId) Then
text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}")
End If
Finally
' Release cloned frame — critical for each iteration
_imaging.ReleaseGdPictureImage(frameId)
End Try
Next
Finally
' Release original TIFF handle
_imaging.ReleaseGdPictureImage(tiffId)
End Try
Return text.ToString()
End Function
End Class
IronOCR Ansatz:
using IronOcr;
public class IronOcrTiffProcessor
{
public string ExtractTextFromTiff(string tiffPath)
{
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // all frames loaded, all cleanup automatic
var result = new IronTesseract().Read(input);
// Per-frame text is available on result.Pages
foreach (var page in result.Pages)
Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}");
return result.Text;
}
}
using IronOcr;
public class IronOcrTiffProcessor
{
public string ExtractTextFromTiff(string tiffPath)
{
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // all frames loaded, all cleanup automatic
var result = new IronTesseract().Read(input);
// Per-frame text is available on result.Pages
foreach (var page in result.Pages)
Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}");
return result.Text;
}
}
Imports IronOcr
Public Class IronOcrTiffProcessor
Public Function ExtractTextFromTiff(tiffPath As String) As String
Using input As New OcrInput()
input.LoadImageFrames(tiffPath) ' all frames loaded, all cleanup automatic
Dim result = New IronTesseract().Read(input)
' Per-frame text is available on result.Pages
For Each page In result.Pages
Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}")
Next
Return result.Text
End Using
End Function
End Class
LoadImageFrames lädt alle Rahmen aus einem mehrseitigen TIFF in die OcrInput Pipeline. Der using-Block behandelt den gesamten Speicher, der mit jedem Rahmen am Ende des Bereichs verbunden ist. Kein List<int> zu warten, keine verschachtelten try/finally Blöcke erforderlich. Der Leitfaden zur Eingabe von TIFF- und GIF-Dateien behandelt die Auswahl der Einzelbilder und die Handhabung mehrerer Formate im Detail.
Streambasierte Eingabe ersetzt Plugin-Initialisierung
Serveranwendungen empfangen Dokumente häufig als Datenströme anstatt als Dateipfade – beispielsweise durch HTTP-Uploads, Message Queues oder Datenbank-Blobs. GdPicture erfordert das Laden des Streams über GdPictureImaging, was selbst die Initialisierungssequenz der Komponente und die Ressourcenordnerkonfiguration erfordert, die jeder Operation vorausgeht.
GdPicture .NET -Ansatz:
using GdPicture14;
public class GdPictureStreamOcr : IDisposable
{
private readonly GdPictureImaging _imaging;
private readonly GdPictureOCR _ocr;
public GdPictureStreamOcr()
{
// Plugin initialization required before stream loading is possible
var lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
_imaging = new GdPictureImaging();
_ocr = new GdPictureOCR();
_ocr.ResourceFolder = @"C:\GdPicture\Resources\OCR"; // path must exist at runtime
}
public string ExtractTextFromStream(Stream documentStream)
{
// Load stream into imaging component to get an image ID
int imageId = _imaging.CreateGdPictureImageFromStream(documentStream);
if (imageId == 0)
throw new Exception($"Stream load failed: {_imaging.GetStat()}");
try
{
_ocr.SetImage(imageId);
_ocr.Language = "eng";
string resultId = _ocr.RunOCR();
if (string.IsNullOrEmpty(resultId))
throw new Exception($"OCR failed: {_ocr.GetStat()}");
return _ocr.GetOCRResultText(resultId);
}
finally
{
_imaging.ReleaseGdPictureImage(imageId);
}
}
public void Dispose()
{
_ocr?.Dispose();
_imaging?.Dispose();
}
}
using GdPicture14;
public class GdPictureStreamOcr : IDisposable
{
private readonly GdPictureImaging _imaging;
private readonly GdPictureOCR _ocr;
public GdPictureStreamOcr()
{
// Plugin initialization required before stream loading is possible
var lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
_imaging = new GdPictureImaging();
_ocr = new GdPictureOCR();
_ocr.ResourceFolder = @"C:\GdPicture\Resources\OCR"; // path must exist at runtime
}
public string ExtractTextFromStream(Stream documentStream)
{
// Load stream into imaging component to get an image ID
int imageId = _imaging.CreateGdPictureImageFromStream(documentStream);
if (imageId == 0)
throw new Exception($"Stream load failed: {_imaging.GetStat()}");
try
{
_ocr.SetImage(imageId);
_ocr.Language = "eng";
string resultId = _ocr.RunOCR();
if (string.IsNullOrEmpty(resultId))
throw new Exception($"OCR failed: {_ocr.GetStat()}");
return _ocr.GetOCRResultText(resultId);
}
finally
{
_imaging.ReleaseGdPictureImage(imageId);
}
}
public void Dispose()
{
_ocr?.Dispose();
_imaging?.Dispose();
}
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
IronOCR Ansatz:
using IronOcr;
public class IronOcrStreamOcr
{
public string ExtractTextFromStream(Stream documentStream)
{
using var input = new OcrInput();
input.LoadImage(documentStream); // stream accepted directly — no imaging component
return new IronTesseract().Read(input).Text;
}
}
using IronOcr;
public class IronOcrStreamOcr
{
public string ExtractTextFromStream(Stream documentStream)
{
using var input = new OcrInput();
input.LoadImage(documentStream); // stream accepted directly — no imaging component
return new IronTesseract().Read(input).Text;
}
}
Imports IronOcr
Public Class IronOcrStreamOcr
Public Function ExtractTextFromStream(documentStream As Stream) As String
Using input As New OcrInput()
input.LoadImage(documentStream) ' stream accepted directly — no imaging component
Return New IronTesseract().Read(input).Text
End Using
End Function
End Class
Der GdPicture-Ansatz erfordert die Erstellung von drei Objekten und die Konfiguration eines Dateisystempfads, bevor der erste Datenstrom verarbeitet werden kann.IronOCR akzeptiert den Stream direkt auf OcrInput ohne vorherige Einrichtung. Der Stream Input Guide deckt Byte-Array, MemoryStream und FileStream-Muster für Pipeline-Architekturen ab, wo temporäre Dateischreibvorgänge unerwünscht sind.
Asynchrone OCR ersetzt Statuscode-Abfrage
GdPicture OCR ist synchron. Anwendungen, die Dokumente in ASP.NET Core-Endpunkten oder Hintergrunddiensten verarbeiten, müssen RunOCR in Task.Run einwickeln, um Anfragethreads nicht zu blockieren – und den Bild-ID-Lebenszyklus über die Thread-Grenze verwalten.IronOCR bietet durch ReadAsync erstklassige asynchrone Unterstützung.
GdPicture .NET -Ansatz:
using GdPicture14;
using System.Threading.Tasks;
public class GdPictureAsyncWrapper
{
private readonly GdPictureImaging _imaging;
private readonly GdPictureOCR _ocr;
private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
public async Task<string> ExtractTextAsync(string imagePath)
{
// Must acquire lock: GdPictureOCR is not thread-safe
await _lock.WaitAsync();
try
{
return await Task.Run(() =>
{
int imageId = _imaging.CreateGdPictureImageFromFile(imagePath);
if (imageId == 0)
throw new Exception($"Load failed: {_imaging.GetStat()}");
try
{
_ocr.SetImage(imageId);
_ocr.Language = "eng";
string resultId = _ocr.RunOCR();
if (string.IsNullOrEmpty(resultId))
throw new Exception($"OCR failed: {_ocr.GetStat()}");
return _ocr.GetOCRResultText(resultId);
}
finally
{
_imaging.ReleaseGdPictureImage(imageId);
}
});
}
finally
{
_lock.Release();
}
}
}
using GdPicture14;
using System.Threading.Tasks;
public class GdPictureAsyncWrapper
{
private readonly GdPictureImaging _imaging;
private readonly GdPictureOCR _ocr;
private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
public async Task<string> ExtractTextAsync(string imagePath)
{
// Must acquire lock: GdPictureOCR is not thread-safe
await _lock.WaitAsync();
try
{
return await Task.Run(() =>
{
int imageId = _imaging.CreateGdPictureImageFromFile(imagePath);
if (imageId == 0)
throw new Exception($"Load failed: {_imaging.GetStat()}");
try
{
_ocr.SetImage(imageId);
_ocr.Language = "eng";
string resultId = _ocr.RunOCR();
if (string.IsNullOrEmpty(resultId))
throw new Exception($"OCR failed: {_ocr.GetStat()}");
return _ocr.GetOCRResultText(resultId);
}
finally
{
_imaging.ReleaseGdPictureImage(imageId);
}
});
}
finally
{
_lock.Release();
}
}
}
Imports GdPicture14
Imports System.Threading.Tasks
Public Class GdPictureAsyncWrapper
Private ReadOnly _imaging As GdPictureImaging
Private ReadOnly _ocr As GdPictureOCR
Private ReadOnly _lock As New SemaphoreSlim(1, 1)
Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
' Must acquire lock: GdPictureOCR is not thread-safe
Await _lock.WaitAsync()
Try
Return Await Task.Run(Function()
Dim imageId As Integer = _imaging.CreateGdPictureImageFromFile(imagePath)
If imageId = 0 Then
Throw New Exception($"Load failed: {_imaging.GetStat()}")
End If
Try
_ocr.SetImage(imageId)
_ocr.Language = "eng"
Dim resultId As String = _ocr.RunOCR()
If String.IsNullOrEmpty(resultId) Then
Throw New Exception($"OCR failed: {_ocr.GetStat()}")
End If
Return _ocr.GetOCRResultText(resultId)
Finally
_imaging.ReleaseGdPictureImage(imageId)
End Try
End Function)
Finally
_lock.Release()
End Try
End Function
End Class
IronOCR Ansatz:
using IronOcr;
public class IronOcrAsyncService
{
private readonly IronTesseract _ocr = new IronTesseract();
public async Task<string> ExtractTextAsync(string imagePath)
{
// ReadAsync is natively async — no Task.Run wrapper, no lock required
var result = await _ocr.ReadAsync(imagePath);
return result.Text;
}
public async Task<string> ExtractFromStreamAsync(Stream stream)
{
using var input = new OcrInput();
input.LoadImage(stream);
var result = await _ocr.ReadAsync(input);
return result.Text;
}
}
using IronOcr;
public class IronOcrAsyncService
{
private readonly IronTesseract _ocr = new IronTesseract();
public async Task<string> ExtractTextAsync(string imagePath)
{
// ReadAsync is natively async — no Task.Run wrapper, no lock required
var result = await _ocr.ReadAsync(imagePath);
return result.Text;
}
public async Task<string> ExtractFromStreamAsync(Stream stream)
{
using var input = new OcrInput();
input.LoadImage(stream);
var result = await _ocr.ReadAsync(input);
return result.Text;
}
}
Imports IronOcr
Imports System.IO
Imports System.Threading.Tasks
Public Class IronOcrAsyncService
Private ReadOnly _ocr As New IronTesseract()
Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
' ReadAsync is natively async — no Task.Run wrapper, no lock required
Dim result = Await _ocr.ReadAsync(imagePath)
Return result.Text
End Function
Public Async Function ExtractFromStreamAsync(stream As Stream) As Task(Of String)
Using input As New OcrInput()
input.LoadImage(stream)
Dim result = Await _ocr.ReadAsync(input)
Return result.Text
End Using
End Function
End Class
Der GdPicture-Ansatz erfordert einen SemaphoreSlim, um den Zugriff auf die gemeinsame GdPictureOCR-Instanz zu serialisieren, plus einen Task.Run, um synchrone blockierende Arbeiten vom aufrufenden Thread abseits zu bewegen, plus den gesamten Bild-ID-Lebenszyklus innerhalb dieses Lambdas. IronOCRs ReadAsync ist wirklich nicht blockierend und threadsicher. Der Leitfaden zur asynchronen OCR behandelt die Integration mit ASP.NET Core Middleware und gehosteten Hintergrunddiensten.
Parallele Stapelverarbeitung mit Thread-Sicherheit
Die schnellstmögliche Verarbeitung eines Ordners mit gescannten Dokumenten erfordert eine parallele Ausführung. GdPicture erfordert eine GdPictureOCR-Instanz pro Thread – das Teilen einer einzigen Instanz verursacht nicht-deterministische Fehler. Jede thread-spezifische Instanz erfordert auch ihre eigene GdPictureImaging-Komponente und Ressourcenkonfiguration, was Thread-Pool-Ansätze ohne ein Fabrikmuster unpraktisch macht.
GdPicture .NET -Ansatz:
using GdPicture14;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class GdPictureParallelBatch
{
private readonly string _resourceFolder = @"C:\GdPicture\Resources\OCR";
public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
{
var results = new ConcurrentDictionary<string, string>();
// Each thread must have its own component instances
Parallel.ForEach(imagePaths, imagePath =>
{
// Create per-thread instances — shared instances cause failures
using var threadImaging = new GdPictureImaging();
using var threadOcr = new GdPictureOCR();
threadOcr.ResourceFolder = _resourceFolder;
// Re-register license per thread (may be required depending on SDK version)
var lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
int imageId = threadImaging.CreateGdPictureImageFromFile(imagePath);
if (imageId == 0)
{
results[imagePath] = $"ERROR: {threadImaging.GetStat()}";
return;
}
try
{
threadOcr.SetImage(imageId);
threadOcr.Language = "eng";
string resultId = threadOcr.RunOCR();
results[imagePath] = string.IsNullOrEmpty(resultId)
? $"ERROR: {threadOcr.GetStat()}"
: threadOcr.GetOCRResultText(resultId);
}
finally
{
threadImaging.ReleaseGdPictureImage(imageId);
}
});
return results;
}
}
using GdPicture14;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class GdPictureParallelBatch
{
private readonly string _resourceFolder = @"C:\GdPicture\Resources\OCR";
public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
{
var results = new ConcurrentDictionary<string, string>();
// Each thread must have its own component instances
Parallel.ForEach(imagePaths, imagePath =>
{
// Create per-thread instances — shared instances cause failures
using var threadImaging = new GdPictureImaging();
using var threadOcr = new GdPictureOCR();
threadOcr.ResourceFolder = _resourceFolder;
// Re-register license per thread (may be required depending on SDK version)
var lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
int imageId = threadImaging.CreateGdPictureImageFromFile(imagePath);
if (imageId == 0)
{
results[imagePath] = $"ERROR: {threadImaging.GetStat()}";
return;
}
try
{
threadOcr.SetImage(imageId);
threadOcr.Language = "eng";
string resultId = threadOcr.RunOCR();
results[imagePath] = string.IsNullOrEmpty(resultId)
? $"ERROR: {threadOcr.GetStat()}"
: threadOcr.GetOCRResultText(resultId);
}
finally
{
threadImaging.ReleaseGdPictureImage(imageId);
}
});
return results;
}
}
Imports GdPicture14
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
Public Class GdPictureParallelBatch
Private ReadOnly _resourceFolder As String = "C:\GdPicture\Resources\OCR"
Public Function ProcessBatch(imagePaths As String()) As ConcurrentDictionary(Of String, String)
Dim results As New ConcurrentDictionary(Of String, String)()
' Each thread must have its own component instances
Parallel.ForEach(imagePaths, Sub(imagePath)
' Create per-thread instances — shared instances cause failures
Using threadImaging As New GdPictureImaging()
Using threadOcr As New GdPictureOCR()
threadOcr.ResourceFolder = _resourceFolder
' Re-register license per thread (may be required depending on SDK version)
Dim lm As New LicenseManager()
lm.RegisterKEY("GDPICTURE-LICENSE-KEY")
Dim imageId As Integer = threadImaging.CreateGdPictureImageFromFile(imagePath)
If imageId = 0 Then
results(imagePath) = $"ERROR: {threadImaging.GetStat()}"
Return
End If
Try
threadOcr.SetImage(imageId)
threadOcr.Language = "eng"
Dim resultId As String = threadOcr.RunOCR()
results(imagePath) = If(String.IsNullOrEmpty(resultId), $"ERROR: {threadOcr.GetStat()}", threadOcr.GetOCRResultText(resultId))
Finally
threadImaging.ReleaseGdPictureImage(imageId)
End Try
End Using
End Using
End Sub)
Return results
End Function
End Class
IronOCR Ansatz:
using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class IronOcrParallelBatch
{
public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
{
var results = new ConcurrentDictionary<string, string>();
// IronTesseract is thread-safe — one instance handles all threads
var ocr = new IronTesseract();
Parallel.ForEach(imagePaths, imagePath =>
{
try
{
results[imagePath] = ocr.Read(imagePath).Text;
}
catch (Exception ex)
{
results[imagePath] = $"ERROR: {ex.Message}";
}
});
return results;
}
}
using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;
public class IronOcrParallelBatch
{
public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
{
var results = new ConcurrentDictionary<string, string>();
// IronTesseract is thread-safe — one instance handles all threads
var ocr = new IronTesseract();
Parallel.ForEach(imagePaths, imagePath =>
{
try
{
results[imagePath] = ocr.Read(imagePath).Text;
}
catch (Exception ex)
{
results[imagePath] = $"ERROR: {ex.Message}";
}
});
return results;
}
}
Imports IronOcr
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
Public Class IronOcrParallelBatch
Public Function ProcessBatch(imagePaths As String()) As ConcurrentDictionary(Of String, String)
Dim results As New ConcurrentDictionary(Of String, String)()
' IronTesseract is thread-safe — one instance handles all threads
Dim ocr As New IronTesseract()
Parallel.ForEach(imagePaths, Sub(imagePath)
Try
results(imagePath) = ocr.Read(imagePath).Text
Catch ex As Exception
results(imagePath) = $"ERROR: {ex.Message}"
End Try
End Sub)
Return results
End Function
End Class
Die parallele Implementierung von GdPicture erzeugt drei Objekte pro Thread und erfordert eine Lizenzregistrierung pro Thread.IronOCR verarbeitet gleichzeitige Lesezugriffe von einer einzigen IronTesseract Instanz ohne Synchronisationsaufwand. Das Multithreading-Beispiel zeigt Durchsatz-Benchmarks und Parallel.ForEach Muster für Hochvolumen-Dokumentverarbeitungs-Workloads.
Byte-Array-Eingabe und Extraktion strukturierter Absätze
Anwendungen, die Dokumente aus Datenbanken oder Objektspeichern abrufen, arbeiten oft mit Byte-Arrays anstatt mit Dateipfaden. GdPicture erfordert die Umwandlung des Byte-Arrays in einen Stream und das Laden über GdPictureImaging. Um strukturierte Daten auf Absatzebene aus dem Ergebnis zu extrahieren, muss die Block-/Zeilenindexhierarchie durchsucht werden.
GdPicture .NET -Ansatz:
using GdPicture14;
public class GdPictureByteArrayOcr
{
private readonly GdPictureImaging _imaging;
private readonly GdPictureOCR _ocr;
public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
{
var paragraphs = new List<string>();
// Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
using var ms = new MemoryStream(imageBytes);
int imageId = _imaging.CreateGdPictureImageFromStream(ms);
if (imageId == 0)
throw new Exception($"Byte array load failed: {_imaging.GetStat()}");
try
{
_ocr.SetImage(imageId);
_ocr.Language = "eng";
string resultId = _ocr.RunOCR();
if (string.IsNullOrEmpty(resultId))
throw new Exception($"OCR failed: {_ocr.GetStat()}");
// Paragraph-level data requires iterating block structure
int blockCount = _ocr.GetOCRResultBlockCount(resultId);
for (int b = 0; b < blockCount; b++)
{
var blockText = new StringBuilder();
int lineCount = _ocr.GetOCRResultBlockLineCount(resultId, b);
for (int l = 0; l < lineCount; l++)
{
int wordCount = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l);
for (int w = 0; w < wordCount; w++)
{
blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w));
blockText.Append(" ");
}
}
string text = blockText.ToString().Trim();
if (!string.IsNullOrEmpty(text))
paragraphs.Add(text);
}
}
finally
{
_imaging.ReleaseGdPictureImage(imageId);
}
return paragraphs;
}
}
using GdPicture14;
public class GdPictureByteArrayOcr
{
private readonly GdPictureImaging _imaging;
private readonly GdPictureOCR _ocr;
public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
{
var paragraphs = new List<string>();
// Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
using var ms = new MemoryStream(imageBytes);
int imageId = _imaging.CreateGdPictureImageFromStream(ms);
if (imageId == 0)
throw new Exception($"Byte array load failed: {_imaging.GetStat()}");
try
{
_ocr.SetImage(imageId);
_ocr.Language = "eng";
string resultId = _ocr.RunOCR();
if (string.IsNullOrEmpty(resultId))
throw new Exception($"OCR failed: {_ocr.GetStat()}");
// Paragraph-level data requires iterating block structure
int blockCount = _ocr.GetOCRResultBlockCount(resultId);
for (int b = 0; b < blockCount; b++)
{
var blockText = new StringBuilder();
int lineCount = _ocr.GetOCRResultBlockLineCount(resultId, b);
for (int l = 0; l < lineCount; l++)
{
int wordCount = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l);
for (int w = 0; w < wordCount; w++)
{
blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w));
blockText.Append(" ");
}
}
string text = blockText.ToString().Trim();
if (!string.IsNullOrEmpty(text))
paragraphs.Add(text);
}
}
finally
{
_imaging.ReleaseGdPictureImage(imageId);
}
return paragraphs;
}
}
Imports GdPicture14
Imports System.IO
Imports System.Text
Public Class GdPictureByteArrayOcr
Private ReadOnly _imaging As GdPictureImaging
Private ReadOnly _ocr As GdPictureOCR
Public Function ExtractParagraphsFromBytes(imageBytes As Byte()) As List(Of String)
Dim paragraphs As New List(Of String)()
' Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
Using ms As New MemoryStream(imageBytes)
Dim imageId As Integer = _imaging.CreateGdPictureImageFromStream(ms)
If imageId = 0 Then
Throw New Exception($"Byte array load failed: {_imaging.GetStat()}")
End If
Try
_ocr.SetImage(imageId)
_ocr.Language = "eng"
Dim resultId As String = _ocr.RunOCR()
If String.IsNullOrEmpty(resultId) Then
Throw New Exception($"OCR failed: {_ocr.GetStat()}")
End If
' Paragraph-level data requires iterating block structure
Dim blockCount As Integer = _ocr.GetOCRResultBlockCount(resultId)
For b As Integer = 0 To blockCount - 1
Dim blockText As New StringBuilder()
Dim lineCount As Integer = _ocr.GetOCRResultBlockLineCount(resultId, b)
For l As Integer = 0 To lineCount - 1
Dim wordCount As Integer = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l)
For w As Integer = 0 To wordCount - 1
blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w))
blockText.Append(" "c)
Next
Next
Dim text As String = blockText.ToString().Trim()
If Not String.IsNullOrEmpty(text) Then
paragraphs.Add(text)
End If
Next
Finally
_imaging.ReleaseGdPictureImage(imageId)
End Try
End Using
Return paragraphs
End Function
End Class
IronOCR Ansatz:
using IronOcr;
public class IronOcrByteArrayOcr
{
public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // byte array accepted directly
var result = new IronTesseract().Read(input);
// Paragraphs are a first-class typed collection
return result.Paragraphs
.Select(p => p.Text)
.Where(t => !string.IsNullOrWhiteSpace(t))
.ToList();
}
}
using IronOcr;
public class IronOcrByteArrayOcr
{
public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
{
using var input = new OcrInput();
input.LoadImage(imageBytes); // byte array accepted directly
var result = new IronTesseract().Read(input);
// Paragraphs are a first-class typed collection
return result.Paragraphs
.Select(p => p.Text)
.Where(t => !string.IsNullOrWhiteSpace(t))
.ToList();
}
}
Imports IronOcr
Public Class IronOcrByteArrayOcr
Public Function ExtractParagraphsFromBytes(imageBytes As Byte()) As List(Of String)
Using input As New OcrInput()
input.LoadImage(imageBytes) ' byte array accepted directly
Dim result = New IronTesseract().Read(input)
' Paragraphs are a first-class typed collection
Return result.Paragraphs _
.Select(Function(p) p.Text) _
.Where(Function(t) Not String.IsNullOrWhiteSpace(t)) _
.ToList()
End Using
End Function
End Class
IronOCR akzeptiert byte[] direkt auf LoadImage ohne das Zwischen-MemoryStream. Das Ergebnis offenbart .Paragraphs als typisierte LINQ-abfragbare Sammlung – kein Block-/Linien-/Wort-Dreifachverschachtelung erforderlich. Der Leitfaden zu den Leseergebnissen behandelt den Koordinatenzugriff, die Vertrauensfilterung und strukturierte Ausgabemuster für Workflows zur Rechnungs- und Formularverarbeitung. Informationen zum Scannen bestimmter Dokumentbereiche finden Sie unter regionenbasierter OCR .
GdPicture .NET API zu IronOCR Mapping-Referenz
| GdPicture.NET | IronOCR-Äquivalent |
|---|---|
using GdPicture14; |
using IronOcr; |
LicenseManager.RegisterKEY("key") |
IronOcr.License.LicenseKey = "key" |
new GdPictureImaging() |
Nicht erforderlich – intern zu OcrInput |
new GdPictureOCR() |
new IronTesseract() |
new GdPicturePDF() |
Nicht erforderlich – OcrInput.LoadPdf() behandelt dies |
_ocr.ResourceFolder = path |
Nicht erforderlich – Ressourcen sind in NuGet enthalten. |
imaging.CreateGdPictureImageFromFile(path) |
input.LoadImage(path) |
imaging.CreateGdPictureImageFromStream(stream) |
input.LoadImage(stream) |
imaging.CreateGdPictureImageFromBytes(bytes) |
input.LoadImage(bytes) |
imaging.CloneImage(tiffId) pro Rahmen |
input.LoadImageFrames(tiffPath) |
imaging.ReleaseGdPictureImage(imageId) |
using var input = new OcrInput() — automatisch |
ocr.SetImage(imageId) |
Nicht erforderlich — OcrInput hält das Bild. |
ocr.Language = "eng" |
ocr.Language = OcrLanguage.English |
ocr.RunOCR() → resultId Zeichenkette |
ocr.Read(input) → typisiert OcrResult |
ocr.GetOCRResultText(resultId) |
result.Text |
ocr.GetOCRResultConfidence(resultId) |
result.Confidence |
ocr.GetOCRResultBlockCount(resultId) |
result.Pages[i].Paragraphs.Count |
ocr.GetOCRResultBlockLineWordText(resultId, b, l, w) |
result.Words[i].Text |
imaging.GetStat() / ocr.GetStat() |
Standard .NET Ausnahmen |
GdPictureStatus.OK-Check nach jedem Anruf |
Nicht erforderlich – Ausnahmen werden weitergegeben |
pdf.OcrPage("eng", resourcePath, "", 200) |
result.SaveAsSearchablePdf(outputPath) |
pdf.RenderPageToGdPictureImage(200, false) |
Nicht erforderlich –IronOCR rendert intern. |
pdf.SelectPage(i) |
Nicht erforderlich – alle Seiten werden standardmäßig verarbeitet |
pdf.GetPageCount() |
result.Pages.Count |
Task.Run(() => ocr.RunOCR()) + SemaphoreSlim |
await ocr.ReadAsync(input) |
Gängige Migrationsprobleme und Lösungen
Problem 1: Bild-ID-Variablen verblieben nach Refactoring im Code.
GdPicture.NET: Bestehender Code erklärt int imageId oben in den Methoden, verfolgt es durch Try/Finally und übergibt es an mehrere GdPicture-Anrufe. Nach dem Ersetzen von GdPicture-Aufrufen werden diese Variablen und ihre ReleaseGdPictureImage-Aufrufe verwaister toter Code.
Lösung: Löschen Sie das gesamte Bild-ID-Muster. Ersetzen Sie die Deklaration, den try, den finally und den Freigabeaufruf durch einen using var input = new OcrInput()-Block. Suchen und Ersetzen für ReleaseGdPictureImage, um jeden Bereinigungsaufruf zu finden, der entfernt werden muss:
grep -rn "ReleaseGdPictureImage\|imageId\|resultId" --include="*.cs" .
grep -rn "ReleaseGdPictureImage\|imageId\|resultId" --include="*.cs" .
// Remove all of this
int imageId = _imaging.CreateGdPictureImageFromFile(path);
try
{
_ocr.SetImage(imageId);
string resultId = _ocr.RunOCR();
return _ocr.GetOCRResultText(resultId);
}
finally
{
_imaging.ReleaseGdPictureImage(imageId);
}
// Replace with
using var input = new OcrInput();
input.LoadImage(path);
return new IronTesseract().Read(input).Text;
// Remove all of this
int imageId = _imaging.CreateGdPictureImageFromFile(path);
try
{
_ocr.SetImage(imageId);
string resultId = _ocr.RunOCR();
return _ocr.GetOCRResultText(resultId);
}
finally
{
_imaging.ReleaseGdPictureImage(imageId);
}
// Replace with
using var input = new OcrInput();
input.LoadImage(path);
return new IronTesseract().Read(input).Text;
' Remove all of this
Dim imageId As Integer = _imaging.CreateGdPictureImageFromFile(path)
Try
_ocr.SetImage(imageId)
Dim resultId As String = _ocr.RunOCR()
Return _ocr.GetOCRResultText(resultId)
Finally
_imaging.ReleaseGdPictureImage(imageId)
End Try
' Replace with
Using input As New OcrInput()
input.LoadImage(path)
Return New IronTesseract().Read(input).Text
End Using
Problem 2: Ressourcenordnerpfad in der bereitgestellten Umgebung nicht gefunden
GdPicture.NET: Der im _ocr.ResourceFolder gesetzte Pfad wird auf der Entwicklungsmaschine aufgelöst, schlägt jedoch in der Produktion fehl. Häufige Symptome sind stille OCR-Fehler, die leere Ergebnisse zurückgeben, oder allgemeine GdPictureStatus-Fehler, die die fehlende Datei nicht benennen.
Lösung: Entfernen Sie die ResourceFolder-Zuordnung vollständig. Englische Unterstützung ist im IronOCR NuGet Paket integriert. Zusätzliche Sprachen werden als NuGet -Pakete installiert. Es gibt keinen Dateisystempfad zum Konfigurieren oder Bereitstellen:
# Remove the filesystem folder from deployment artifacts
# Add language NuGet packages to the project instead
:InstallCmd dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
# Remove the filesystem folder from deployment artifacts
# Add language NuGet packages to the project instead
:InstallCmd dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
Problem 3: Fehlerbehandlung für GdPictureStatus durch Ausnahmen ersetzt
GdPicture.NET: Jede Operation gibt oder setzt einen GdPictureStatus-Enum-Wert, der sofort überprüft werden muss. Der Code ist dicht mit if (status != GdPictureStatus.OK)-Schutzmaßnahmen. Einige Statuscodes sind generisch (z.B. Error, InvalidParameter) und erfordern es, die Dokumentation zu konsultieren, um die Ursache zu bestimmen.
Lösung:IronOCR löst typisierte .NET -Ausnahmen aus. Ersetzen Sie Statusprüfungen durch try/catch-Blöcke. Standard IOException und FileNotFoundException decken Eingabefehler ab; IronOcr.Exceptions.OcrException deckt OCR-spezifische Fehler ab. Empfohlene Fehlerbehandlungsmuster finden Sie im IronTesseract-Einrichtungsleitfaden :
try
{
var result = new IronTesseract().Read(imagePath);
return result.Text;
}
catch (FileNotFoundException ex)
{
_logger.LogError("Input file missing: {Path}", ex.FileName);
throw;
}
catch (IronOcr.Exceptions.OcrException ex)
{
_logger.LogError("OCR processing failed: {Message}", ex.Message);
throw;
}
try
{
var result = new IronTesseract().Read(imagePath);
return result.Text;
}
catch (FileNotFoundException ex)
{
_logger.LogError("Input file missing: {Path}", ex.FileName);
throw;
}
catch (IronOcr.Exceptions.OcrException ex)
{
_logger.LogError("OCR processing failed: {Message}", ex.Message);
throw;
}
Imports IronOcr
Imports System.IO
Try
Dim result = New IronTesseract().Read(imagePath)
Return result.Text
Catch ex As FileNotFoundException
_logger.LogError("Input file missing: {Path}", ex.FileName)
Throw
Catch ex As IronOcr.Exceptions.OcrException
_logger.LogError("OCR processing failed: {Message}", ex.Message)
Throw
End Try
Problem 4: GdPicture14 Namespace in mehreren Dateien
GdPicture.NET: Die Versionsnummer im Namespace bedeutet, dass es ein projektweites using GdPicture14;-Anweisung in Dutzenden von Dateien gibt. Nach der Migration müssen alle mit using IronOcr; ersetzt werden.
Lösung: Verwenden Sie ein globales Suchen-und-Ersetzen über alle .cs-Dateien und verifizieren Sie dann, dass keine GdPicture-Referenzen mehr übrig sind:
# Find all files with GdPicture namespace
grep -rln "using GdPicture" --include="*.cs" .
# After replacing, verify nothing remains
grep -rn "GdPicture14\|GdPictureOCR\|GdPictureImaging\|GdPicturePDF" --include="*.cs" .
# Find all files with GdPicture namespace
grep -rln "using GdPicture" --include="*.cs" .
# After replacing, verify nothing remains
grep -rn "GdPicture14\|GdPictureOCR\|GdPictureImaging\|GdPicturePDF" --include="*.cs" .
Ausgabe 5: Logik zur TIFF-Framezählung
GdPicture.NET: Code, der TIFF-Rahmen durchläuft, mischt oft Aufrufe über GdPictureImaging.GetPageCount(imageId) und GdPicturePDF.GetPageCount() hinweg, abhängig davon, wie die Datei geladen wurde. Der Frame-Index beginnt bei 1.
Lösung: input.LoadImageFrames(path) behandelt alle Rahmen automatisch. Wenn Ihr vorhandener Code nur spezifische Rahmen verarbeitet, verwenden Sie input.LoadImageFrames(path, frameNumbers) mit einem nullbasierten Index-Array. Zugriff auf pro-Rahmen-Ergebnisse über result.Pages, der auch nullbasiert ist. Das TIFF-Eingabehandbuch dokumentiert das Indexierungsverhalten explizit.
Problem 6: Vorverarbeitung erfordert das Dokumenten-Imaging-Plugin
GdPicture.NET: Deskew- und Despeckle-Operationen gehören zum GdPictureDocumentImaging Plugin, das einen separaten Lizenzerwerb erfordert. Teams, die das Plugin übersprungen haben, haben oft Probleme mit der OCR-Genauigkeit bei gescannten Dokumenten mit schiefen oder verrauschten Seiten.
Lösung: Die IronOCR Vorverarbeitungsmethoden sind Teil des Basispakets. Fügen Sie Deskew() und DeNoise() direkt auf OcrInput hinzu. Der Leitfaden zur Bildqualitätskorrektur deckt alle verfügbaren Filter einschließlich Contrast(), Sharpen(), Binarize() und DeepCleanBackgroundNoise() für stark verschlechterte Scans ab:
using var input = new OcrInput();
input.LoadImage("scanned-document.tiff");
input.Deskew(); // no separate plugin license
input.DeNoise();
input.Contrast();
var result = new IronTesseract().Read(input);
using var input = new OcrInput();
input.LoadImage("scanned-document.tiff");
input.Deskew(); // no separate plugin license
input.DeNoise();
input.Contrast();
var result = new IronTesseract().Read(input);
Imports IronOcr
Using input As New OcrInput()
input.LoadImage("scanned-document.tiff")
input.Deskew() ' no separate plugin license
input.DeNoise()
input.Contrast()
Dim result = New IronTesseract().Read(input)
End Using
GdPicture .NET Migrations-Checkliste
Vor der Migration
Prüfen Sie den Quellcode, um alle GdPicture-Abhängigkeiten zu ermitteln, bevor Sie Änderungen vornehmen:
# Find all GdPicture namespace imports
grep -rn "using GdPicture" --include="*.cs" .
# Find all image ID creation points
grep -rn "CreateGdPictureImageFromFile\|CreateGdPictureImageFromStream\|RenderPageToGdPictureImage\|CloneImage" --include="*.cs" .
# Find all release calls — these map to using block boundaries
grep -rn "ReleaseGdPictureImage" --include="*.cs" .
# Find all resource folder assignments
grep -rn "ResourceFolder" --include="*.cs" .
# Find all OCR result ID accesses
grep -rn "RunOCR\|GetOCRResult\|resultId" --include="*.cs" .
# Find all GdPictureStatus checks
grep -rn "GdPictureStatus\|GetStat()" --include="*.cs" .
# Count GdPicture-dependent files
grep -rln "GdPicture14" --include="*.cs" . | wc -l
# Find all GdPicture namespace imports
grep -rn "using GdPicture" --include="*.cs" .
# Find all image ID creation points
grep -rn "CreateGdPictureImageFromFile\|CreateGdPictureImageFromStream\|RenderPageToGdPictureImage\|CloneImage" --include="*.cs" .
# Find all release calls — these map to using block boundaries
grep -rn "ReleaseGdPictureImage" --include="*.cs" .
# Find all resource folder assignments
grep -rn "ResourceFolder" --include="*.cs" .
# Find all OCR result ID accesses
grep -rn "RunOCR\|GetOCRResult\|resultId" --include="*.cs" .
# Find all GdPictureStatus checks
grep -rn "GdPictureStatus\|GetStat()" --include="*.cs" .
# Count GdPicture-dependent files
grep -rln "GdPicture14" --include="*.cs" . | wc -l
Dokumentieren Sie Folgendes, bevor Sie den Code ändern:
- Welche Dateien enthalten
GdPictureImaging,GdPictureOCRundGdPicturePDF-Referenzen - Wie viele unterschiedliche Bild-ID-Erstellungs-/Veröffentlichungspaare gibt es?
- Ob das Document Imaging Plugin (Entzerren, Fleckenentfernen) verwendet wird
- Welche Sprach
traineddata-Dateien befinden sich im Ressourcenordner - Welche Bereitstellungsskripte oder Docker-Dateien verweisen auf den Ressourcenordnerpfad?
Code-Migration
- Entfernen Sie alle GdPicture NuGet Pakete aus der Projektdatei.
- Installieren Sie
IronOcrüber NuGet - Installieren Sie
IronOcr.Languages.*-Pakete für jede Sprache, die zuvor im Ressourcenordner war - Fügen Sie
IronOcr.License.LicenseKey = "..."zuProgram.csoderStartup.cshinzu - Entfernen Sie den
LicenseManager.RegisterKEY()-Aufruf und das Lizenzmanagerobjekt - Entfernen Sie alle
GdPictureImaging-Felderklärungen und Konstruktorinitialisierungen - Entfernen Sie alle
GdPictureOCRFelderklärungen und dieResourceFolder-Zuweisung - Entfernen Sie alle
GdPicturePDFFelderklärungen, die für OCR-Workflows verwendet werden - Ersetzen Sie jeden
int imageId = _imaging.CreateGdPictureImage*(...)-Block durchusing var input = new OcrInput();input.Load*(...) - Ersetzen Sie jedes
_ocr.SetImage(imageId); _ocr.Language = "..."; string resultId = _ocr.RunOCR();withvar result = new IronTesseract().Read(input); - Ersetzen Sie
_ocr.GetOCRResultText(resultId)durchresult.Text - Entfernen Sie alle
_imaging.ReleaseGdPictureImage(imageId)-Aufrufe - Ersetzen Sie
GdPictureStatus-Prüfungen durch try/catch-Blöcke - Ersetzen Sie TIFF-Rahmenschleifen durch
input.LoadImageFrames(path) - Ersetzen Sie
pdf.OcrPage(...)+pdf.SaveToFile(...)durchresult.SaveAsSearchablePdf(outputPath) - Entfernen Sie den Pfad zum Ressourcenordner aus den Bereitstellungsskripten und Docker-Images.
- Aktualisieren Sie
using GdPicture14;aufusing IronOcr;in allen betroffenen Dateien
Nach der Migration
Nachdem alle Codeänderungen abgeschlossen sind, überprüfen Sie bitte Folgendes, bevor Sie die Bereitstellung in der Produktionsumgebung durchführen:
- Einzelselbstbild-OCR gibt den erwarteten Text ohne
NullReferenceExceptionvon entfernten Komponenten zurück - Mehrseitige TIFF-Verarbeitung umfasst alle Rahmen und produziert pro-Seite-Text durch
result.PagesDie PDF-OCR verarbeitet alle Seiten ohne Speicherbedarf bei einem Stapel von über 50 Dokumenten. - Stream-Eingabe akzeptiert
MemoryStreamundFileStreamohne Zwischen-Dateischreibvorgänge - Asynchrone OCR integriert sich in ASP.NET Core Anforderungshandler, ohne den Threadpool zu blockieren.
- Parallele Batch-Verarbeitung mit
Parallel.ForEachliefert genaue Ergebnisse über alle Threads hinweg - Alle Sprachpakete (Französisch, Deutsch usw.) werden über NuGet Pakete korrekt aktiviert.
- Vorverarbeitungsfilter (Entzerren, Rauschen) verbessern die Genauigkeit gescannter Dokumente
- Durchsuchbare PDF-Dateien können von PDF-Readern und Textsuchanwendungen gelesen werden.
- Keine GdPicture-Namespaces-Verweise verbleiben in einer
.cs-Datei nach der Migration - Das Speicherprofil zeigt eine stabile Nutzung unter anhaltender Last (keine Speicherlecks bei Image-Zuweisungen).
- Die Bereitstellung auf Linux- und Docker-Systemen war erfolgreich, ohne dass Dateisystempfadfehler auftraten.
Wichtigste Vorteile der Migration zu IronOCR
Compilerseitig erzwungene Speichersicherheit. Der Image-ID-Lebenszyklus, den Entwickler bei GdPicture manuell verwalten mussten, entfällt vollständig. OcrInput implementiert IDisposable, und using-Blöcke erzwingen die Bereinigung am Ende jedes Bereichs – einschließlich Ausnahmepfade. Kein List<int> zu warten, keine finally-Blöcke zu erinnern, keine Produktivitätsvorfälle durch nicht freigegebene Aufrufe.
Ein einzelnes Paket für jedes OCR-Szenario. Bild-OCR, PDF-OCR, mehrseitige TIFF-Verarbeitung, durchsuchbare PDF-Erstellung, Vorverarbeitungsfilter, Barcode-Lesen und über 125 Sprachpakete sind alle aus dem IronOcr-NuGet-Paket und seinen Sprachbegleitern verfügbar. Es gibt keine Funktionsbarriere, die den Kauf einer zweiten oder dritten Lizenz erfordert, bevor ein gemeinsamer Arbeitsablauf möglich wird. Die vollständige Funktionsübersicht von IronOCR finden Sie hier.
Nativer Async und Thread-Sicherheit. ReadAsync ist eine echte asynchrone Methode, keine Task.Run-Verpackung. IronTesseract ist sicher, um über Threads ohne Synchronisation verwendet zu werden. Dokumentenverarbeitungsdienste, die zuvor eine thread-spezifische Komponenteninitialisierung und Semaphore-Serialisierung erforderten, reduzieren sich auf eine einzige geteilte Instanz mit Parallel.ForEach. Der Leitfaden zur asynchronen OCR behandelt sowohl ASP.NET Core als auch gehostete Dienstmuster.
Keine Konfiguration erforderlich.IronOCR benötigt weder Dateisystempfade noch externe Sprachdateien, native Binärverzeichnisse oder Bereitstellungsskripte. Der NuGet Wiederherstellungsschritt stellt alles bereit, was die Anwendung benötigt. Docker-Images, Azure App Service-Bereitstellungen und Linux-Server funktionieren alle identisch zur Entwicklungsumgebung. Die Docker-Bereitstellungsanleitung und die Azure-Bereitstellungsanleitung zeigen produktionsreife Konfigurationen.
Version-Stable Namespace. using IronOcr hat sich über Hauptversionen hinweg nicht geändert. Die Versionsnummern von NuGet regeln die Versionsverwaltung über das Standard-Paketverwaltungsmodell. Zukünftige größere Aktualisierungen erfordern keine codeweite Suche und Ersetzung des Namespace-Imports.
Vorhersehbare unbefristete Lizenzierung.IronOCR ist zu $999 (Lite), $1.499 (Plus), $2.999 (Professional) und $5.999 (Unlimited) erhältlich — einmalige unbefristete Käufe, die ein Jahr Updates beinhalten, mit optionaler jährlicher Erneuerung. Alle Funktionen sind in jeder Stufe verfügbar. Es gibt keine Plugins pro Funktion, keine Kosten pro Seite und keine Wartungsverpflichtung nach dem ersten Jahr. Teams, die zuvor über 8.000 US-Dollar für GdPicture-Plugin-Lizenzen für einen reinen OCR-Workflow aufgewendet haben, gleichen diese Lücke innerhalb des ersten Lizenzzyklus aus. Die vollständigen Preisinformationen finden Sie auf der IronOCR Lizenzseite .
Häufig gestellte Fragen
Warum sollte ich von GdPicture.NET OCR 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 GdPicture.NET OCR zu IronOCR?
Ersetzen Sie die Initialisierungssequenzen von GdPicture.NET durch die Instanziierung von IronTesseract, entfernen Sie das COM-Lebenszyklusmanagement (explizite Create/Load/Close-Muster) und aktualisieren Sie die Namen der Ergebniseigenschaften. Das Ergebnis ist eine deutliche Verringerung der Anzahl von 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 GdPicture.NET OCR 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 GdPicture.NET OCR 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 GdPicture.NET OCR zu IronOCR Änderungen an der Bereitstellungsinfrastruktur?
IronOCR erfordert weniger Änderungen an der Infrastruktur als GdPicture.NET OCR. Es gibt keine SDK-Binärpfade, keine Platzierung von Lizenzdateien oder Lizenzserverkonfigurationen. Das NuGet-Paket enthält die komplette OCR-Engine, und der Lizenzschlüssel ist eine im Anwendungscode festgelegte Zeichenfolge.
Wie konfiguriere ich die IronOCR-Lizenzierung nach der Migration?
Weisen Sie IronOcr.License.LicenseKey = "YOUR-KEY" im Startup-Code der Anwendung zu. In Docker oder Kubernetes speichern Sie den Schlüssel als Umgebungsvariable und lesen ihn beim Starten aus. Verwenden Sie License.IsValidLicense zur Validierung, bevor Sie den Datenverkehr akzeptieren.
Kann IronOCR PDFs auf die gleiche Weise verarbeiten wie GdPicture.NET?
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 Arbeitslasten berechenbarer als die von GdPicture.NET OCR?
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 GdPicture.NET OCR 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.

