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")
// 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()
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>
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
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"
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")
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
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
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
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)
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
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
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
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
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
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
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
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
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}}
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"))
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)
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
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
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" .
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
- Remova a referência
FREngine.dllde todos os arquivos.csproj - Execute
dotnet add package IronOcrem cada projeto que usou ABBYY - Adicione
IronOcr.License.LicenseKey = ...na inicialização do aplicativo (Program.csou classe de inicialização) - Instale pacotes de idioma NuGet para cada idioma não-inglês (
dotnet add package IronOcr.Languages.French, etc.) - Exclua todas as chamadas de
EngineLoader,GetEngineObject, eLoadPredefinedProfile - Exclua todas as chamadas de
CreateLanguageParamselangParams.Languages.Add - Substitua
engine.CreateFRDocument()+document.AddImageFile()+document.Process()pornew IronTesseract().Read(path) - Substitua loops de TIFF de vários quadros por
input.LoadImageFrames(tiffPath) - Substitua
document.PlainText.Textporresult.Text - Substitua
frDocument.Pages[i].PlainText.Textporresult.Pages[i].Text - Substitua
document.Export(..., FEF_PDF, pdfParams)porresult.SaveAsSearchablePdf(path) - Substitua todas as chamadas de
document.Close()por blocos deusingemOcrInput - Exclua
SemaphoreSlime o código de bloqueio que serializava o acesso ao motor ABBYY - Substitua
engine.CreateZone()/zone.SetBounds()/page.Zones.Add()pornew CropRectangle(x, y, width, height)passado parainput.LoadImage() - Remover etapas de cópia de arquivos de licença dos pipelines de CI/CD
- Atualize as imagens Docker — remova a camada de instalação do SDK, adicione
libgdipluspara 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.Confidenceem 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 deusing)
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.
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.

