Passer au contenu du pied de page
VIDéOS

Migration d'ABBYY FineReader vers IronOcr

Ce guide accompagne les développeurs .NET à chaque étape du remplacement du kit de développement logiciel Moteur ABBYY FineReader par IronOCR . Il décrit les étapes mécaniques de la suppression des dépendances COM et des artefacts d'installation du SDK, établit une correspondance entre l'API d'ABBYY et ses équivalents IronOCR , et fournit des exemples de code avant/après pour les modèles les plus fréquemment rencontrés dans les intégrations ABBYY en production. Les cibles de migration sont les équipes qui ont décidé que le coût d'entreprise et la complexité de déploiement d'ABBYY ne s'alignent plus avec leurs exigences de projet.

Pourquoi migrer depuis ABBYY FineReader ?

ABBYY FineReader Engine est une plateforme OCR performante, mais son architecture a été conçue pour les Enterprise Windows disposant d'équipes d'infrastructure dédiées. Lorsque la charge de travail réelle d'une équipe .NET consiste à traiter des factures, à numériser des contrats ou à extraire des formulaires scannés, cette architecture devient un handicap plutôt qu'un atout.

La dette d'interopérabilité COM s'accumule avec le temps. Chaque intégration ABBYY dans .NET passe par une couche d'interopérabilité COM. Les objets COM nécessitent une gestion explicite du cycle de vie : créer, initialiser, traiter, puis fermer dans un bloc finally ou le processus fuit de la mémoire. Chaque chemin de code qui touche ABBYY présente ce modèle. Sur deux ou trois ans d'ajouts de fonctionnalités, cette cérémonie de cycle de vie se propage à travers les classes de services, les processus en arrière-plan et les gestionnaires de requêtes. Le résultat est de 30 à 50 % de code standard dans chaque classe liée à l'OCR qui disparaît complètement lorsque vous passez à IronTesseract.

Le programme d'installation du SDK bloque les modèles de déploiement modernes. ABBYY déploie ses produits via un programme d'installation de SDK Windows qui place les fichiers binaires, les données de langue, les fichiers d'exécution et les fichiers de licence dans des chemins d'accès codés en dur. La containerisation d'un service qui utilise ABBYY nécessite soit de créer une image de base personnalisée de plus de 300 Mo à partir de la sortie de cet installateur, soit de monter des volumes avec des fichiers de licence au démarrage. Aucune des approches ne convient à un pipeline Kubernetes standard ou cloud-native. IronOCR est un package NuGet : le même dotnet restore qui télécharge toutes les autres dépendances télécharge le moteur OCR complet.

La facturation à la page transforme le volume en centre de coûts. Les modèles de licences d'ABBYY basés sur le volume facturent chaque page traitée au-delà des seuils inclus. Une application qui traite 50 000 documents par mois à son lancement et qui atteint 500 000 deux ans plus tard voit ses coûts OCR augmenter proportionnellement à son succès. IronOCR facture un tarif fixe pour la licence : une équipe traitant deux millions de pages par mois paie exactement le même coût de licence qu'une équipe en traitant deux mille.

Les données linguistiques nécessitent une coordination manuelle du déploiement. Les modules linguistiques ABBYY sont stockés sous forme de fichiers dans le répertoire d'exécution du SDK. L'ajout d'une langue implique d'identifier les fichiers de données appropriés, de les copier au bon emplacement sur chaque cible de déploiement et de mettre à jour les scripts CI/CD pour les inclure. Sur IronOCR, ajouter le français est dotnet add package IronOcr.Languages.French — le gestionnaire de packages s'occupe du reste.

Les échecs des fichiers de licence touchent la production sans avertissement. Les licences ABBYY existent sous forme de fichiers .lic et .key qui doivent être présents à des chemins de disque spécifiques lorsque loader.GetEngineObject() s'exécute. Si ces fichiers sont manquants sur un nouveau serveur de production (script de déploiement erroné, copie de fichiers ayant échoué, problème d'autorisations), l'appel génère une erreur au démarrage. Une licence expirée provoque la même erreur. La licence de IronOCR est une clé de chaîne attribuée dans le code au démarrage, stockable dans n'importe quel gestionnaire de secrets, avec une vérification effectuée par IronOcr.License.IsValidLicense avant que l'application n'accepte le trafic.

La sécurité des threads nécessite une instance unique de moteur partagé. Le moteur d'ABBYY n'est pas trivialement sécurisé pour les appels CreateFRDocument concurrents depuis plusieurs threads. Les implémentations en production utilisent des stratégies de verrouillage ou des pools de processeurs. Le IronTesseract de IronOCR est sans état : lancez une instance par thread, exécutez la reconnaissance simultanément sans verrous, disposez lorsque c'est terminé.

Le problème fondamental

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

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

Comparaison des fonctionnalités IronOCR et d'ABBYY FineReader

Le tableau suivant récapitule les fonctionnalités pertinentes pour les équipes évaluant cette migration.

Fonction Moteur ABBYY FineReader IronOCR
Installation Programme d'installation du SDK (Windows) dotnet add package IronOcr
Acquisition Contactez le service commercial (4 à 12 semaines) NuGet en libre-service
Modèle de licence Enterprise, par serveur ou par page Perpétuelle, $999-2,999 une fois
Gestion des licences .lic + fichiers .key sur le disque Clé de chaîne dans le code ou variable d'environnement
Intégration .NET Interopérabilité COM Natif .NET
Dépendance COM Oui Non
Sécurité des threads Nécessite une stratégie de verrouillage Complet (un IronTesseract par thread)
Langues prises en charge 190+ 125+
Installation de la langue Fichiers de données d'exécution au chemin du SDK packages de langage NuGet
Entrée PDF Oui (via CreatePDFFile) Oui (natif, input.LoadPdf())
Sortie PDF consultable Oui (pipeline d'exportation) Oui (result.SaveAsSearchablePdf())
Prétraitement automatique Basé sur le profil Intégré (Correction de l'inclinaison du bureau, Réduction du bruit, Contraste, Binarisation, Netteté)
OCR basé sur la région Objets de zone (CreateZone, SetBounds) Paramètre CropRectangle
Lecture de codes-barres Oui Oui (ocr.Configuration.ReadBarCodes = true)
Cross-Platform Windows, Linux, macOS Windows, Linux, macOS, Docker, Azure, AWS
Déploiement Docker Image de base personnalisée requise Image de base standard .NET + libgdiplus
Évaluation de la confiance Oui Oui (result.Confidence)
Délai d'obtention du premier résultat OCR 4 à 12 semaines (passation de commande) Le même jour

Démarrage rapide : Migration d'ABBYY FineReader vers IronOCR

Étape 1 : Remplacer le package NuGet

ABBYY FineReader Engine ne possède pas de package NuGet . Supprimez-le en désinstallant le SDK et en supprimant la référence d'assemblage manuel de votre fichier projet :


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

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

Ensuite, supprimez la référence d'interopérabilité COM FREngine.dll du nœud des Références de Visual Studio, ou supprimez l'entrée correspondante directement de votre fichier de projet. Installez IronOCR depuis NuGet :

dotnet add package IronOcr

Étape 2 : Mise à jour des espaces de noms

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

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

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

Étape 3 : initialisation de la licence

Ajoutez ceci une seule fois au démarrage de l'application, avant tout appel OCR :

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

Stockez la clé dans une variable d'environnement ou un gestionnaire de secrets pour les déploiements en production :

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

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

Exemples de migration de code

Cycle de vie du moteur dans un service Windows vs IronTesseract sans état

La cérémonie d'initialisation du moteur d'ABBYY appartient à un wrapper de service parce que les objets EngineLoader et IEngine sont coûteux à créer. La plupart des intégrations en production encapsulent le moteur dans un service singleton avec des méthodes de démarrage et de destruction explicites.

Approche ABBYY FineReader :

using FREngine;

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

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // Step 1: Create loader — requires Interopérabilité COM registration
        var loader = new EngineLoader();

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

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

        return Task.CompletedTask;
    }

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

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

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

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

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // Step 1: Create loader — requires Interopérabilité COM registration
        var loader = new EngineLoader();

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

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

        return Task.CompletedTask;
    }

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

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

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

Public Class DocumentOcrService
    Implements IHostedService, IDisposable

    Private _engine As IEngine

    Public Function StartAsync(cancellationToken As CancellationToken) As Task Implements IHostedService.StartAsync
        ' Step 1: Create loader — requires Interopérabilité COM registration
        Dim loader As New EngineLoader()

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

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

        Return Task.CompletedTask
    End Function

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

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

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

Approche IronOCR :

using IronOcr;

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

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

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

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

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

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

IronTesseract n'a pas de cycle de vie du moteur. Il s'initialise en interne lors de sa première utilisation et ne nécessite aucun arrêt explicite. Le wrapper de service hébergé, le champ IEngine et les méthodes StopAsync disparaissent tous. Si l'application traite des documents simultanément, chaque thread crée sa propre instance IronTesseract — aucun verrouillage requis. Le guide d'installation IronTesseract couvre les options de configuration y compris les propriétés TesseractVersion et Configuration.

Configuration de la langue de reconnaissance

La configuration linguistique ABBYY implique la création d'un objet LanguageParams, l'ajout de chaînes de noms de langage qui doivent correspondre aux fichiers de données installés, et l'association de ces paramètres au moteur avant que tout document ne soit traité. Chaque langue supplémentaire nécessite les fichiers de données correspondants déployés dans le chemin d'exécution.

Approche ABBYY FineReader :

using FREngine;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Approche IronOCR :

using IronOcr;

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

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

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

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

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

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

Les packs de langues s'installent comme des packages NuGet standard (dotnet add package IronOcr.Languages.French). Aucun fichier de données à déployer manuellement, aucune configuration de chemin, aucune réinitialisation du moteur lors du changement de langue. Le guide multilingue explique comment combiner les langues, et l' index des langues répertorie tous les plus de 125 packs disponibles.

Traitement TIFF multi-images

ABBYY traite les fichiers TIFF multipages en itérant sur les images et en ajoutant chaque image comme une page de document distincte. Le nombre d'images doit être récupéré à partir de l'objet TIFF, puis chaque image est ajoutée individuellement au conteneur du document.

Approche ABBYY FineReader :

using FREngine;

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

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

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

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

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

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

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

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

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

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

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

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

Approche IronOCR :

using IronOcr;

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

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

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

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

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

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

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

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

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

OcrInput.LoadImageFrames lit chaque trame dans un TIFF multi-page sans itération manuelle. Le résultat offre un accès par page via result.Pages, y compris le texte, les données de coordonnées et la confiance par trame. Le guide d'entrée TIFF couvre à la fois la gestion des fichiers TIFF multi-images et des GIF animés.

Traitement par lots parallèle

Le moteur basé sur COM d'ABBYY n'est pas sûr à appeler CreateFRDocument de façon concurrente à partir de plusieurs threads sans stratégie de synchronisation. Les processeurs de traitement par lots en production maintiennent généralement un pool d'instances de moteur ou sérialisent l'accès via un verrou. Chacune de ces approches ajoute une infrastructure IronOCR élimine.

Approche ABBYY FineReader :

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

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

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

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

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

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

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

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

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

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

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

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

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

Approche IronOCR :

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

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

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

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

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

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

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

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

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

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

Chaque instance IronTesseract est indépendante. Parallel.ForEach sature les cœurs CPU disponibles sans aucun état partagé, verroux ou sérialisation. La version ABBYY traite les documents de manière séquentielle malgré le wrapper asynchrone ; La version IronOCR les traite véritablement en parallèle. L' exemple de multithreading illustre ce modèle par des comparaisons de temps d'exécution. Pour un contrôle du débit de niveau supérieur, consultez le guide d'optimisation de la vitesse .

Pipeline d'exportation de documents

ABBYY prend en charge plusieurs formats d'exportation via sa méthode Export avec des valeurs FileExportFormatEnum. L'exportation vers DOCX, RTF ou texte brut nécessite la création d'objets de paramètres d'exportation spécifiques au format, puis l'appel de document.Export avec la valeur enum appropriée et l'objet de paramètres.

Approche ABBYY FineReader :

using FREngine;

public class AbbyyExporter
{
    private IEngine _engine;

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

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

            string baseName = Path.GetFileNameWithoutExtension(imagePath);

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

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

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

public class AbbyyExporter
{
    private IEngine _engine;

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

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

            string baseName = Path.GetFileNameWithoutExtension(imagePath);

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

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

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

Public Class AbbyyExporter
    Private _engine As IEngine

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

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

            Dim baseName As String = Path.GetFileNameWithoutExtension(imagePath)

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

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

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

Approche IronOCR :

using IronOcr;

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

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

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

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

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

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

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

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

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

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

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

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

Le OcrResult d'IronOCR expose directement .Text et fournit des méthodes de sortie sans objets de paramètres ni enums de format. L'appel SaveAsSearchablePdf gère l'exportation PDF en une seule ligne contre la séquence de trois étapes de paramètres/exportation d'ABBYY. Le guide PDF consultable couvre les options de plage de pages et les paramètres de compression. Le guide d'exportation hOCR couvre le format HOCR pour les systèmes qui consomment une sortie OCR prenant en compte la position.

Référence de mappage de l'API ABBYY FineReader vers IronOCR

Moteur ABBYY FineReader Équivalent d'IronOCR
new EngineLoader() Non requis
loader.GetEngineObject(sdkPath, licensePath) new IronTesseract()
engine.LoadPredefinedProfile("...") Non requis (traité en interne)
engine.CreateLanguageParams() Non requis
langParams.Languages.Add("French") ocr.Language = OcrLanguage.French
langParams.Languages.Add("English") + langParams.Languages.Add("German") ocr.Language = OcrLanguage.English + OcrLanguage.German
engine.CreateFRDocument() new OcrInput()
engine.CreateFRDocumentFromImage(path, null) ocr.Read(path)
document.AddImageFile(path, null, null) input.LoadImage(path)
imageInfo.LoadImageFile(tiff) + boucle frameCount input.LoadImageFrames(tiff)
engine.CreatePDFFile() puis pdfFile.Open(path, null, null) input.LoadPdf(path)
document.Process(null) ocr.Read(input)
document.PlainText.Text result.Text
frDocument.Pages[i].PlainText.Text result.Pages[i].Text
page.Layout.Blocks + contrôle BlockTypeEnum.BT_Table result.Pages + données de coordonnées de mots
block.GetAsTableBlock() result.Pages[i].Lines (avec coordonnées)
engine.CreatePDFExportParams() Non requis
document.Export(path, FEF_PDF, params) result.SaveAsSearchablePdf(path)
document.Export(path, FEF_TextUnicodeDefaults, null) File.WriteAllText(path, result.Text)
engine.CreateDOCXExportParams() + Exportation Non directement pris en charge
document.Close() Géré par using sur OcrInput
_engine.GetLicenseInfo().ExpirationDate IronOcr.License.IsValidLicense
Fichiers de licence (ABBYY.lic, ABBYY.key) IronOcr.License.LicenseKey = "key"
engine.CreateZone() + zone.SetBounds(x, y, w, h) new CropRectangle(x, y, width, height)

Problèmes de migration courants et solutions

Problème 1 : Erreurs d'enregistrement COM après la suppression du SDK

ABBYY : Après avoir retiré FREngine.dll des références du projet, la construction peut toujours échouer avec Could not load type 'FREngine.EngineLoader' ou des erreurs d'interopérabilité COM provenant des classes qui ont conservé l'ancien espace de noms.

Solution : Recherchez toutes les utilisations de FREngine et ABBYY.FineReader avant de retirer la référence. Toute classe qui implémente IDisposable spécifiquement pour annuler un champ IEngine a besoin de remplacer sa logique de disposition par des blocs using sur OcrInput :

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

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

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



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

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

Problème n° 2 : Le profil de reconnaissance n'a pas d'équivalent

ABBYY : Le code qui appelle engine.LoadPredefinedProfile("DocumentConversion_Speed") ou engine.LoadPredefinedProfile("FieldLevelRecognition") utilise des profils spécifiques à ABBYY pour équilibrer la précision contre le débit. Il n'existe pas de propriété équivalente dans IronOCR nommée Profile.

Solution : IronOCR expose les mêmes compromis via IronTesseract.Configuration. Pour optimiser la vitesse, définissez ocr.Configuration.TesseractVersion = TesseractVersion.Tesseract5 (défaut) et réduisez les filtres de prétraitement. Pour une précision maximale, ajoutez le pipeline de prétraitement complet :

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

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

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

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

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

Le guide de correction de la qualité d'image explique quels filtres permettent de résoudre quels problèmes de qualité d'image. Le guide d'optimisation de la vitesse décrit les propriétés de configuration qui réduisent le temps de traitement des documents propres.

Problème 3 : L'étape de déploiement du fichier de licence reste dans l'intégration continue/le déploiement continu (CI/CD).

ABBYY : Les pipelines de construction contiennent généralement une étape qui copie ABBYY.lic et ABBYY.key d'un magasin sécurisé vers la cible de déploiement. Après la migration, il arrive que les équipes oublient de supprimer cette étape, laissant ainsi du code de déploiement inactif qui référence des chemins d'accès qui n'existent plus.

Solution : Supprimez complètement l'étape de copie du fichier de licence. Remplacez-la par une étape d'injection de variable d'environnement :

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

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

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

Et au démarrage de l'application :

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

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

Problème 4 : Moteur non sécurisé pour les threads — Code de verrouillage existant

ABBYY : Les applications qui appellent ABBYY depuis plusieurs threads contiennent généralement SemaphoreSlim, des instructions lock, ou des instances de moteur locales au thread pour éviter les problèmes de threading COM. Ce code de synchronisation est spécifique au modèle de threads d'ABBYY.

Solution : Supprimez tout le code de synchronisation encapsulant les appels ABBYY. Le IronTesseract d'IronOCR est sûr à instancier par thread :

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

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

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

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

Problème 5 : Modèle CreateImageInfo / FrameCount pour TIFF

ABBYY : Le code qui lit les nombres de trames à partir de fichiers TIFF en utilisant engine.CreateImageInfo() et imageInfo.LoadImageFile() avant de boucler à travers les trames n'a pas d'équivalent direct dans IronOCR car OcrInput.LoadImageFrames gère l'énumération des trames en interne.

Solution : Supprimer complètement la boucle de comptage d'images :

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

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

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

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

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

Problème n°6 : L'exportation DOCX n'a pas d'équivalent direct

ABBYY : document.Export(path, FileExportFormatEnum.FEF_DOCX, docxParams) produit un document Word. IronOCR ne produit pas directement de fichiers DOCX.

Solution : IronOCR produit des PDF consultables et des données textuelles structurées. Pour les flux de travail nécessitant une sortie DOCX, la voie de migration pratique consiste à produire un PDF consultable et à le convertir en aval, ou à extraire le texte structuré et à l'écrire dans un fichier DOCX à l'aide d'une bibliothèque telle que Open XML SDK :

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

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

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

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

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

Le guide des résultats de lecture explique comment accéder aux paragraphes, aux lignes, aux mots et aux données de coordonnées au niveau des caractères pour un traitement ultérieur.

Liste de vérification pour la migration d'ABBYY FineReader

Tâches préalables à la migration

Vérifiez le code source avant d'apporter toute modification :

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

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

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

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

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

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

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

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

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

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

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

Documentez chaque classe qui contient un champ IEngine ou IFRDocument. Notez les formats d'exportation utilisés : la sortie DOCX nécessite une approche alternative (voir le problème 6 ci-dessus).

Tâches de mise à jour du code

  1. Retirez la référence FREngine.dll de tous les fichiers .csproj
  2. Exécutez dotnet add package IronOcr dans chaque projet qui utilisait ABBYY
  3. Ajoutez IronOcr.License.LicenseKey = ... au démarrage de l'application (Program.cs ou classe de démarrage)
  4. Installez les packages de langue NuGet pour chaque langue non anglaise (dotnet add package IronOcr.Languages.French, etc.)
  5. Supprimez tous les appels EngineLoader, GetEngineObject, et LoadPredefinedProfile
  6. Supprimez tous les appels CreateLanguageParams et langParams.Languages.Add
  7. Remplacez engine.CreateFRDocument() + document.AddImageFile() + document.Process() par new IronTesseract().Read(path)
  8. Remplacez les boucles TIFF multi-trames par input.LoadImageFrames(tiffPath)
  9. Remplacez document.PlainText.Text par result.Text
  10. Remplacez frDocument.Pages[i].PlainText.Text par result.Pages[i].Text
  11. Remplacez document.Export(..., FEF_PDF, pdfParams) par result.SaveAsSearchablePdf(path)
  12. Remplacez tous les appels document.Close() par des blocs using sur OcrInput
  13. Supprimez SemaphoreSlim et le code de verrouillage qui sérialisait l'accès au moteur ABBYY
  14. Remplacez engine.CreateZone() / zone.SetBounds() / page.Zones.Add() par new CropRectangle(x, y, width, height) passé à input.LoadImage()
  15. Supprimer les étapes de copie des fichiers de licence des pipelines CI/CD
  16. Mettez à jour les images Docker — supprimez la couche d'installation SDK, ajoutez libgdiplus pour les cibles Linux

Test de post-migration

  • Vérifier le résultat de l'extraction de texte sur un échantillon représentatif de chaque type de document (factures, contrats, formulaires numérisés).
  • Vérifier que le traitement TIFF multipage renvoie le même nombre de pages que les images produites par ABBYY
  • Tester les documents multilingues avec les mêmes données d'entrée que celles utilisées pour la comparaison de référence ABBYY.
  • Vérifier que le fichier PDF interrogeable est bien interrogeable dans Adobe Reader et les visionneuses PDF des navigateurs.
  • Exécutez le processeur de traitement par lots parallèle avec le niveau de concurrence de production et vérifiez qu'aucune exception n'est constatée.
  • Vérifiez result.Confidence sur des documents de bonne qualité connus pour établir un seuil de référence pour les portes de qualité
  • Tester l'initialisation de la clé de licence à partir d'une variable d'environnement dans l'environnement de déploiement de préproduction
  • Vérifier que l'image Docker se construit et exécute l'OCR sans le montage de volume du SDK ABBYY
  • Vérifier que le pipeline CI/CD s'exécute correctement sans l'étape de copie du fichier de licence.
  • Exécutez un profileur de mémoire sur le processeur en lot pour confirmer qu'aucun objet OcrInput n'est en fuite (vérifiez le placement using)

Principaux avantages de la migration vers IronOCR

La complexité du déploiement est considérablement réduite. Chaque déploiement ABBYY nécessitait l'installation du SDK, le placement du fichier de licence, la configuration du chemin d'exécution et la vérification que les fichiers se trouvaient aux bons emplacements avant le démarrage de l'application. IronOCR se déploie en tant que dépendance NuGet . dotnet publish produit un artefact autonome avec le moteur OCR inclus. Le guide de déploiement Docker et le guide d'installation Azure présentent la configuration complète ; les deux tiennent sur une seule page.

L'interopérabilité COM a disparu. Le retrait de la couche COM élimine une catégorie entière de défaillances au moment de l'exécution : erreurs d'enregistrement COM sur les nouvelles machines, incompatibilités de threading par appartement, bogues de cycle de vie RCW, et les 15 à 25 lignes de boilerplate try/finally que chaque appel de traitement de document ABBYY nécessitait. La base de code se réduit. La surface d'erreur se réduit en conséquence.

L'augmentation du volume de documents ne justifie plus de révision budgétaire. La licence perpétuelle d'IronOCR couvre un volume de documents illimité. Une application traitant 10 000 documents par mois la première année et 2 000 000 par mois la troisième année conserve le même coût de licence OCR. Il n'y a ni facturation au nombre de pages traitées, ni facturation supplémentaire, ni renégociation des paliers de volume. La page des licences affiche tous les niveaux — la licence Professional à 2 999 $ couvre dix développeurs traitant n'importe quel volume sur n'importe quel nombre de cibles de déploiement.

Le déploiement multiplateforme ouvre de nouvelles perspectives en matière d'infrastructure. La couche COM d'ABBYY nécessite Windows. Les équipes qui souhaitaient transférer le traitement des documents vers des conteneurs Linux pour des raisons de coût ou de densité ont été bloquées. IronOCR fonctionne de manière identique sous Windows, Linux et macOS à partir du même package NuGet . La migration depuis ABBYY supprime la contrainte Windows de la couche OCR de la pile applicative. Le guide de déploiement Linux et le guide de déploiement AWS couvrent la configuration complète de chaque environnement.

Le débit parallèle est disponible sans travaux d'infrastructure. Les stratégies de verrouillage qui sérialisaient l'accès au moteur ABBYY ont disparu. Les instances IronTesseract sont indépendantes : lancez-en une par thread, exécutez Parallel.ForEach sur un lot de documents, obtenez les résultats. Le débit s'adapte au nombre de cœurs de processeur disponibles sans aucun code supplémentaire. L' exemple de multithreading démontre les améliorations du temps d'exécution sur un matériel multicœur.

La configuration linguistique est une référence de package. L'ajout de la prise en charge de la reconnaissance optique de caractères (OCR) en allemand ou en japonais à une intégration ABBYY impliquait d'identifier les fichiers de données, de les déployer dans les répertoires d'exécution sur chaque machine cible et de gérer les erreurs en cas de fichiers manquants. Avec IronOCR, dotnet add package IronOcr.Languages.German ajoute le pack de langue comme une dépendance NuGet versionnée et reproductible. Le Package Manager garantit que les données sont présentes dans chaque compilation. Le guide des packs de langue personnalisés couvre la formation et le déploiement de modèles de langue personnalisés pour des domaines spécialisés.

Veuillez noterABBYY FineReader et Tesseract sont des marques déposées de leurs propriétaires respectifs. Ce site n'est pas affilié, approuvé ou sponsorisé par ABBYY ou Google. 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 d'ABBYY FineReader Engine 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 d'ABBYY FineReader Engine vers IronOcr ?

Remplacer les séquences d'initialisation d'ABBYY FineReader 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 offre-t-il la même précision d'OCR qu'ABBYY FineReader Engine pour les documents professionnels 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 qu'ABBYY FineReader Engine 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 d'ABBYY FineReader Engine vers IronOCR nécessite-t-elle des modifications de l'infrastructure de déploiement ?

IronOCR nécessite moins de changements d'infrastructure qu'ABBYY FineReader Engine. 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 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 qu'ABBYY FineReader ?

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 d'ABBYY FineReader Engine 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 d'ABBYY FineReader Engine vers IronOcr ?

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