Migrando do SDK Tesseract.NET para o IronOCR
Este guia orienta os desenvolvedores .NET por meio de uma migração concreta doSDK Tesseract.NET(Tesseract.Net.SDK, namespace Patagames.Ocr) para o IronOCR. O foco principal são as equipes que estão levando padrões de inicialização da era do .NET Framework, práticas legadas de descarte e pipelines exclusivamente síncronos para um mundo que agora roda em .NET 8, contêineres Linux e frameworks web com foco em assincronismo. Se o seu serviço de OCR compila contra net472 e falha no momento em que alguém adiciona <TargetFramework>net8.0</TargetFramework> ao .csproj, este guia foi escrito para você.
Por que migrar do SDK Tesseract .NET?
O SDK da Patagames ofereceu valor real quando o .NET Framework 4.5 era a versão básica de implantação e o Windows Server era o único alvo. Esse contexto mudou. A maioria das organizações agora conteineriza serviços, executa integração contínua em servidores Linux e padroniza o uso do .NET 6, 8 ou 9. O SDK do Tesseract for .NET não consegue acompanhar essas tendências.
Teto rígido no .NET Framework 4.5. O pacote direciona net20 por meio de net45. Ele não produz netstandard ou net6.0 assembly. Um arquivo de projeto que inclui Tesseract.Net.SDK não pode definir <TargetFramework>net8.0</TargetFramework>. A atualização do .NET , que o restante do código-fonte conclui em um sprint, fica paralisada indefinidamente na camada de OCR.
Não há caminho de contêiner. O SDK inclui chamadas P/Invoke exclusivas do Windows em binários nativos do Windows. Em qualquer imagem base Linux — mcr.microsoft.com/dotnet/aspnet:8.0, ubuntu:22.04, alpine:3.19 — o aplicativo lança DllNotFoundException antes de processar um único documento. Os contêineres do Windows existem como uma solução alternativa, mas apresentam tamanhos de imagem maiores, um custo de licenciamento separado e incompatibilidade com a maioria dos serviços gerenciados do Kubernetes, que utilizam pools de nós Linux por padrão.
API somente síncrona bloqueia pipelines do ASP.NET Core. O método OcrApi.GetTextFromImage() é síncrono. Não ASP.NET Core, chamar operações síncronas bloqueantes em threads de requisição degrada o desempenho sob carga e aumenta o risco de esgotamento do pool de threads. O IronOCR fornece ReadAsync() para integração não bloqueante. Consulte o guia de OCR assíncrono para obter o padrão.
Criação de engine por solicitação consome memória. O código do .NET Framework geralmente cria uma instância de OcrApi por chamada de método ou por solicitação, descartando-a na saída. Este é o gerenciamento idiomático do ciclo de vida do .NET Framework . Também é caro: cada Init() carrega 40–100 MB de dados de idioma. Dez requisições simultâneas carregam o mesmo modelo de linguagem dez vezes. O IronTesseract do IronOCR é seguro para threads — uma instância vive durante toda a vida do aplicativo e atende a todas as chamadas concorrentes a partir de um único carregamento de modelo de idioma.
Padrões legados de descarte acumulam riscos. O uso correto do SDK requer um using (var api = OcrApi.Create()) { ... } block — the C# 1.0 using statement that predates using var declarations. Bases de código escritas antes do C# 8.0 frequentemente incluem padrões de descarte de try/finally ou, em casos de bug, nenhum descarte. Esses padrões compilam e executam no .NET Framework , mas carregam dívida técnica que impede a refatoração moderna.
Sem async, sem DI, sem inicialização moderna. O SDK não tem conceito de integração de injeção de dependência, tempo de vida de serviço hospedado ou configuração de IOptions<t>. A integração com uma aplicação ASP.NET Core requer o registro manual do serviço e a necessidade de evitar cuidadosamente a instanciação por requisição. O IronOCR se integra perfeitamente como um serviço singleton no contêiner DI padrão.
O problema fundamental
// Tesseract.NET SDK: .NET Framework 4.5 ceiling — will not compile on net8.0
// Every project referencing this package is locked below the upgrade line
using Patagames.Ocr; // Patagames.Ocr targets net45; no netstandard or net8 assembly
public class OcrService
{
public string ProcessDocument(string imagePath)
{
// Synchronous-only — blocks ASP.NET Core request threads
// Não DI support — must be instantiated manually each time
using (var api = OcrApi.Create()) // C# 1.0 using statement, 40-100MB load per call
{
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
// Project cannot target net6.0, net8.0, or any Linux container base image
}
}
// IronOCR: same logic, any runtime from net462 to net9.0, any platform
using IronOcr; // Single NuGet, supports .NET Framework 4.6.2+, .NET 5/6/7/8/9
// Register once as singleton — load language model once, share across all requests
// Call ReadAsync() in ASP.NET Core for non-blocking operation
var ocr = new IronTesseract();
var result = await ocr.ReadAsync("document.jpg"); // Async-first, no thread blocking
Console.WriteLine(result.Text);
IronOCR vs Tesseract .NET SDK: Comparação de Recursos
A tabela abaixo mapeia as funcionalidades diretamente relevantes para uma migração de modernização do .NET .
| Recurso | SDK Tesseract.NET | IronOCR |
|---|---|---|
| .NET Framework 2.0–4.5 | Sim | Não |
| .NET Framework 4.6.2–4.8 | Não | Sim |
| .NET Core 2.x / 3.x | Não | Sim |
| .NET 5 | Não | Sim |
| .NET 6 | Não | Sim |
| .NET 7 | Não | Sim |
| .NET 8 | Não | Sim |
| .NET 9 | Não | Sim |
| Implantação do Windows | Sim | Sim |
| Implantação do Linux | Não | Sim |
| implantação do macOS | Não | Sim |
| Contêineres Docker Linux | Não | Sim |
| Serviço de Aplicativos do Azure (Linux) | Não | Sim |
| AWS Lambda | Não | Sim |
API assíncrona (ReadAsync) | Não | Sim |
| Instância única thread-safe | Não | Sim |
| Integração de injeção de dependência (DI) do ASP.NET Core | Manual | Serviço Singleton |
| Entrada nativa de PDF | Não | Sim |
| Pré-processamento integrado | Não | Sim |
| Saída em PDF pesquisável | Não | Sim |
| Dados estruturados (palavras, linhas, parágrafos) | Não | Sim |
| Suporte comercial / SLA | Não (desenvolvedor individual) | Sim |
| Preço da licença perpétua | Aproximadamente US$ 20 a US$ 50 (desenvolvedor individual) | De $999 |
Guia de Início Rápido: Migração do SDK .NET do Tesseract para o IronOCR
Passo 1: Substitua o pacote NuGet
Remover o SDK .NET do Tesseract:
dotnet remove package Tesseract.Net.SDK
Se o PdfiumViewer ou uma biblioteca similar de renderização de PDF foi instalada apenas para fornecer páginas PDF ao SDK, remova-a também — o IronOCR lê PDFs nativamente:
dotnet remove package PdfiumViewer
Instale o IronOCR a partir do NuGet :
Etapa 2: Atualizar Namespaces
// Before (Tesseract.NET SDK)
using Patagames.Ocr;
using Patagames.Ocr.Enums;
// After (IronOCR)
using IronOcr;
Etapa 3: Inicializar a licença
Adicione a chamada de chave de licença uma vez na inicialização do aplicativo — em Program.cs, Startup.cs ou no construtor do host do aplicativo:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"Uma licença de avaliação gratuita está disponível para consulta, sem marcas d'água.
Exemplos de migração de código
Do padrão de inicialização do .NET Framework ao Builder de host moderno
Aplicações do .NET Framework normalmente inicializam o motor de OCR em um construtor estático, um evento de Application_Start, ou um manipulador de Global.asax. Nenhuma dessas opções existe em aplicativos .NET 6+ construídos com base no modelo de host genérico.
Abordagem do SDK Tesseract .NET :
// Global.asax.cs — .NET Framework MVC application
// OcrApi lifecycle managed manually; no DI container involved
public class MvcApplication : System.Web.HttpApplication
{
// Static field — one engine for the app lifetime
// But: NOT thread-safe; concurrent requests share a single OcrApi instance
private static OcrApi _globalApi;
protected void Application_Start()
{
// Initialize OCR engine on app startup
// Path to tessdata hardcoded for deployment environment
_globalApi = OcrApi.Create();
_globalApi.Init(Languages.English);
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
protected void Application_End()
{
// Must manually dispose on shutdown
_globalApi?.Dispose();
}
}
Abordagem IronOCR:
// Program.cs —.NET 8ASP.NET Core application
// IronTesseract é seguro para roscas; register as singleton, inject where needed
var builder = WebApplication.CreateBuilder(args);
IronOcr.License.LicenseKey = builder.Configuration["IronOcr:LicenseKey"];
// Register as singleton — one instance, thread-safe, shared across all requests
builder.Services.AddSingleton<IronTesseract>();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
O padrão Global.asax desaparece completamente. IronTesseract se registra como um serviço singleton padrão, injetado em controladores e serviços através do construtor. O modelo de linguagem é carregado uma única vez, no primeiro uso, e permanece na memória durante toda a vida útil da aplicação. O guia de configuração do IronTesseract aborda opções de configuração, incluindo a seleção de idioma e o modo do mecanismo no momento do registro.
Modernização dos padrões de descarte legados
O código .NET Framework 2.0 usa a declaração de bloco using (var x = ...) { }. O C# 8.0 introduziu declarações using var que limitam o descarte ao bloco de encerramento. Bases de código mais antigas também possuem proteções de descarte de try/finally escritas quando as declarações using não eram confiáveis em todos os cenários. Todos esses padrões indicam código escrito para o .NET Framework e devem ser modernizados durante a migração.
Abordagem do SDK Tesseract .NET :
// .NET Framework 4.x disposal patterns — three variants encountered in production
public class LegacyOcrProcessor
{
// Pattern 1: try/finally guard (pre-C# 2.0 style, still common in legacy code)
public string ProcessWithTryFinally(string imagePath)
{
OcrApi api = null;
try
{
api = OcrApi.Create();
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
finally
{
if (api != null)
api.Dispose(); //Manualnull check required
}
}
// Pattern 2: nested using blocks — one for engine, one for image object
public string ProcessWithNestedUsing(string imagePath)
{
using (var api = OcrApi.Create())
{
api.Init(Languages.English);
using (var img = OcrImage.FromFile(imagePath))
{
api.SetImage(img);
return api.GetText();
} // img disposed here
} // api disposed here — nested indentation grows with each resource
}
// Pattern 3: missing disposal — memory leak, common in older service code
public string ProcessUnsafe(string imagePath)
{
var api = OcrApi.Create(); // WARNING: never disposed
api.Init(Languages.English);
return api.GetTextFromImage(imagePath);
}
}
Abordagem IronOCR:
// Modern C# 8.0+ disposal — flat, readable, no nesting
public class ModernOcrProcessor
{
private readonly IronTesseract _ocr; // Injected singleton, never disposed per-request
public ModernOcrProcessor(IronTesseract ocr) => _ocr = ocr;
// Pattern 1: using var declaration — scoped to method, no nesting
public string ProcessDocument(string imagePath)
{
using var input = new OcrInput(); // OcrInput is the disposable resource, not the engine
input.LoadImage(imagePath);
return _ocr.Read(input).Text;
} // input disposed here automatically — no nesting, no try/finally
// Pattern 2: multiple inputs in one scope — still flat
public string ProcessMultipleInputs(string imagePath, string pdfPath)
{
using var imageInput = new OcrInput();
imageInput.LoadImage(imagePath);
using var pdfInput = new OcrInput();
pdfInput.LoadPdf(pdfPath);
var imageText = _ocr.Read(imageInput).Text;
var pdfText = _ocr.Read(pdfInput).Text;
return $"{imageText}\n{pdfText}";
} // both inputs disposed here — zero nesting
}
OcrInput é o único recurso descartável no IronOCR. O próprio motor (IronTesseract) não é descartado por solicitação — ele é um singleton. Isso elimina o recarregamento do modelo de idioma de 40–100 MB por solicitação imposto por OcrApi.Create() + api.Init(). O guia de entrada de imagem cobre todos os métodos de carregamento de OcrInput, incluindo streams, arrays de bytes e URLs.
Integração assíncrona para controladores ASP.NET Core
O SDK Tesseract .NET não possui uma API assíncrona. Cada chamada é síncrona. Não ASP.NET Core, chamar operações síncronas de bloqueio a partir de ações assíncronas do controlador representa um risco de esgotamento do pool de threads sob carga. A solução alternativa comum — envolver chamadas síncronas em Task.Run() — transfere o trabalho de bloqueio para um thread do pool de threads, mas não elimina o consumo de threads. O ReadAsync() do IronOCR oferece integração I/O genuinamente assíncrona.
Abordagem do SDK Tesseract .NET :
// ASP.NET Core controller — forced workaround for synchronous OCR API
[ApiController]
[Route("api/ocr")]
public class OcrController : ControllerBase
{
[HttpPost("extract")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
// Must copy upload to temp file — OcrApi does not accept streams directly
var tempPath = Path.GetTempFileName();
await using (var stream = System.IO.File.OpenWrite(tempPath))
await file.CopyToAsync(stream);
string text;
try
{
// Task.Run wraps synchronous call — still consumes a thread-pool thread
// Does NOT free the calling thread during OCR processing
text = await Task.Run(() =>
{
using (var api = OcrApi.Create()) // 40-100MB load per request
{
api.Init(Languages.English);
return api.GetTextFromImage(tempPath); // synchronous, blocking
}
});
}
finally
{
System.IO.File.Delete(tempPath); //Manualtemp file cleanup
}
return Ok(new { text });
}
}
Abordagem IronOCR:
// ASP.NET Core controller — genuine async OCR, no temp files, no thread blocking
[ApiController]
[Route("api/ocr")]
public class OcrController : ControllerBase
{
private readonly IronTesseract _ocr; // Singleton injected via DI
public OcrController(IronTesseract ocr) => _ocr = ocr;
[HttpPost("extract")]
public async Task<IActionResult> ExtractText(IFormFile file)
{
// Load stream directly — no temp file needed
using var input = new OcrInput();
input.LoadImage(file.OpenReadStream()); // Stream input, no disk write
// ReadAsync — genuinely non-blocking, integrates with ASP.NET Core pipeline
var result = await _ocr.ReadAsync(input);
return Ok(new
{
text = result.Text,
confidence = result.Confidence
});
}
}
O processo de transferência de arquivos temporários desaparece. O wrapper Task.Run desaparece. O OcrApi.Create() por solicitação e o carregamento de 40–100 MB que o seguiam desaparecem. O guia prático de OCR assíncrono e o guia de entrada de fluxo documentam o pipeline assíncrono completo, incluindo o suporte a tokens de cancelamento.
Processamento TIFF de múltiplos quadros
O artigo comparativo da Fase 1 abordou o processamento básico de imagens e PDFs. O formato TIFF com múltiplos quadros é um cenário específico comum em arquivamento de documentos, sistemas de fax e fluxos de trabalho de imagens médicas. OSDK Tesseract.NET/exige iterar manualmente quadros TIFF usando System.Drawing.Bitmap, extraindo cada quadro para um arquivo PNG temporário, executando OCR no arquivo temporário e limpando. O padrão força chamadas explícitas de GC em documentos grandes para evitar erros de falta de memória.
Abordagem do SDK Tesseract .NET :
// Multi-frame TIFF: manual frame extraction to temp files + forced GC
using System.Drawing;
using System.Drawing.Imaging;
using Patagames.Ocr;
public List<string> ProcessMultiFrameTiff(string tiffPath)
{
var pageTexts = new List<string>();
using (var api = OcrApi.Create())
{
api.Init(Languages.English);
using (var bitmap = new Bitmap(tiffPath))
{
var dimension = new FrameDimension(bitmap.FrameDimensionsList[0]);
int frameCount = bitmap.GetFrameCount(dimension);
for (int i = 0; i < frameCount; i++)
{
bitmap.SelectActiveFrame(dimension, i);
// Must write each frame to a temp file — no in-memory path
var tempPath = Path.GetTempFileName() + ".png";
bitmap.Save(tempPath, ImageFormat.Png);
try
{
pageTexts.Add(api.GetTextFromImage(tempPath));
}
finally
{
File.Delete(tempPath); //Manualcleanup on every frame
}
// Force GC every 10 frames — workaround for memory pressure
// Slows processing; indicates memory management is manual
if (i % 10 == 0)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
}
return pageTexts;
}
Abordagem IronOCR:
// Multi-frame TIFF: one method call, no temp files, no manual GC
using IronOcr;
public List<string> ProcessMultiFrameTiff(string tiffPath)
{
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImageFrames(tiffPath); // Loads all frames natively — no temp files
var result = ocr.Read(input);
// Pages map directly to TIFF frames
return result.Pages.Select(page => page.Text).ToList();
}
Trinta linhas se reduzem a oito. Sem arquivos temporários, sem iteração de quadros de Bitmap, sem chamadas de GC.Collect(). LoadImageFrames lida com TIFFs multiframes de tamanho arbitrário sem escrever arquivos intermediários. O guia de entrada TIFF e GIF aborda o carregamento seletivo de quadros (por intervalo de índice) e as funções de retorno de chamada de progresso para documentos grandes.
Preparação para a implantação de contêineres Docker
O código do SDK .NET do Tesseract, executado na máquina Windows de um desenvolvedor, falha na etapa de compilação ou execução do Docker quando a imagem base é Linux. A solução não é um ajuste no Dockerfile — os binários nativos são exclusivos do Windows e não podem ser carregados no Linux de forma alguma. O suporte do IronOCR para Linux requer uma pequena adição apt-get ao Dockerfile e nada mais no código do aplicativo.
Abordagem do SDK Tesseract .NET :
# Dockerfile attempt — fails at runtime on Linux base image
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# This base image is Linux (Debian) by default
# Tesseract.Net.SDK's Windows native DLLs cannot load here
# Application throws DllNotFoundException on first OCR call
WORKDIR /app
COPY --from=build /app/publish .
# Even copying the Windows tessdata folder has no effect —
# the P/Invoke DLL cannot be loaded regardless of file placement
COPY tessdata/ ./tessdata/
ENTRYPOINT ["dotnet", "MyApp.dll"]
# Runtime error: DllNotFoundException: Unable to load DLL 'libtesseract'
# Não fix available within Tesseract.Net.SDK — requires replacing the library
Abordagem IronOCR:
# Dockerfile for IronOCR on Linux — add one apt-get line, nothing else changes
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
# Required system dependency for IronOCR on Debian/Ubuntu base images
RUN apt-get update && apt-get install -y libgdiplus \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/publish .
# Não tessdata folder — language data is bundled with the IronOcr NuGet packages
# Não platform check code —IronOCR runs identically on Windows and Linux
ENTRYPOINT ["dotnet", "MyApp.dll"]
Uma linha de apt-get. Sem pasta tessdata. Não há código condicional à plataforma no aplicativo. O mesmo binário de aplicação que roda na máquina Windows do desenvolvedor roda neste contêiner Linux sem alterações. O guia de implantação do Docker abrange imagens baseadas em Alpine (que usam apk em vez de apt-get), otimização de compilação em várias etapas e configuração de variáveis de ambiente para a chave de licença. O guia de implantação do Linux abrange cenários de Linux em sistemas bare-metal e WSL2.
Referência de mapeamento da API do SDK .NET do Tesseract para o IronOCR
| SDK Tesseract.NET | Equivalente de IronOCR | Notas |
|---|---|---|
Install-Package Tesseract.Net.SDK | dotnet add package IronOcr | O IronOCR é compatível com o .NET Framework 4.6.2+ e .NET 5–9. |
using Patagames.Ocr; | using IronOcr; | Espaço de nomes único |
using Patagames.Ocr.Enums; | (not needed) | Enums estão no namespace IronOcr |
OcrApi.Create() | new IronTesseract() | IronTesseract é seguro para roscas; usar como singleton |
api.Init(Languages.English) | ocr.Language = OcrLanguage.English | Atribuição de propriedade, não chamada de método |
api.Init(Languages.English | Languages.German) | ocr.Language = OcrLanguage.English + OcrLanguage.German | Operador +, não OR bit a bit |
api.GetTextFromImage(path) | ocr.Read("path.jpg").Text | Diretamente ou via OcrInput |
api.GetTextFromImage(path) (assíncrono) | await ocr.ReadAsync(input) | Assíncrono genuíno — sem wrapper Task.Run necessário |
OcrImage.FromFile(path) | input.LoadImage(path) | OcrInput substitui OcrImage |
OcrImage.FromBitmap(bitmap) | input.LoadImage(bitmap) | |
new MemoryStream(bytes) → OcrImage.FromBitmap | input.LoadImage(bytes) | Suporte direto a matrizes de bytes |
api.SetImage(img); api.GetText() | ocr.Read(input).Text | OcrInput passado para Read |
api.GetMeanConfidence() | result.Confidence | Percentagem de retorno; also available per-word |
api.SetRectangle(x, y, w, h) | input.LoadImage(path, new CropRectangle(x, y, w, h)) | OCR baseado em região via CropRectangle |
api.SetVariable("tessedit_char_whitelist", x) | ocr.Configuration.WhiteListCharacters = x | |
api.SetVariable("tessedit_char_blacklist", x) | ocr.Configuration.BlackListCharacters = x | |
| Iteração de quadro bitmap + arquivo temporário | input.LoadImageFrames(tiffPath) | Suporte nativo a TIFF com múltiplos quadros |
| (synchronous only) | result.SaveAsSearchablePdf("out.pdf") | Não há equivalente no SDK .NET do Tesseract. |
| (no structured output) | result.Pages, result.Words, result.Lines | Coordenadas e confiança ao nível da palavra |
Soluções alternativas de GC.Collect() | (not needed) | O IronOCR gerencia a memória internamente. |
Verificação de plataforma: IsOSPlatform(Windows) | (remove entirely) | IronOCR é multiplataforma |
| Gerenciamento de pastas Tessdata | (remove entirely) | Idiomas incluídos nos pacotes NuGet |
Problemas e soluções comuns em migrações
Questão 1: Conflito na Estrutura de Metas do Projeto
Tesseract.NET SDK: Após remover Tesseract.Net.SDK e adicionar IronOcr, o projeto ainda direciona net45 ou net472 do requisito antigo. O IronOCR dá suporte a net462 e posteriores, então projetos net45 precisam da atualização do framework de destino antes que o pacote possa ser restaurado sem problemas.
Solução: Atualize o <TargetFramework> no arquivo .csproj antes de adicionar o IronOCR. Se o projeto precisar oferecer suporte a ambientes de execução antigos e novos durante uma migração faseada, use o recurso de direcionamento múltiplo:
<!-- Single modern target (preferred) -->
<TargetFramework>net8.0</TargetFramework>
<!-- Multi-targeting during phased migration — supports both simultaneously -->
<TargetFrameworks>net462;net8.0</TargetFrameworks>
O IronOCR identifica automaticamente a montagem correta para cada alvo. O mesmo comando dotnet add package IronOcr funciona para ambos. A página da biblioteca .NET OCR lista todas as estruturas de destino suportadas.
Problema 2: Campo OcrApi estático substituído por Singleton de injeção de dependência
Tesseract.NET SDK: O código legado registra uma única instância de OcrApi como um campo estático (em Global.asax, um localizador de serviço estático ou uma classe de wrapper singleton). Este padrão era necessário porque OcrApi não é seguro para threads — compartilhar uma instância entre threads causa condições de corrida, então o campo estático era protegido por um bloqueio ou era recriado por solicitação, apesar do nome do campo.
Solução: Registre IronTesseract como um singleton genuinamente seguro para threads através do contêiner DI. Remova o bloqueio, remova o campo estático, remova qualquer recriação por solicitação:
// Remove: private static OcrApi _instance; / private static readonly object _lock = new();
// Replace with DI registration in Program.cs
builder.Services.AddSingleton<IronTesseract>();
// In consuming classes — constructor injection
public class DocumentProcessor
{
private readonly IronTesseract _ocr;
public DocumentProcessor(IronTesseract ocr) => _ocr = ocr;
public async Task<string> ProcessAsync(string path)
{
using var input = new OcrInput();
input.LoadImage(path);
var result = await _ocr.ReadAsync(input);
return result.Text;
}
}
Problema 3: Pasta Tessdata ausente após a implantação
SDK Tesseract .NET : Após a migração para o IronOCR, as equipes às vezes deixam etapas de implantação do tessdata nos pipelines de CI/CD. A pasta tessdata/ referenciada em scripts de compilação e manifestos de implantação não existe mais — era parte do gerenciamento de modelo de idioma do antigo SDK. Os scripts falham quando tentam copiar ou verificar uma pasta que não existe mais.
Solução: Remova todas as referências de tessdata dos scripts de implantação, alvos de cópia .csproj, comandos Docker COPY e etapas de pipeline CI/CD. Os dados de idioma do IronOCR são incluídos nos pacotes NuGet . Execute dotnet restore e os dados de idioma estarão disponíveis. Nada mais é necessário:
# Remove from CI/CD pipeline
# BEFORE (delete these lines):
# - cp -r tessdata/ $DEPLOY_PATH/tessdata/
# - test -f $DEPLOY_PATH/tessdata/eng.traineddata
# AFTER: nothing — language data is in the NuGet package restore output
dotnet restore # Downloads IronOcr and any IronOcr.Languages.* packages
dotnet publish # Includes language data automatically
O guia de vários idiomas aborda a instalação de pacotes de idiomas específicos como pacotes NuGet para implantações offline/isoladas da internet.
Problema 4: BadImageFormatException em incompatibilidade 32/64-bit
SDK do Tesseract for .NET : O SDK inclui binários nativos separados para Windows, nas versões x86 e x64. Projetos direcionados a AnyCPU às vezes resolvem para o binário errado dependendo da arquitetura do processo. O erro aparece como BadImageFormatException ou DllNotFoundException em tempo de execução em máquinas onde a arquitetura do processo não coincide com a DLL nativa na pasta de saída.
Solução: O IronOCR agrupa o binário nativo correto para cada plataforma no pacote NuGet e resolve o binário certo automaticamente através da pasta runtimes/ no layout do pacote. Sem configuração de destino Platform, sem comandos de cópia condicionais à arquitetura, sem subpastas x64 para gerenciar:
<!-- Remove architecture-specific build configurations from .csproj -->
<!-- BEFORE: Conditional native DLL copy based on Platform target -->
<!--
<ItemGroup Condition="'$(Platform)' == 'x64'">
<Content Include="$(SolutionDir)libs\x64\*.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
-->
<!-- AFTER: Nothing.IronOCR resolves the correct binary automatically. -->
Problema 5: Migração da string de configuração
Tesseract.NET SDK: Variáveis do motor do Tesseract são definidas via api.SetVariable(string name, string value) usando chaves de strings brutas da referência da API do Tesseract (por exemplo, "tessedit_char_whitelist", "tessedit_pageseg_mode"). Essas são strings sem tipo definido e sem recurso de autocompletar no IDE. Erros de digitação causam falhas silenciosas — a variável é ignorada, não uma exceção.
Solução: O IronOCR expõe a configuração do motor como propriedades tipadas em ocr.Configuration. Erros de digitação se transformam em erros de compilação:
// Before: untyped string variables, silent failures on typos
api.SetVariable("tessedit_char_whitelist", "0123456789");
api.SetVariable("tessedit_pageseg_mode", "7");
// After: typed properties, compile-time validation, IDE completion
ocr.Configuration.WhiteListCharacters = "0123456789";
ocr.Configuration.PageSegmentationMode = TesseractPageSegmentationMode.SingleLine;
A documentação de referência da API do IronTesseract apresenta todas as propriedades de configuração, seus tipos e valores aceitos.
Problema 6: Relatórios de progresso para trabalhos em lote de longa duração
Tesseract.NET SDK: Código de processamento em lote que reporta progresso usando IProgress<t> funciona no nível do trabalho (incrementa um contador após cada arquivo) mas não pode relatar dentro de um único documento — não há mecanismo de callback dentro de GetTextFromImage(). Em documentos de 500 páginas, a barra de progresso fica travada até que o documento inteiro seja concluído.
Solução: O IronOCR fornece rastreamento de progresso embutido por meio do evento OcrProgress em OcrInput. O progresso é exibido página por página, permitindo barras de progresso precisas para documentos longos com várias páginas:
// IronOCR: page-level progress tracking for multi-page documents
using IronOcr;
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf("large-archive.pdf");
// Subscribe to page-level progress events
input.OcrProgress += (sender, e) =>
{
Console.WriteLine($"Processing page {e.CurrentPage} of {e.TotalPages} " +
$"({e.ProgressPercent:F0}%)");
};
var result = ocr.Read(input);
Console.WriteLine($"Complete: {result.Pages.Count} pages extracted");
O guia de acompanhamento de progresso aborda a integração com o ASP.NET Core SignalR para o envio de informações de progresso em tempo real para clientes de navegador.
Lista de verificação para migração do SDK .NET do Tesseract
Pré-migração
Antes de modificar qualquer código, faça uma auditoria completa da base de código para verificar se há uso do SDK .NET do Tesseract:
# Find all files referencing Patagames namespace
grep -rl "Patagames" --include="*.cs" .
# Find all OcrApi instantiation points
grep -rn "OcrApi.Create" --include="*.cs" .
# Find tessdata references in project and build files
grep -rn "tessdata" --include="*.cs" --include="*.csproj" --include="*.yaml" --include="*.yml" .
# Find platform guard checks that can be removed after migration
grep -rn "IsOSPlatform.*Windows" --include="*.cs" .
# Find Task.Run wrappers around synchronous OCR calls
grep -rn "Task.Run" --include="*.cs" . | grep -i "ocr\|image\|text"
# Count distinct OcrApi.Create() call sites to estimate migration scope
grep -c "OcrApi.Create" $(find . -name "*.cs")
Documente a contagem de locais de chamada OcrApi.Create() — cada um é um candidato à substituição por injeção de singleton. Observe quaisquer padrões de descarte de try/finally para modernização. Identifique qualquer inicialização de Global.asax, Application_Start ou de construtor estático que se moverá para Program.cs.
Migração de código
- Atualize
<TargetFramework>paranet8.0(ou o runtime moderno de destino) em todos os arquivos.csproj - Execute
dotnet remove package Tesseract.Net.SDKem cada projeto - Execute
dotnet remove package PdfiumViewer(ou pacote de renderização de PDF equivalente) se presente - Execute
dotnet add package IronOcrem cada projeto - Adicione
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";aoProgram.csou ao construtor do host - Registre
IronTesseractcomo um singleton no contêiner DI:services.AddSingleton<IronTesseract>() - Substitua todo
using Patagames.Ocr;eusing Patagames.Ocr.Enums;porusing IronOcr; - Substitua
OcrApi.Create()+api.Init(Languages.X)porIronTesseractinjetado no construtor - Substitua
using (var api = OcrApi.Create()) { ... }blocks withusing var input = new OcrInput()declarations - Substitua
api.GetTextFromImage(path)porocr.Read(input).Textouawait ocr.ReadAsync(input) - Substitua
Task.Run(() => { /* synchronous OCR */ })porawait ocr.ReadAsync(input)direto - Substitua
api.GetMeanConfidence()porresult.Confidence - Substitua loops de iteração de quadros TIFF de Bitmap por
input.LoadImageFrames(tiffPath) - Substitua
api.SetVariable("tessedit_char_whitelist", x)porocr.Configuration.WhiteListCharacters = x - Exclua a pasta tessdata do projeto e remova todas as referências a ela nos scripts de implantação.
Pós-migração
- Compile o projeto direcionado a
net8.0e confirme que não restam referências dePatagamesna saída de compilação - Execute o aplicativo em um host Linux ou contêiner Docker Linux e confirme que não há
DllNotFoundException - Verificar se a saída de texto do OCR corresponde à saída pré-migração em uma amostra representativa de documentos de produção (10 a 20 documentos).
- Testar o processamento de TIFF com várias páginas e confirmar se a contagem de páginas corresponde à contagem de quadros original.
- Execute testes de carga nos endpoints do ASP.NET Core usando
ReadAsync()e verifique as métricas do pool de threads mostram nenhum bloqueio - Confirme que o contêiner DI resolve
IronTesseractcomo um singleton (mesma instância em todas as solicitações) - Verifique se o pipeline de CI/CD é concluído sem erros agora que as etapas de cópia do tessdata foram removidas.
- Testar a criação de imagens Docker e a execução de contêineres em uma imagem base Linux.
- Confirme se os eventos de progresso são disparados corretamente em um documento com várias páginas (PDF ou TIFF)
- Verificar se os níveis de confiança estão dentro da faixa esperada para documentos comprovadamente bons.
Principais benefícios da migração para o IronOCR
O bloqueio de atualização do .NET foi removido. Antes da migração, qualquer plano para migrar o serviço do .NET Framework 4.x para o.NET 8era interrompido na camada de OCR. Após a migração, o serviço OCR compila e executa no .NET Framework 4.6.2, .NET 6,.NET 8e.NET 9a partir da mesma referência de pacote. O caminho de atualização está desbloqueado. As equipes que mantinham uma implementação de ambiente de execução legado separado apenas para OCR podem consolidar tudo em um único ambiente de execução moderno.
Implantação de contêiner funciona sem compromissos. O DllNotFoundException em imagens base Linux é eliminado. O mesmo binário de aplicativo que roda na estação de trabalho Windows de um desenvolvedor roda dentro de um contêiner Debian ou Alpine com uma linha apt-get no Dockerfile. Implantações do Kubernetes, Azure Container Apps e tarefas AWS ECS em pools de nós Linux funcionam todas sem licenciamento de contêiner Windows, tamanhos de imagem maiores ou caminhos de código condicionais à arquitetura. O guia de implantação do Docker e o guia do Azure documentam a configuração exata para cada ambiente de destino.
Pipelines primeiro assíncrono eliminam a pressão do pool de threads. A solução que envolvia a OCR síncrona em um método assíncrono Task.Run é substituída por ReadAsync(). Não ASP.NET Core, as threads de requisição são liberadas durante o processamento de OCR, em vez de serem bloqueadas. Em situações de alta concorrência, isso se traduz diretamente em maior taxa de transferência de solicitações e menor latência para toda a aplicação, e não apenas para os endpoints de OCR.
O consumo de memória cai proporcionalmente com a concorrência. Um serviço que anteriormente criava uma instância de OcrApi por solicitação concorrente — cada uma carregando 40–100 MB de dados de idioma — agora carrega esses dados uma vez em uma instância singleton IronTesseract. Com dez solicitações simultâneas, a diferença é de 400 a 1000 MB em comparação com uma única carga fixa. Essa redução é imediatamente visível nas métricas de recursos do contêiner e possibilita limites de memória menores para os pods, maior densidade de pods e menor custo de infraestrutura em nuvem.
Padrões modernos de C# substituem cerimonial do .NET Framework. As proteções de descarte de try/finally, os blocos aninhados de using, as chamadas de GC.Collect() entre quadros TIFF — todos esses desaparecem. using var input = new OcrInput() é o padrão completo de gerenciamento de recursos. As revisões de código são mais curtas. A integração de novos desenvolvedores ao serviço de OCR leva menos tempo. A documentação de referência da API OcrResult apresenta o modelo completo do objeto de resultado, incluindo dados estruturados, pontuações de confiança e saída em PDF pesquisável, que substituem os padrões de manipulação manual de resultados do SDK legado.
O suporte comercial substitui a dependência de um único desenvolvedor. O SDK .NET do Tesseract é operado por um desenvolvedor individual, sem SLA e sem garantia de continuidade organizacional. O IronOCR é desenvolvido pela Iron Software, uma entidade comercial com canais de suporte dedicados, processos documentados de divulgação de segurança e termos de licenciamento que atendem aos requisitos de aquisição Enterprise . A página de licenciamento do IronOCR cobre níveis de suporte e o modelo de licença perpétua (de $999) que substitui tanto a taxa do SDK Patagames quanto o custo oculto de manutenção de infraestrutura exclusivamente Windows em uma stack .NET em modernização.
