Passer au contenu du pied de page
VIDéOS

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
SHELL

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
$vbLabelText   $csharpLabel

É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"
$vbLabelText   $csharpLabel

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");
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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" .
SHELL
// 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
$vbLabelText   $csharpLabel

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
SHELL

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
$vbLabelText   $csharpLabel

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" .
SHELL

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
$vbLabelText   $csharpLabel

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
SHELL

Documentez les éléments suivants avant de modifier le code :

  • Quels fichiers contiennent des références GdPictureImaging, GdPictureOCR, et GdPicturePDF Combien 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 traineddata sont 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

  1. Supprimez tous les packages NuGet GdPicture du fichier projet.
  2. Installez IronOcr via NuGet
  3. Installez des packages IronOcr.Languages.* pour chaque langue précédemment dans le dossier de ressources
  4. Ajoutez IronOcr.License.LicenseKey = "..." à Program.cs ou Startup.cs
  5. Supprimez l'appel LicenseManager.RegisterKEY() et l'objet du gestionnaire de licence
  6. Supprimez toutes les déclarations de champ GdPictureImaging et l'initialisation du constructeur
  7. Supprimez toutes les déclarations de champ GdPictureOCR et l'assignation ResourceFolder
  8. Supprimez toutes les déclarations de champ GdPicturePDF utilisées pour les flux de travail OCR
  9. Replace each int imageId = _imaging.CreateGdPictureImage*(...) block with `using var input = new OcrInput(); input.Load*(...)
  10. Remplacez chaque _ocr.SetImage(imageId); _ocr.Language = &quot;...&quot;; string resultId = _ocr.RunOCR(); with var result = new IronTesseract().Read(input);
  11. Remplacez _ocr.GetOCRResultText(resultId) par result.Text
  12. Supprimez tous les appels _imaging.ReleaseGdPictureImage(imageId)
  13. Remplacez les vérifications GdPictureStatus par des blocs try/catch
  14. Remplacez les boucles de cadres TIFF par input.LoadImageFrames(path)
  15. Remplacez pdf.OcrPage(...) + pdf.SaveToFile(...) par result.SaveAsSearchablePdf(outputPath)
  16. Supprimez le chemin d'accès au dossier de ressources des scripts de déploiement et des images Docker.
  17. Mettez à jour using GdPicture14; vers using 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 NullReferenceException des 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 MemoryStream et FileStream sans é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.ForEach produit 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 .cs aprè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 .

Veuillez noterGdPicture.NET et Tesseract sont des marques déposées de leurs propriétaires respectifs. Ce site n'est ni affilié à, ni approuvé par, ni sponsorisé par Google, Nutrient, ou ORPALIS. Tous les noms de produits, logos et marques sont la propriété de leurs propriétaires respectifs. Les comparaisons sont à titre informatif uniquement et reflètent les informations publiquement disponibles au moment de l'écriture.

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.

Kannaopat Udonpant
Ingénieur logiciel
Avant de devenir ingénieur logiciel, Kannapat a obtenu un doctorat en ressources environnementales à l'université d'Hokkaido au Japon. Pendant qu'il poursuivait son diplôme, Kannapat est également devenu membre du laboratoire de robotique de véhicules, qui fait partie du département de bioproduction. En 2022, il a utilisé ses compé...
Lire la suite

Équipe de soutien Iron

Nous sommes en ligne 24 heures sur 24, 5 jours sur 7.
Chat
Email
Appelez-moi