Ir para o conteúdo do rodapé
VíDEOS

Migrando do ABBYY FineReader para o IronOCR

Este guia orienta os desenvolvedores .NET em cada etapa da substituição do SDK do Motor ABBYY FineReader pelo IronOCR . Este documento aborda os passos mecânicos para remover dependências COM e artefatos do instalador do SDK, mapeia a API da ABBYY para equivalentes no IronOCR e fornece exemplos de código antes e depois para os padrões mais comuns em integrações da ABBYY em produção. A migração visa equipes que decidiram que o custo empresarial e a complexidade de implantação do ABBYY não estão mais alinhados com os requisitos de seus projetos.

Por que migrar do ABBYY FineReader?

O Motor ABBYY FineReader é uma plataforma OCR competente, mas sua arquitetura foi projetada para ambientes Enterprise Windows com equipes de infraestrutura dedicadas. Quando a carga de trabalho real de uma equipe .NET se resume ao processamento de faturas, digitalização de contratos ou extração de formulários digitalizados, essa arquitetura se torna um passivo em vez de um ativo.

A dívida de interoperabilidade COM se acumula com o tempo. Toda integração da ABBYY em .NET passa por uma camada de interoperabilidade COM. Objetos COM exigem gerenciamento explícito de ciclo de vida: criar, inicializar, processar, depois fechar em um bloco finally ou o processo vazará memória. Todo caminho de código que passa por ABBYY segue esse padrão. Ao longo de dois ou três anos de adições de funcionalidades, essa cerimônia de ciclo de vida se propaga pelas classes de serviço, processos em segundo plano e manipuladores de requisições. O resultado é 30-50% de código boilerplate em cada classe relacionada ao OCR que desaparece completamente quando você muda para IronTesseract.

O instalador do SDK bloqueia os padrões de implantação modernos. A ABBYY realiza a implantação por meio de um instalador do SDK para Windows que coloca binários, dados de idioma, arquivos de tempo de execução e arquivos de licença em caminhos predefinidos. Containerizar um serviço que usa ABBYY requer ou montar uma imagem base personalizada de 300+ MB a partir dessa saída do instalador ou montar volumes com arquivos de licença ao iniciar. Nenhuma abordagem se encaixa em um pipeline padrão de Kubernetes ou nativo da nuvem.IronOCR é um pacote NuGet: o mesmo dotnet restore que obtém qualquer outra dependência detém todo o mecanismo OCR.

O licenciamento por página transforma o volume em um centro de custos. Os modelos de licenciamento por volume da ABBYY cobram por página processada acima dos limites incluídos. Um aplicativo que processa 50.000 documentos por mês no lançamento e atinge 500.000 dois anos depois tem seus custos de OCR crescendo em proporção direta ao seu sucesso. A IronOCR cobra uma taxa fixa pela licença — uma equipe que processa dois milhões de páginas por mês paga exatamente o mesmo custo de licença que uma equipe que processa duas mil.

Os dados de idioma exigem coordenação manual de implantação. Os pacotes de idioma da ABBYY estão disponíveis como arquivos no diretório de tempo de execução do SDK. Adicionar um idioma significa identificar os arquivos de dados corretos, copiá-los para o caminho certo em cada destino de implantação e atualizar os scripts de CI/CD para incluí-los. Não IronOCR, adicionar francês é dotnet add package IronOcr.Languages.French — o gerenciador de pacotes cuida do resto.

Falhas de arquivo de licença impactam a produção sem aviso. Licenças ABBYY existem como arquivos .lic e .key que devem estar presentes em caminhos de disco específicos quando loader.GetEngineObject() executa. Se esses arquivos estiverem faltando em um novo servidor de produção — script de implantação incorreto, falha na cópia de arquivos, problema de permissões — a chamada gera um erro na inicialização. Uma licença expirada causa a mesma falha. A licença do IronOCR é uma chave string atribuída no código de inicialização, armazenável em qualquer gerenciador de segredos, com validação checada por IronOcr.License.IsValidLicense antes do aplicativo aceitar tráfego.

Segurança de thread requer uma única instância de motor compartilhada. O motor da ABBYY não é trivialmente seguro para threads para chamadas CreateFRDocument concorrentes de múltiplos threads. As implementações em produção utilizam estratégias de bloqueio ou pools de processadores. O IronTesseract do IronOCR é sem estado: inicie uma instância por thread, execute reconhecimento sem bloqueios, descarte quando terminado.

O problema fundamental

// 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

IronOCR vs ABBYY FineReader: Comparação de Recursos

A tabela a seguir abrange as funcionalidades relevantes para as equipes que avaliam essa migração.

Recurso Motor ABBYY FineReader IronOCR
Instalação Instalador do SDK (Windows) dotnet add package IronOcr
Aquisição Contatar a equipe de vendas (4 a 12 semanas) NuGet de autoatendimento
Modelo de licenciamento Enterprise, por servidor ou por página Perpétua, $999-$2,999 única vez
Gestão de Licenças .lic + .key arquivos no disco String chave no código ou variável de ambiente
Integração .NET Interoperabilidade COM .NET nativo
Dependência COM Sim Não
Segurança da rosca Requer estratégia de bloqueio Completo (um IronTesseract por thread)
Idiomas suportados 190+ 125+
Instalação de idioma Arquivos de dados de tempo de execução no caminho do SDK Pacotes de idioma NuGet
Entrada de PDF Sim (via CreatePDFFile) Sim (nativo, input.LoadPdf())
Saída em PDF pesquisável Sim (pipeline de exportação) Sim (result.SaveAsSearchablePdf())
Pré-processamento automático Baseado em perfil Funções integradas (Corrigir distorção, Reduzir ruído, Contraste, Binarizar, Nitidez)
OCR baseado em região Objetos de zona (CreateZone, SetBounds) Parâmetro CropRectangle
Leitura de código de barras Sim Sim (ocr.Configuration.ReadBarCodes = true)
Multiplataforma Windows, Linux, macOS Windows, Linux, macOS, Docker, Azure, AWS
Implantação do Docker Imagem base personalizada necessária Imagem base padrão .NET + libgdiplus
Pontuação de Confiança Sim Sim (result.Confidence)
Tempo até o primeiro resultado de OCR 4 a 12 semanas (aquisição) Não mesmo dia

Guia rápido: Migração do ABBYY FineReader para o IronOCR

Passo 1: Substitua o pacote NuGet

O Motor ABBYY FineReader não possui pacote NuGet . Remova-o desinstalando o SDK e removendo a referência de montagem manual do seu arquivo de projeto:


<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

Em seguida, remova a referência de interoperabilidade COM FREngine.dll do nó de Referências do Visual Studio ou exclua a entrada correspondente diretamente do arquivo de projeto. Instale o IronOCR a partir do NuGet :

dotnet add package IronOcr

Etapa 2: Atualizar Namespaces

// 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

Etapa 3: Inicializar a licença

Adicione isto uma vez na inicialização da aplicação, antes de qualquer chamada de OCR:

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

Armazene a chave em uma variável de ambiente ou gerenciador de segredos para implantações em produção:

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

Exemplos de migração de código

Ciclo de vida do mecanismo em um serviço do Windows versus IronTesseract sem estado

A cerimônia de inicialização do motor ABBYY pertence a um invólucro de serviço porque os objetos EngineLoader e IEngine são caros de criar. A maioria das integrações de produção encapsula o mecanismo em um serviço singleton com métodos explícitos de inicialização e encerramento.

Abordagem do ABBYY FineReader:

using FREngine;

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

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // Step 1: Create loader — requires Interoperabilidade 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 Interoperabilidade 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 Interoperabilidade 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

Abordagem IronOCR:

using IronOcr;

public class DocumentOcrService
{
    // Não 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
{
    // Não 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
    ' Não 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ão tem ciclo de vida do motor. Ele é inicializado internamente no primeiro uso e não requer um desligamento explícito. O invólucro do serviço hospedado, o campo IEngine, e os métodos StopAsync desaparecem. Se o aplicativo processa documentos simultaneamente, cada thread cria sua própria instância IronTesseract — nenhum bloqueio necessário. O guia de configuração do IronTesseract cobre opções de configuração, incluindo propriedades TesseractVersion e Configuration.

Configuração do idioma de reconhecimento

A configuração de idioma da ABBYY envolve criar um objeto LanguageParams, adicionar strings de nomes de idiomas que devem corresponder aos arquivos de dados instalados e associar esses parâmetros ao motor antes que qualquer documento seja processado. Cada idioma adicional requer os arquivos de dados correspondentes, que devem ser implantados no caminho de tempo de execução.

Abordagem do 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

Abordagem 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

Pacotes de linguagem são instalados como pacotes padrão do NuGet (dotnet add package IronOcr.Languages.French). Sem necessidade de implantar arquivos de dados manualmente, sem configuração de caminho, sem reinicialização do mecanismo ao trocar de idioma. O guia multilíngue aborda a combinação de idiomas e o índice de idiomas lista todos os mais de 125 pacotes disponíveis.

Processamento TIFF de múltiplos quadros

A ABBYY processa arquivos TIFF com várias páginas iterando os quadros e adicionando cada quadro como uma página de documento separada. A contagem de quadros deve ser obtida do objeto TIFF e, em seguida, cada quadro é adicionado individualmente ao contêiner do documento.

Abordagem do 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

Abordagem 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 lê cada quadro em um TIFF de várias páginas sem iteração manual. O resultado fornece acesso por página através de result.Pages, incluindo texto, dados de coordenadas e confiança por quadro. O guia de entrada TIFF abrange o processamento de TIFFs com múltiplos quadros e GIFs animados.

Processamento em lote paralelo

O motor baseado em COM ABBYY não é seguro para chamada CreateFRDocument de forma concorrente a partir de múltiplos threads sem uma estratégia de sincronização. Os processadores de lote de produção normalmente mantêm um conjunto de instâncias do mecanismo ou serializam o acesso por meio de um bloqueio. Qualquer uma das abordagens adiciona infraestrutura que o IronOCR elimina.

Abordagem do 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

Abordagem 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

Cada instância IronTesseract é independente. Parallel.ForEach satura os núcleos de CPU disponíveis sem qualquer estado compartilhado, bloqueios ou serialização. A versão ABBYY processa documentos sequencialmente, apesar do wrapper assíncrono; A versão IronOCR processa-os verdadeiramente em paralelo. O exemplo de multithreading demonstra esse padrão com comparações de tempo. Para controle de taxa de transferência de nível superior, consulte o guia de otimização de velocidade .

Canal de Exportação de Documentos

ABBYY suporta múltiplos formatos de exportação através de seu método Export com valores FileExportFormatEnum. Exportar para DOCX, RTF, ou texto simples requer a criação de objetos de parâmetro de exportação específicos do formato, depois chamar document.Export com o valor do enum apropriado e o objeto de parâmetros.

Abordagem do 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

Abordagem 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

O OcrResult do IronOCR expõe .Text diretamente e fornece métodos de saída sem objetos de parâmetro ou enums de formato. A chamada SaveAsSearchablePdf lida com exportação para PDF em uma linha versus a sequência de parâmetro/exportação em três etapas da ABBYY. O guia em PDF pesquisável aborda opções de intervalo de páginas e configurações de compressão. O guia de exportação hOCR abrange o formato HOCR para sistemas que utilizam saída OCR com reconhecimento de posição.

Referência de mapeamento da API ABBYY FineReader para o IronOCR

Motor ABBYY FineReader Equivalente de IronOCR
new EngineLoader() Não é necessário
loader.GetEngineObject(sdkPath, licensePath) new IronTesseract()
engine.LoadPredefinedProfile("...") Não é necessário (tratado internamente)
engine.CreateLanguageParams() Não é necessário
langParams.Languages.Add("French") ocr.Language = OcrLanguage.French
langParams.Languages.Add("English") + langParams.Languages.Add("German") ocr.Language = OcrLanguage.English + OcrLanguage.German
engine.CreateFRDocument() new OcrInput()
engine.CreateFRDocumentFromImage(path, null) ocr.Read(path)
document.AddImageFile(path, null, null) input.LoadImage(path)
imageInfo.LoadImageFile(tiff) + frameCount loop input.LoadImageFrames(tiff)
engine.CreatePDFFile() e depois pdfFile.Open(path, null, null) input.LoadPdf(path)
document.Process(null) ocr.Read(input)
document.PlainText.Text result.Text
frDocument.Pages[i].PlainText.Text result.Pages[i].Text
page.Layout.Blocks + BlockTypeEnum.BT_Table check result.Pages + dados de coordenadas das palavras
block.GetAsTableBlock() result.Pages[i].Lines (com coordenadas)
engine.CreatePDFExportParams() Não é necessário
document.Export(path, FEF_PDF, params) result.SaveAsSearchablePdf(path)
document.Export(path, FEF_TextUnicodeDefaults, null) File.WriteAllText(path, result.Text)
engine.CreateDOCXExportParams() + Exportar Não há suporte direto.
document.Close() Lidado por using em OcrInput
_engine.GetLicenseInfo().ExpirationDate IronOcr.License.IsValidLicense
Arquivos de licença (ABBYY.lic, ABBYY.key) IronOcr.License.LicenseKey = "key"
engine.CreateZone() + zone.SetBounds(x, y, w, h) new CropRectangle(x, y, width, height)

Problemas e soluções comuns em migrações

Problema 1: Erros de registro COM após a remoção do SDK

ABBYY: Após remover FREngine.dll das referências do projeto, a compilação pode ainda falhar com Could not load type 'FREngine.EngineLoader' ou erros de interoperabilidade COM de classes que mantiveram o antigo namespace.

Solução: Procure por todos os usos de FREngine e ABBYY.FineReader antes de remover a referência. Qualquer classe que implemente IDisposable especificamente para anular um campo IEngine precisa de sua lógica de descarte substituída por blocos de using em 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

Problema 2: O perfil de reconhecimento não tem equivalente.

ABBYY: Código que chama engine.LoadPredefinedProfile("DocumentConversion_Speed") ou engine.LoadPredefinedProfile("FieldLevelRecognition") usa perfis específicos da ABBYY para equilibrar precisão contra taxa de transferência. Não há propriedade equivalente a Profile no IronOCR.

Solução:IronOCR expõe as mesmas compensações através de IronTesseract.Configuration. Para otimização de velocidade, configure ocr.Configuration.TesseractVersion = TesseractVersion.Tesseract5 (padrão) e reduza filtros de pré-processamento. Para obter a máxima precisão, adicione o pipeline de pré-processamento completo:

// Speed-optimized
var ocr = new IronTesseract();
// Não 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();
// Não 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()
' Não 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

O guia de correção da qualidade da imagem explica quais filtros resolvem quais problemas de qualidade da imagem de entrada. O guia de otimização de velocidade aborda propriedades de configuração que reduzem o tempo de processamento em documentos limpos.

Problema 3: A etapa de implantação do arquivo de licença permanece no CI/CD

ABBYY: Pipelines de construção tipicamente contêm uma etapa que copia ABBYY.lic e ABBYY.key de um armazenamento seguro para o alvo de implantação. Após a migração, as equipes às vezes se esquecem de remover essa etapa, deixando um código de implantação obsoleto que faz referência a caminhos que não existem mais.

Solução: Elimine completamente a etapa de cópia do arquivo de licença. Substitua isso por uma etapa de injeção de variável de ambiente:

# 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

E na inicialização do aplicativo:

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

Problema 4: Motor não é seguro para threads — Código de bloqueio existente

ABBYY: Aplicativos que chamam ABBYY de múltiplos threads tipicamente contêm SemaphoreSlim, declarações de lock, ou instâncias de motor locais de thread para evitar problemas de encadeamento do COM. Este código de sincronização é específico para o modelo de threading da ABBYY.

Solução: Exclua todo o código de sincronização que envolve as chamadas ABBYY. O IronTesseract do IronOCR é seguro para instanciar por 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

Problema 5: Padrão CreateImageInfo / FrameCount para TIFF

ABBYY: Código que lê contagens de quadros de arquivos TIFF usando engine.CreateImageInfo() e imageInfo.LoadImageFile() antes de iterar os quadros não tem equivalente direto no IronOCR porque OcrInput.LoadImageFrames lida com enumeração de quadros internamente.

Solução: Elimine completamente o loop de contagem de frames:

// 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

Problema 6: A exportação para DOCX não possui equivalente direto.

ABBYY: document.Export(path, FileExportFormatEnum.FEF_DOCX, docxParams) produz um documento Word. O IronOCR não gera arquivos DOCX diretamente.

Solução: O IronOCR gera PDFs pesquisáveis ​​e dados de texto estruturados. Para fluxos de trabalho que exigem saída em DOCX, o caminho prático de migração é gerar um PDF pesquisável e convertê-lo posteriormente, ou extrair o texto estruturado e gravá-lo em um arquivo DOCX usando uma biblioteca como o 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

O guia de resultados de leitura abrange o acesso a parágrafos, linhas, palavras e dados de coordenadas em nível de caractere para processamento posterior.

Lista de verificação para migração do ABBYY FineReader

Tarefas pré-migração

Analise o código-fonte antes de fazer qualquer alteração:

# 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

Documente todas as classes que mantêm um campo IEngine ou IFRDocument. Observe quais formatos de exportação estão em uso — a saída em DOCX requer uma abordagem alternativa (consulte o Problema 6 acima).

Tarefas de atualização de código

  1. Remova a referência FREngine.dll de todos os arquivos .csproj
  2. Execute dotnet add package IronOcr em cada projeto que usou ABBYY
  3. Adicione IronOcr.License.LicenseKey = ... na inicialização do aplicativo (Program.cs ou classe de inicialização)
  4. Instale pacotes de idioma NuGet para cada idioma não-inglês (dotnet add package IronOcr.Languages.French, etc.)
  5. Exclua todas as chamadas de EngineLoader, GetEngineObject, e LoadPredefinedProfile
  6. Exclua todas as chamadas de CreateLanguageParams e langParams.Languages.Add
  7. Substitua engine.CreateFRDocument() + document.AddImageFile() + document.Process() por new IronTesseract().Read(path)
  8. Substitua loops de TIFF de vários quadros por input.LoadImageFrames(tiffPath)
  9. Substitua document.PlainText.Text por result.Text
  10. Substitua frDocument.Pages[i].PlainText.Text por result.Pages[i].Text
  11. Substitua document.Export(..., FEF_PDF, pdfParams) por result.SaveAsSearchablePdf(path)
  12. Substitua todas as chamadas de document.Close() por blocos de using em OcrInput
  13. Exclua SemaphoreSlim e o código de bloqueio que serializava o acesso ao motor ABBYY
  14. Substitua engine.CreateZone() / zone.SetBounds() / page.Zones.Add() por new CropRectangle(x, y, width, height) passado para input.LoadImage()
  15. Remover etapas de cópia de arquivos de licença dos pipelines de CI/CD
  16. Atualize as imagens Docker — remova a camada de instalação do SDK, adicione libgdiplus para alvos Linux

Testes pós-migração

  • Verificar o resultado da extração de texto em uma amostra representativa de cada tipo de documento (faturas, contratos, formulários digitalizados)
  • Confirme se o processamento de TIFF com várias páginas retorna o mesmo número de páginas que os frames produzidos pela ABBYY.
  • Testar documentos multilíngues com as mesmas entradas usadas para a comparação da linha de base da ABBYY.
  • Verifique se o PDF pesquisável permite a busca de texto no Adobe Reader e nos visualizadores de PDF do navegador. Execute o processador em lote paralelo com o nível de concorrência de produção e confirme que não ocorreram exceções.
  • Verifique result.Confidence em documentos conhecidos para estabelecer um limite de qualidade
  • Testar a inicialização da chave de licença a partir da variável de ambiente no ambiente de teste.
  • Verifique se a imagem Docker é criada e executa o OCR sem a montagem do volume do SDK da ABBYY.
  • Confirme se o pipeline de CI/CD foi concluído sem a etapa de cópia do arquivo de licença.
  • Execute um profiler de memória no processador em lote para confirmar que não há vazamento de objetos OcrInput (verifique o posicionamento de using)

Principais benefícios da migração para o IronOCR

A complexidade de implantação diminui drasticamente. Antes, cada implantação da ABBYY exigia a instalação do SDK, a colocação do arquivo de licença, a configuração do caminho de tempo de execução e a validação de que os arquivos estavam nos caminhos corretos antes que o aplicativo pudesse ser iniciado. O IronOCR é distribuído como uma dependência do NuGet . dotnet publish produz um artefato autossuficiente com o motor OCR incluído. O guia de implantação do Docker e o guia de configuração do Azure mostram a configuração completa — ambos cabem em uma única página.

A interoperabilidade COM se foi. Remover a camada COM elimina uma categoria inteira de falhas de tempo de execução: erros de registro COM em novas máquinas, erros de encadeamento de apartamento, bugs de ciclo de vida RCW, e as 15-25 linhas de código boilerplate try/finally que cada chamada de processamento de documento ABBYY requeria. A base de código diminui. A superfície de erro diminui com isso.

O aumento do volume de documentos não motiva mais revisões orçamentárias. A licença perpétua do IronOCR cobre um volume ilimitado de documentos. Um aplicativo que processa 10.000 documentos por mês no primeiro ano e 2.000.000 por mês no terceiro ano tem o mesmo custo de licenciamento de OCR. Não há contadores por página, faturas por excesso de uso ou renegociações de planos por volume. A página de licenciamento mostra todos os níveis — a licença Professional , a US$ 2.999, cobre dez desenvolvedores processando qualquer volume em qualquer número de destinos de implantação.

A implantação multiplataforma abre novas opções de infraestrutura. A camada COM da ABBYY requer Windows. As equipes que desejavam migrar o processamento de documentos para contêineres Linux por motivos de custo ou densidade de dados foram impedidas. O IronOCR funciona de forma idêntica no Windows, Linux e macOS a partir do mesmo pacote NuGet . A migração do ABBYY remove a restrição do Windows da camada OCR da pilha de aplicativos. O guia de implantação do Linux e o guia de implantação da AWS abrangem a configuração completa para cada ambiente.

O processamento paralelo está disponível sem necessidade de alterações na infraestrutura. As estratégias de bloqueio que serializavam o acesso ao mecanismo ABBYY foram eliminadas. Instâncias IronTesseract são independentes: inicie uma por thread, execute Parallel.ForEach em um lote de documentos, obtenha os resultados. A taxa de transferência aumenta proporcionalmente aos núcleos de CPU disponíveis, sem a necessidade de código adicional. O exemplo de multithreading demonstra melhorias significativas em desempenho real em hardware multi-core.

A configuração de idioma é uma referência de pacote. Adicionar suporte a OCR em alemão ou japonês a uma integração ABBYY significava identificar arquivos de dados, implantá-los em caminhos de tempo de execução em cada máquina de destino e lidar com falhas quando os arquivos estavam ausentes. Com IronOCR, dotnet add package IronOcr.Languages.German adiciona o pacote de idioma como uma dependência NuGet versionada e reprodutível. O gerenciador de pacotes garante que os dados estejam presentes em todas as compilações. O guia de pacotes de idiomas personalizados aborda o treinamento e a implantação de modelos de linguagem personalizados para domínios especializados.

ObserveABBYY FineReader e Tesseract são marcas registradas de seus respectivos proprietários. Este site não é afiliado, endossado ou patrocinado pela ABBYY ou Google. Todos os nomes de produtos, logotipos e marcas são propriedade de seus respectivos proprietários. As comparações são apenas para fins informativos e refletem informações disponíveis publicamente no momento da redação.

Perguntas frequentes

Por que devo migrar do ABBYY FineReader Engine para o IronOCR?

Entre os principais motivos, incluem-se a eliminação da complexidade da interoperabilidade COM, a substituição do gerenciamento de licenças baseado em arquivos, a eliminação da cobrança por página, a viabilização da implantação em Docker/contêineres e a adoção de um fluxo de trabalho nativo do NuGet que se integra às ferramentas padrão do .NET.

Quais são as principais alterações de código ao migrar do ABBYY FineReader Engine para o IronOCR?

Substitua as sequências de inicialização do ABBYY FineReader pela instanciação do IronTesseract, remova o gerenciamento do ciclo de vida COM (padrões explícitos de Criação/Carregamento/Fechamento) e atualize os nomes das propriedades de resultado. O resultado é uma redução significativa no número de linhas de código repetitivo.

Como faço para instalar o IronOCR para iniciar a migração?

Execute 'Install-Package IronOcr' no Console do Gerenciador de Pacotes ou 'dotnet add package IronOcr' na CLI. Os pacotes de idiomas são pacotes separados: 'dotnet add package IronOcr.Languages.French' para francês, por exemplo.

O IronOCR atinge a mesma precisão de OCR que o ABBYY FineReader Engine para documentos comerciais padrão?

O IronOCR alcança alta precisão para conteúdo comercial padrão, incluindo faturas, contratos, recibos e formulários digitados. Filtros de pré-processamento de imagem (correção de distorção, remoção de ruído, aprimoramento de contraste) melhoram ainda mais o reconhecimento em entradas de baixa qualidade.

Como o IronOCR lida com os dados de idioma que o ABBYY FineReader Engine instala separadamente?

Os dados de idioma no IronOCR são distribuídos como pacotes NuGet. O comando 'dotnet add package IronOcr.Languages.German' instala o suporte ao alemão. Não é necessário inserir arquivos manualmente nem configurar caminhos de diretório.

A migração do ABBYY FineReader Engine para o IronOCR requer alterações na infraestrutura de implantação?

O IronOCR requer menos alterações de infraestrutura do que o ABBYY FineReader Engine. Não há caminhos binários do SDK, necessidade de instalar arquivos de licença ou configurar servidores de licença. O pacote NuGet contém o mecanismo OCR completo e a chave de licença é uma string definida no código do aplicativo.

Como configuro o licenciamento do IronOCR após a migração?

Atribua `IronOcr.License.LicenseKey = "YOUR-KEY"` no código de inicialização do aplicativo. No Docker ou Kubernetes, armazene a chave como uma variável de ambiente e leia-a na inicialização. Use `License.IsValidLicense` para validar a licença antes de aceitar o tráfego.

O IronOCR consegue processar PDFs da mesma forma que o ABBYY FineReader?

Sim. O IronOCR lê PDFs nativos e digitalizados. Instancie o IronTesseract, chame ocr.Read(input) onde input é um caminho para um PDF ou OcrPdfInput, e itere pelas páginas do OcrResult. Não é necessário um pipeline de renderização de PDF separado.

Como o IronOCR lida com multithreading em processamento de alto volume?

O IronTesseract pode ser instanciado com segurança por thread. Crie uma instância por thread em um Parallel.ForEach ou pool de Tasks, execute o OCR simultaneamente e descarte cada instância ao terminar. Não é necessário nenhum estado global ou bloqueio.

Quais formatos de saída o IronOCR suporta após a extração de texto?

O IronOCR retorna resultados estruturados, incluindo texto, coordenadas de palavras, níveis de confiança e estrutura da página. As opções de exportação incluem texto simples, PDF pesquisável e objetos de resultados estruturados para processamento posterior.

O preço do IronOCR é mais previsível do que o do ABBYY FineReader Engine para cargas de trabalho escaláveis?

O IronOCR utiliza licenciamento perpétuo com preço fixo, sem cobranças por página ou volume. Independentemente de você processar 10.000 ou 10 milhões de páginas, o custo da licença permanece constante. As opções de licenciamento por volume e para equipes estão disponíveis na página de preços do IronOCR.

O que acontece com meus testes existentes após a migração do ABBYY FineReader Engine para o IronOCR?

Os testes que verificam o conteúdo de texto extraído devem continuar a ser aprovados após a migração. Os testes que validam padrões de chamadas de API ou o ciclo de vida de objetos COM precisarão ser atualizados para refletir o modelo de inicialização e resultados mais simples do IronOCR.

Kannaopat Udonpant
Engenheiro de Software
Antes de se tornar Engenheiro de Software, Kannapat concluiu um doutorado em Recursos Ambientais pela Universidade de Hokkaido, no Japão. Durante o doutorado, Kannapat também integrou o Laboratório de Robótica Veicular, que faz parte do Departamento de Engenharia de Bioprodução. Em 2022, ele utilizou suas habilidades ...
Leia mais

Equipe de Suporte Iron

Estamos online 24 horas por dia, 5 dias por semana.
Bater papo
E-mail
Liga para mim