Comment extraire du texte arabe à partir d'images à l'aide d'outils OCR
Ce guide accompagne les développeurs .NET tout au long d'une migration complète de GdPicture .NET OCR vers IronOCR . Il couvre l'échange de packages, les modifications d'espace de noms et les modèles de code pratiques avant/après pour chaque flux de travail OCR majeur, en mettant l'accent sur l'élimination du cycle de vie de l'identifiant d'image entier qui définit le modèle de gestion des ressources de GdPicture. Aucune lecture préalable de l'article comparatif n'est requise.
Pourquoi migrer depuis GdPicture .NET ?
GdPicture .NET est une plateforme d'imagerie documentaire conçue pour les équipes ayant besoin d'une intégration de scanner, de la prise en charge DICOM, de l'édition de PDF, de l'annotation et de la reconnaissance optique de caractères (OCR) auprès d'un fournisseur unique. Lorsque la reconnaissance optique de caractères (OCR) est la seule exigence, la tarification et l'architecture API de la plateforme créent des frictions qui s'accumulent au fil du temps.
Coût des plugins pour un flux de travail OCR de base. L'extraction de texte à partir de PDF numérisés et la production d'un résultat interrogeable nécessitent trois licences distinctes : le kit de développement logiciel (SDK) principal à environ 4 000 $, le plugin OCR à environ 2 000 $ et le plugin PDF à environ 2 000 $. Cela représente un coût initial de 8 000 $, Plus 20 % de frais de maintenance annuels. Les équipes qui n'ont besoin que de la reconnaissance optique de caractères (OCR) absorbent l'intégralité de la structure tarifaire d'une plateforme d'imagerie documentaire. IronOCR couvre le même flux de travail — OCR d'image, OCR de PDF, prétraitement, sortie PDF interrogeable — depuis un seul package à $999 jusqu'à 2 999 $ perpétuels, sans décisions de licence par fonctionnalité. Consultez la page des licences IronOCR pour obtenir le détail complet des différents niveaux.
Le cycle de vie de l'ID image entier. Chaque image chargée via GdPicture retourne un int. Vous transmettez cet entier aux opérations OCR, puis appelez ReleaseGdPictureImage avec celui-ci lorsque terminé. Ce schéma précède IDisposable. Cela fonctionne si on suit les instructions correctement ; Cela provoque une fuite de mémoire en cas d'échec. Dans les services de production traitant des centaines de documents par jour, un seul appel de libération manqué sur une branche d'erreur entraîne une augmentation de la consommation de mémoire véritablement difficile à diagnostiquer. Le OcrInput d'IronOCR implémente IDisposable — une déclaration using élimine toute la charge de nettoyage.
Espace de noms spécifique à la version. GdPicture intègre le numéro de version majeure dans son espace de noms : using GdPicture14. La mise à niveau vers la prochaine version majeure nécessite la mise à jour de cette directive using dans chaque fichier source qui fait référence aux classes GdPicture. Une application de grande envergure avec une reconnaissance optique de caractères (OCR) répartie sur des dizaines de services transforme cette tâche de recherche et de remplacement en une opération de plusieurs heures sans aucune amélioration fonctionnelle. L'espace de noms d'IronOCR a été IronOcr à travers toutes les versions majeures.
Exigence de dossier de ressources externes. L'OCR de GdPicture nécessite une propriété ResourceFolder pointant vers un répertoire de fichiers de langue .traineddata à l'exécution. Ce chemin fonctionne sur une machine de développement, puis casse sur les serveurs Linux, les conteneurs Docker, et les déploiements de Azure App Service où la structure du répertoire n'existe pas. IronOCR regroupe la prise en charge de la langue anglaise dans le package NuGet; Les langues supplémentaires s'installent sous forme de packages NuGet qui sont inclus dans le résultat de la compilation.
Initialisation à trois composants. Un flux de travail OCR de PDF dans GdPicture nécessite d'instancier GdPictureImaging, GdPictureOCR, et GdPicturePDF — trois composants distincts avec des exigences de suppression individuelles — plus l'enregistrement du gestionnaire de licence et l'affectation du dossier de ressources. IronOCR nécessite une ligne au démarrage et une classe lors de l'appel.
Aucune sécurité multithread native. Les instances OCR de GdPicture ne sont pas compatibles avec le multithreading. Le traitement parallèle des documents nécessite une gestion et une synchronisation rigoureuses des instances afin d'éviter toute corruption d'état. IronOCR est conçu pour une utilisation simultanée : créez un IronTesseract par thread, ou partagez une seule instance sous charge — chaque schéma fonctionne sans code de synchronisation supplémentaire.
Le problème fondamental
GdPicture alloue de la mémoire pour chaque image sous forme de descripteur entier géré à l'exécution. Chaque appel RenderPageToGdPictureImage dans une boucle de traitement TIFF crée une nouvelle allocation qui doit être libérée manuellement :
// 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 élimine complètement le cycle de vie. OcrInput gère l'énumération et le nettoyage des frames :
// 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: Comparaison des fonctionnalités
Le tableau ci-dessous compare les fonctionnalités des deux bibliothèques pour les flux de travail axés sur la reconnaissance optique de caractères (OCR).
| Fonction | GdPicture.NET | IronOCR |
|---|---|---|
| Installation | Plusieurs packages NuGet | dotnet add package IronOcr |
| Activation de la licence | LicenseManager.RegisterKEY() |
IronOcr.License.LicenseKey = "..." |
| Espace de noms lors de la mise à niveau majeure | Nécessite de trouver-remplacer (GdPicture14 → suivant) |
Inchangé (IronOcr) |
| Initialisation des composants | GdPictureImaging + GdPictureOCR + GdPicturePDF |
new IronTesseract() |
| Modèle de mémoire de ressources | Suivi et publication manuels des identifiants numériques | IDisposable / using statement |
| risque de fuite de mémoire | Élevée (manquant ReleaseGdPictureImage) |
Aucun (imposé par le compilateur via using) |
| dossier de ressources externes | Requis (_ocr.ResourceFolder = path) |
Non requis — inclus dans l'emballage |
| OCR d'image | Oui | Oui |
| OCR PDF | Oui (plugin PDF requis) | Intégré, aucune licence supplémentaire |
| TIFF multipage | Boucle d'images manuelle + nettoyage des ID par image | input.LoadImageFrames() |
| Entrée du flux | Via GdPictureImaging surcharge de flux |
input.LoadImage(stream) |
| Sortie PDF consultable | pdf.OcrPage() + pdf.SaveToFile() |
result.SaveAsSearchablePdf() |
| Prétraitement de la correction de la courbure | Module d'imagerie de documents requis | input.Deskew() — intégré |
| suppression du bruit | Module d'imagerie de documents requis | input.DeNoise() — intégré |
| Langues | Fichiers de données entraînées basés sur Tesseract dans le dossier | Plus de 125 packages NuGet |
| OCR multilingue | Oui | OcrLanguage.French + OcrLanguage.German |
| Sécurité des threads | Gestion manuelle des instances | Sécurité des threads dès la conception |
| OCR asynchrone | Non intégré | ReadAsync() |
| Lecture de codes-barres | Module de code-barres séparé | ocr.Configuration.ReadBarCodes = true |
| Sortie structurée | Accès par bloc/ligne/mot basé sur l'index | Typé .Pages, .Words, .Characters |
| Score de confiance | GetOCRResultConfidence(resultId) |
result.Confidence |
| Multiplateforme | Windows, Linux, macOS | Windows, Linux, macOS, Docker, AWS, Azure |
| Coût d'entrée (OCR à partir de PDF) | Environ 8 000 $ (modules de base + OCR + plugins PDF) | $999–2 999 $ |
| Modèle de tarification | Licence perpétuelle basée sur un plugin + 20 %/an de maintenance | Forfait perpétuel, mises à jour annuelles facultatives |
| soutien commercial | Oui | Oui |
Démarrage rapide : Migration de GdPicture .NET vers IronOCR
Étape 1 : Remplacer le package NuGet
Supprimez les paquets GdPicture :
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
Installez IronOCR depuis la page du package NuGet :
dotnet add package IronOcr
Pour les langues autres que l'anglais, installez le pack de langue correspondant :
dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
Étape 2 : Mise à jour des espaces de noms
Remplacez l'espace de noms GdPicture par l'espace de noms IronOCR :
// Before (GdPicture)
using GdPicture14;
// After (IronOCR)
using IronOcr;
// Before (GdPicture)
using GdPicture14;
// After (IronOCR)
using IronOcr;
Imports IronOcr
Étape 3 : initialisation de la licence
Placez cette ligne dans Program.cs ou Startup.cs, avant tout appel OCR :
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Supprimez complètement le bloc d'enregistrement de licence GdPicture :
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
Une clé d'essai gratuite est disponible sur la page produit IronOCR pour évaluer le produit avant l'achat.
Exemples de migration de code
Traitement d'images TIFF multipages
Le traitement des fichiers TIFF multipages dans GdPicture nécessite la sélection de chaque image via l'API PDF/imagerie, son rendu en un nouvel identifiant d'image, l'exécution de la reconnaissance optique de caractères (OCR) et la libération de l'identifiant. Un seul cadre qui n'est pas libéré dans le bloc finally fuit entre 10 et 50 Mo selon le DPI.
Approche GdPicture .NET :
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
Approche IronOCR :
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 charge chaque cadre d'un TIFF multipages dans le pipeline OcrInput. Le bloc using gère toute la mémoire associée à chaque cadre en fin de portée. Aucun List<int> à maintenir, pas de blocs try/finally imbriqués requis. Le guide d'entrée TIFF et GIF couvre en détail la sélection des images et la gestion multiformat.
Initialisation du plugin de remplacement d'entrée basé sur le flux
Les applications serveur reçoivent fréquemment des documents sous forme de flux plutôt que de chemins de fichiers, provenant de téléchargements HTTP, de files d'attente de messages ou de données binaires de base de données. GdPicture nécessite le chargement du flux via GdPictureImaging, qui lui-même nécessite la séquence d'initialisation du composant et la configuration du dossier de ressources qui précèdent chaque opération.
Approche GdPicture .NET :
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
Approche IronOCR :
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
L'approche GdPicture nécessite la construction de trois objets et la configuration d'un chemin d'accès au système de fichiers avant que le premier flux puisse être consommé. IronOCR accepte le flux directement sur OcrInput sans configuration préalable. Le guide d'entrée des flux couvre les tableaux d'octets, MemoryStream, et les modèles FileStream pour les architectures de pipeline où les écritures de fichiers temporaires sont indésirables.
OCR asynchrone remplaçant l'interrogation du code d'état
La reconnaissance optique de caractères (OCR) de GdPicture est synchrone. Les applications qui traitent des documents dans les points de terminaison ASP.NET Core ou les services d'arrière-plan doivent envelopper RunOCR dans Task.Run pour éviter de bloquer les threads de requête — et ensuite gérer le cycle de vie de l'ID image à travers la limite du thread. IronOCR offre un support asynchrone de premier ordre via ReadAsync.
Approche GdPicture .NET :
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
Approche IronOCR :
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
L'approche GdPicture requiert un SemaphoreSlim pour sérialiser l'accès à l'instance partagée GdPictureOCR, plus un Task.Run pour déplacer le travail de blocage synchrone du thread appelant, plus le cycle de vie complet de l'ID image à l'intérieur de ce lambda. Le ReadAsync d'IronOCR est vraiment non-bloquant et thread-safe. Le guide OCR asynchrone traite de l'intégration avec les intergiciels ASP.NET Core et les services d'arrière-plan hébergés.
Traitement par lots parallèle avec sécurité des fils
Le traitement le plus rapide possible d'un dossier de documents numérisés nécessite une exécution parallèle. GdPicture nécessite une instance GdPictureOCR par thread — partager une seule instance entraîne des échecs non déterministes. Chaque instance par thread nécessite également son propre composant GdPictureImaging et la configuration du dossier de ressources, rendant les approches avec pool de threads impraticables sans un modèle de fabrique.
Approche GdPicture .NET :
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
Approche IronOCR :
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
L'implémentation parallèle de GdPicture crée trois objets par thread et nécessite un enregistrement de licence par thread. IronOCR gère les lectures concurrentes à partir d'une seule instance IronTesseract sans surcharge de synchronisation. L'exemple de multithreading démontre des benchmarks de débit et des schémas Parallel.ForEach pour les charges de travail de traitement de documents à haut volume.
Saisie de tableaux d'octets et extraction de paragraphes structurés
Les applications qui récupèrent des documents à partir de bases de données ou de systèmes de stockage d'objets fonctionnent souvent avec des tableaux d'octets plutôt qu'avec des chemins de fichiers. GdPicture nécessite la conversion du tableau d'octets en un flux et son chargement via GdPictureImaging. L'extraction de données structurées au niveau du paragraphe à partir du résultat nécessite de naviguer dans la hiérarchie d'index des blocs/lignes.
Approche GdPicture .NET :
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
Approche IronOCR :
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 accepte byte[] directement sur LoadImage sans l'intermédiaire MemoryStream. Le résultat expose .Paragraphs comme une collection typée interrogeable LINQ — aucune triple-boucle bloc/ligne/mot requise. Le guide des résultats de lecture couvre l'accès coordonné, le filtrage de confiance et les modèles de sortie structurés pour les flux de travail de traitement des factures et des formulaires. Pour numériser des zones spécifiques d'un document, voir la reconnaissance optique de caractères (OCR) basée sur les régions .
Référence de mappage de l'API .NET de GdPicture vers IronOCR
| GdPicture.NET | Équivalent d'IronOCR |
|---|---|
using GdPicture14; |
using IronOcr; |
LicenseManager.RegisterKEY("key") |
IronOcr.License.LicenseKey = "key" |
new GdPictureImaging() |
Non requis — interne à OcrInput |
new GdPictureOCR() |
new IronTesseract() |
new GdPicturePDF() |
Non requis — OcrInput.LoadPdf() gère cela |
_ocr.ResourceFolder = path |
Non requis — ressources incluses dans NuGet |
imaging.CreateGdPictureImageFromFile(path) |
input.LoadImage(path) |
imaging.CreateGdPictureImageFromStream(stream) |
input.LoadImage(stream) |
imaging.CreateGdPictureImageFromBytes(bytes) |
input.LoadImage(bytes) |
imaging.CloneImage(tiffId) par cadre |
input.LoadImageFrames(tiffPath) |
imaging.ReleaseGdPictureImage(imageId) |
using var input = new OcrInput() — automatique |
ocr.SetImage(imageId) |
Non requis — OcrInput détient l'image |
ocr.Language = "eng" |
ocr.Language = OcrLanguage.English |
ocr.RunOCR() → chaîne resultId |
ocr.Read(input) → typé 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() |
Exceptions .NET Standard |
GdPictureStatus.OK vérifie après chaque appel |
Non requis — les exceptions se propagent |
pdf.OcrPage("eng", resourcePath, "", 200) |
result.SaveAsSearchablePdf(outputPath) |
pdf.RenderPageToGdPictureImage(200, false) |
Non requis — IronOCR effectue le rendu en interne |
pdf.SelectPage(i) |
Non requis — toutes les pages sont traitées par défaut |
pdf.GetPageCount() |
result.Pages.Count |
Task.Run(() => ocr.RunOCR()) + SemaphoreSlim |
await ocr.ReadAsync(input) |
Problèmes de migration courants et solutions
Problème n° 1 : Variables d'identification d'image restantes dans le code après la refactorisation
GdPicture.NET: Le code existant déclare int imageId en haut des méthodes, le suit via try/finally, et le passe à plusieurs appels GdPicture. Après le remplacement des appels GdPicture, ces variables et leurs appels ReleaseGdPictureImage deviennent du code mort orphelin.
Solution : Supprimez l'intégralité du modèle d'identification de l'image. Remplacez la déclaration, le try, le finally, et l'appel de suppression par un bloc using var input = new OcrInput(). Grep pour ReleaseGdPictureImage pour trouver chaque appel de nettoyage qui doit être supprimé :
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
Problème 2 : Chemin du dossier de ressources introuvable dans l'environnement déployé
GdPicture.NET: Le chemin défini dans _ocr.ResourceFolder se résout sur la machine de développement mais échoue en production. Les symptômes courants sont des échecs OCR silencieux retournant des résultats vides, ou des erreurs génériques GdPictureStatus qui ne nomment pas le fichier manquant.
Solution : Supprimez entièrement l'assignation ResourceFolder. La prise en charge de l'anglais est intégrée au package NuGet IronOCR . Les langues supplémentaires s'installent sous forme de packages NuGet . Aucun chemin de système de fichiers n'est disponible pour la configuration ou le déploiement :
# 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
Problème 3 : La gestion des erreurs GdPictureStatus est remplacée par des exceptions
GdPicture.NET: Chaque opération retourne ou définit une valeur d'énum GdPictureStatus qui doit être vérifiée immédiatement. Le code est dense avec des gardes if (status != GdPictureStatus.OK). Certains codes d'état sont génériques (par ex., Error, InvalidParameter) et nécessitent de consulter la documentation pour déterminer la cause première.
Solution : IronOCR génère des exceptions .NET typées. Remplacez les contrôles d'état par des blocs try/catch. Les standards IOException et FileNotFoundException couvrent les échecs d'entrée ; IronOcr.Exceptions.OcrException couvre les erreurs spécifiques à l'OCR. Consultez le guide d'installation d'IronTesseract pour connaître les modèles de gestion des erreurs recommandés :
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
Problème 4 : Espace de noms GdPicture14 dans plusieurs fichiers
GdPicture.NET: Le numéro de version dans l'espace de noms signifie qu'une directive using GdPicture14; à l'échelle du projet existe dans des dizaines de fichiers. Après la migration, ceux-ci doivent tous être remplacés par using IronOcr;.
Solution : Utilisez une recherche et remplacement global dans tous les fichiers .cs, puis vérifiez qu'aucune référence GdPicture ne subsiste :
# 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" .
Problème 5 : Logique de comptage des images TIFF
GdPicture.NET: Le code qui itère les frames TIFF mélange souvent les appels entre GdPictureImaging.GetPageCount(imageId) et GdPicturePDF.GetPageCount() selon la façon dont le fichier a été chargé. L'index des trames commence à 1.
Solution : input.LoadImageFrames(path) gère automatiquement tous les frames. Si votre code existant ne traite que des frames spécifiques, utilisez input.LoadImageFrames(path, frameNumbers) avec un tableau d'index à partir de zéro. Accédez aux résultats par cadre via result.Pages, qui est également indexé à partir de zéro. Le guide d'entrée TIFF documente explicitement le comportement de l'index.
Problème n° 6 : Le prétraitement nécessite le plugin d'imagerie de documents
GdPicture.NET: Les opérations de redressement et de suppression de taches appartiennent au plugin GdPictureDocumentImaging, qui nécessite un achat de licence supplémentaire. Les équipes qui n'ont pas utilisé le plugin rencontrent souvent des problèmes de précision de reconnaissance optique de caractères (OCR) sur les documents numérisés dont les pages sont déformées ou présentent des artefacts.
Solution : Les méthodes de prétraitement IronOCR font partie du package de base. Ajoutez Deskew() et DeNoise() directement sur OcrInput. Le guide de correction de la qualité d'image couvre tous les filtres disponibles, y compris Contrast(), Sharpen(), Binarize(), et DeepCleanBackgroundNoise() pour les scans sévèrement dégradés :
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
Liste de contrôle de migration GdPicture .NET
Pré-migration
Avant d'apporter des modifications, auditez le code source afin de localiser toutes les dépendances de GdPicture :
# 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
Documentez les éléments suivants avant de modifier le code :
- Quels fichiers contiennent des références
GdPictureImaging,GdPictureOCR, etGdPicturePDFCombien existe-t-il de paires distinctes d'identifiants de création/publication d'images ? - Si le plugin d'imagerie de documents (redressement, débruitage) est utilisé
- Quels fichiers de langue
traineddatasont dans le dossier de ressources - Quels scripts de déploiement ou fichiers Docker font référence au chemin du dossier de ressources
Migration de code
- Supprimez tous les packages NuGet GdPicture du fichier projet.
- Installez
IronOcrvia NuGet - Installez des packages
IronOcr.Languages.*pour chaque langue précédemment dans le dossier de ressources - Ajoutez
IronOcr.License.LicenseKey = "..."àProgram.csouStartup.cs - Supprimez l'appel
LicenseManager.RegisterKEY()et l'objet du gestionnaire de licence - Supprimez toutes les déclarations de champ
GdPictureImaginget l'initialisation du constructeur - Supprimez toutes les déclarations de champ
GdPictureOCRet l'assignationResourceFolder - Supprimez toutes les déclarations de champ
GdPicturePDFutilisées pour les flux de travail OCR - Replace each
int imageId = _imaging.CreateGdPictureImage*(...)block with `using var input = new OcrInput(); input.Load*(...) - Remplacez chaque
_ocr.SetImage(imageId); _ocr.Language = "..."; string resultId = _ocr.RunOCR();withvar result = new IronTesseract().Read(input); - Remplacez
_ocr.GetOCRResultText(resultId)parresult.Text - Supprimez tous les appels
_imaging.ReleaseGdPictureImage(imageId) - Remplacez les vérifications
GdPictureStatuspar des blocs try/catch - Remplacez les boucles de cadres TIFF par
input.LoadImageFrames(path) - Remplacez
pdf.OcrPage(...)+pdf.SaveToFile(...)parresult.SaveAsSearchablePdf(outputPath) - Supprimez le chemin d'accès au dossier de ressources des scripts de déploiement et des images Docker.
- Mettez à jour
using GdPicture14;versusing IronOcr;dans tous les fichiers concernés
Après la migration
Après avoir effectué toutes les modifications de code, vérifiez les points suivants avant le déploiement en production :
- L'OCR d'image unique retourne le texte attendu sans
NullReferenceExceptiondes composants supprimés - Le traitement multipages TIFF couvre tous les frames et produit du texte par page via
result.Pages - La reconnaissance optique de caractères (OCR) des fichiers PDF traite toutes les pages sans augmentation de la mémoire nécessaire pour un lot de plus de 50 documents.
- L'entrée de flux accepte
MemoryStreametFileStreamsans écritures de fichiers intermédiaires - La reconnaissance optique de caractères asynchrone s'intègre aux gestionnaires de requêtes ASP.NET Core sans bloquer le pool de threads.
- Le traitement par lots parallèle avec
Parallel.ForEachproduit des résultats précis sur tous les threads - Tous les modules linguistiques (français, allemand, etc.) s'activent correctement via les packages NuGet
- Les filtres de prétraitement (redressement, débruitage) améliorent la précision des documents numérisés
- Le fichier PDF indexable est lisible par les visionneuses PDF et les applications de recherche textuelle.
- Aucune référence d'espace de noms GdPicture ne subsiste dans tout fichier
.csaprès migration - Le profil mémoire indique une utilisation stable sous charge soutenue (aucune fuite d'allocation d'images).
- Le déploiement réussit sur les cibles Linux et Docker sans erreurs de chemin d'accès au système de fichiers
Principaux avantages de la migration vers IronOCR
Sécurité mémoire assurée par le compilateur. Le cycle de vie des identifiants d'image que GdPicture exige des développeurs qu'ils gèrent manuellement disparaît entièrement. OcrInput implémente IDisposable, et les blocs using imposent un nettoyage à la fin de chaque portée — y compris les chemins d'exception. Aucun List<int> à maintenir, pas de blocs finally à se souvenir, aucun incident de mémoire en production provenant d'appels de libération manqués.
Un seul package pour tous les scénarios OCR. L'OCR d'image, l'OCR de PDF, le traitement multipages TIFF, la génération de PDF interrogeable, les filtres de prétraitement, la lecture de codes-barres, et plus de 125 packs linguistiques sont tous disponibles à partir du package NuGet IronOcr et de ses compagnons linguistiques. Il n'existe aucune condition d'accès aux fonctionnalités qui exige l'achat d'une deuxième ou d'une troisième licence avant qu'un flux de travail courant ne devienne possible. Consultez la présentation des fonctionnalités IronOCR pour obtenir la liste complète des capacités.
Async natif et sécurité des threads. ReadAsync est une méthode async authentique, pas un wrapper Task.Run. IronTesseract est sûr à utiliser à travers les threads sans synchronisation. Les services de traitement de documents qui nécessitaient précédemment l'initialisation de composants par thread et la sérialisation des sémaphores se réduisent à une seule instance partagée avec Parallel.ForEach. Le guide OCR asynchrone couvre à la fois les modèles ASP.NET Core et les services hébergés.
Configuration de déploiement nulle. IronOCR ne nécessite aucun chemin de système de fichiers, aucun fichier de langue externe, aucun emplacement binaire natif ni aucun script de déploiement. L'étape de restauration NuGet fournit tout ce dont l'application a besoin. Les images Docker, les déploiements Azure App Service et les serveurs Linux fonctionnent de manière identique à la machine de développement. Les guides de déploiement Docker et Azure présentent des configurations prêtes pour la production.
Espace de noms stable en version. using IronOcr n'a pas changé à travers les versions majeures. Les numéros de version NuGet gèrent le versionnage via le modèle standard de gestion des packages. Les futures mises à jour majeures ne nécessiteront pas une opération de recherche et de remplacement à l'échelle du code source de l'importation de l'espace de noms.
Licences perpétuelles prévisibles. IronOCR est proposé à $999 (Lite), 1 499 $ (Plus), 2 999 $ (Professional), et 5 999 $ (Unlimited) — achats perpétuels uniques qui incluent un an de mises à jour, avec un renouvellement facultatif annuel. Toutes les fonctionnalités sont disponibles à tous les niveaux. Il n'y a pas de plugins par fonctionnalité, pas de frais par page et aucune obligation de maintenance après la première année. Les équipes qui avaient auparavant dépensé plus de 8 000 $ en licences de plugins GdPicture pour un flux de travail basé uniquement sur la reconnaissance optique de caractères (OCR) récupèrent ce montant dès le premier cycle de licence. Les détails complets des tarifs sont disponibles sur la page de licences IronOCR .
Questions Fréquemment Posées
Pourquoi devrais-je migrer de GdPicture.NET OCR vers IronOCR ?
Parmi les motivations communes, citons l'élimination de la complexité de l'interopérabilité COM, le remplacement de la gestion des licences basée sur les fichiers, l'absence de facturation à la page, l'activation du déploiement Docker/conteneur et l'adoption d'un flux de travail NuGet-natif qui s'intègre à l'outillage .NET standard.
Quels sont les principaux changements de code lors de la migration de GdPicture.NET OCR vers IronOCOCR ?
Remplacer les séquences d'initialisation de GdPicture.NET par l'instanciation d'IronTesseract, supprimer la gestion du cycle de vie de COM (modèles explicites Create/Load/Close) et mettre à jour les noms des propriétés des résultats. Le résultat est une réduction significative du nombre de lignes de code.
Comment installer IronOCR pour commencer la migration ?
Exécutez "Install-Package IronOcr" dans la console du Package Manager ou "dotnet add package IronOcr" dans le CLI. Les packs de langues sont des paquets distincts : 'dotnet add package IronOcr.Languages.French' pour le français, par exemple.
IronOCR atteint-il la précision de l'OCR de GdPicture.NET pour les documents commerciaux standard ?
IronOcr atteint un niveau de précision élevé pour les contenus commerciaux standard, notamment les factures, les contrats, les reçus et les formulaires dactylographiés. Les filtres de prétraitement d'image (désalignement, suppression du bruit, amélioration du contraste) améliorent encore la reconnaissance sur des données dégradées.
Comment IronOCR gère-t-il les données linguistiques que GdPicture.NET OCR installe séparément ?
Les données linguistiques de l'IronOcr sont distribuées sous forme de packages NuGet. 'dotnet add package IronOcr.Languages.German' installe la prise en charge de l'allemand. Il n'y a pas de placement manuel de fichiers ou de chemins d'accès aux répertoires.
La migration de GdPicture.NET OCR vers IronOCR nécessite-t-elle des changements au niveau de l'infrastructure de déploiement ?
IronOCR nécessite moins de changements d'infrastructure que GdPicture.NET OCR. Il n'y a pas de chemins binaires SDK, de placements de fichiers de licence ou de configurations de serveurs de licence. Le package NuGet contient le moteur OCR complet, et la clé de licence est une chaîne de caractères définie dans le code de l'application.
Comment configurer les licences IronOCR après la migration ?
Attribuer IronOcr.License.LicenseKey = "YOUR-KEY" dans le code de démarrage de l'application. Dans Docker ou Kubernetes, stockez la clé dans une variable d'environnement et lisez-la au démarrage. Utilisez License.IsValidLicense pour valider avant d'accepter le trafic.
IronOCR peut-il traiter les PDF de la même manière que GdPicture.NET ?
Oui, IronOCR lit aussi bien les PDF natifs que les PDF numérisés. Instanciez IronTesseract, appelez ocr.Read(input) où l'input est un chemin PDF ou OcrPdfInput, et itérez les pages OcrResult. Aucun pipeline de rendu PDF séparé n'est nécessaire.
Comment IronOcr gère-t-il le threading dans le cadre d'un traitement à haut volume ?
IronTesseract est sûr pour l'instanciation par thread. Créez une instance par thread dans un Parallel.ForEach ou un Task pool, exécutez l'OCR simultanément et disposez de chaque instance lorsque vous avez terminé. Aucun état global ou verrouillage n'est nécessaire.
Quels formats de sortie IronOCR prend-il en charge après l'extraction du texte ?
IronOCR renvoie des résultats structurés comprenant le texte, les coordonnées des mots, les scores de confiance et la structure des pages. Les options d'exportation comprennent le texte brut, le PDF interrogeable et les objets de résultats structurés pour le traitement en aval.
La tarification d'IronOCR est-elle plus prévisible que celle de GdPicture.NET OCR pour la mise à l'échelle des charges de travail ?
IronOCR utilise des licences perpétuelles forfaitaires sans frais par page ou par volume. Que vous traitiez 10 000 ou 10 millions de pages, le coût de la licence reste constant. Les options de licence en volume et en équipe sont disponibles sur la page de tarification d'IronOcr.
Qu'advient-il de mes tests existants après la migration de GdPicture.NET OCR vers IronOCOCR ?
Les tests qui vérifient le contenu du texte extrait doivent continuer à passer après la migration. Les tests qui valident les modèles d'appel d'API ou le cycle de vie des objets COM devront être mis à jour pour refléter le modèle d'initialisation et de résultat plus simple d'IronOcr.

