IRONSOFTWAREHOME
VÍDEOS

Como realizar OCR no NET Maui

Kannaopat Udonpant
Kannapat Udonpant
Updated: 28 de junho de 2026

Este guia orienta os desenvolvedores .NET em uma migração completa do OCR do Leadtools para o IronOCR . Abrange todas as etapas, desde a substituição de pacotes NuGet até a migração completa do código, com exemplos de antes e depois para os padrões mais afetados pela inicialização do LEADTOOLS, pela estrutura de múltiplos namespaces e pelo modelo de implantação de licenças baseado em arquivos.

Por que migrar do OCR da LEADTOOLS?

O OCR do Leadtools é fornecido dentro de uma plataforma de imagem Enterprise com raízes que remontam a 1990, e a API reflete essa linhagem. A configuração mínima de funcionamento requer quatro pacotes NuGet , quatro namespaces, dois arquivos de licença física implantados em um caminho conhecido, uma camada de codec inicializada antes do mecanismo, a seleção de um tipo de mecanismo entre três opções e uma chamada de inicialização bloqueante que carrega os binários de tempo de execução na memória. Tudo isso ocorre antes que um único caractere seja reconhecido. As equipes que migram para o IronOCR eliminam toda essa camada — um pacote, um namespace, uma linha para definir uma chave de licença.

Implantação de Licença Baseada em Arquivo Falha em Contêineres. LEADTOOLS requer dois arquivos físicos — LEADTOOLS.LIC e LEADTOOLS.LIC.KEY — legíveis em um caminho específico em cada máquina que executa o aplicativo. Em contêineres Docker, esses arquivos devem ser incorporados à imagem (expondo-os no histórico de camadas) ou montados em tempo de execução (exigindo coordenação de volumes em cada ambiente de orquestração). O Azure Functions e o AWS Lambda não possuem um mecanismo para implantação de arquivos de licença sem soluções alternativas. Os pipelines de CI/CD precisam que os arquivos estejam presentes exatamente no caminho usado pela chamada de inicialização; caso contrário, o aplicativo gera um erro antes de processar um único documento. O IronOCR substitui ambos os arquivos por uma string que se encaixa em uma variável de ambiente, um segredo do Kubernetes ou uma referência do Azure Key Vault.

Quatro Pacotes para Uma Tarefa. Um projeto OCR do Leadtools funcional requer Leadtools, Leadtools.Ocr, Leadtools.Codecs, e Leadtools.Forms.DocumentWriters no mínimo. O suporte a PDFs protegidos por senha requer um módulo adicional Leadtools.Pdf que pode não estar incluído no pacote comprado. Cada pacote deve estar presente, ser compatível e ter a mesma versão. O IronOCR é distribuído como um único pacote NuGet . Todas as funcionalidades — entrada nativa de PDF, saída de PDF pesquisável, pré-processamento, leitura de código de barras — estão incluídas.

O Ciclo de Vida do Motor Cria uma Superfície de Manutenção. LEADTOOLS envolve o motor OCR em uma classe de serviço IDisposable não por razões idiomáticas do .NET, mas porque a chamada Shutdown() deve preceder Dispose() ou o aplicativo produz erros. Implementações de produção de processadores de lote do LEADTOOLS normalmente incluem chamadas GC.Collect() / GC.WaitForPendingFinalizers() entre pedaços de documentos para compensar instâncias RasterImage que se acumulam.IronOCR usa blocos padrão using. OcrInput é o único objeto que precisa de descarte.

Confusão sobre pacotes surge na produção. A LEADTOOLS não divulga preços publicamente. O SDK de Imagens de Documentos — o nível que inclui OCR — custa aproximadamente de US$ 3.000 a US$ 8.000 por desenvolvedor por ano. Equipes que compraram o módulo OCR sem o módulo PDF descobrem a lacuna quando RasterSupport.IsLocked() retorna verdadeiro contra documentos protegidos por senha em produção. O nível de precisão do mecanismo OmniPage requer um contrato de licença Kofax separado, além da compra do LEADTOOLS. A IronOCR licencia todos os recursos em cada nível. Não existe relacionamento com fornecedores secundários, nem módulo separado para documentos criptografados.

Custo de Inicialização Afeta Partidas Frias. engine.Startup() é uma chamada bloqueante que carrega arquivos de execução para a memória. Em ambientes sem servidor onde a latência de inicialização a frio é importante — Azure Functions, AWS Lambda — uma inicialização bloqueante de 500 a 2000 ms antes que qualquer trabalho de reconhecimento ocorra é um problema estrutural. O IronOCR utiliza inicialização preguiçosa. A instância IronTesseract inicializa no primeiro uso, e chamadas subsequentes dentro do mesmo processo não pagam nenhum custo de inicialização.

O problema fundamental

O LEADTOOLS requer quatro namespaces, quatro pacotes NuGet e uma cerimônia de inicialização obrigatória antes que um caractere seja reconhecido:

// LEADTOOLS: Four namespaces, four packages, six steps before recognition
using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;
using Leadtools.Forms.DocumentWriters;

RasterSupport.SetLicense(licPath, File.ReadAllText(keyPath)); // Step 1: two files on disk
var codecs = new RasterCodecs();                              // Step 2: codec layer
var engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD); // Step 3: engine factory
engine.Startup(codecs, null, null, runtimePath);              // Step 4: blocking startup
// ... still need to create document, add page, call Recognize(), extract text
C#
// IronOCR: One namespace, one package, one line
using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var text = new IronTesseract().Read("document.jpg").Text;
C#

##IronOCR vs. LEADTOOLS OCR: Comparação de Recursos

A tabela a seguir mapeia diretamente as funcionalidades entre as duas bibliotecas.

RecursoOCR do LeadtoolsIronOCR
Pacotes NuGet necessáriosMínimo de 4 (mais para PDF)1 (IronOcr)
Mecanismo de licenciamento.LIC + .LIC.KEY par de arquivosChave de string
Implantação de licençaArquivos em todas as máquinas de produçãoVariável de ambiente ou configuração
Modelo de preçosUS$ 3.000 a US$ 15.000+ por desenvolvedor por ano (estimativa)$999–$2.999 único perpétuo
Inicialização do motorManual Startup() com caminho de execuçãoAutomático, preguiçoso
Desligamento do motorManual Shutdown() antes de Dispose()Não é necessário
Camada de codecRasterCodecs necessário para todo carregamento de imagemNão é necessário
Entrada de PDFLoop de rasterização página por páginaNativo LoadPdf()
PDF protegido por senhaRequer módulo Leadtools.Pdf separadoParâmetro embutido Password
Saída em PDF pesquisávelDocumentWriter + PdfDocumentOptions + document.Save()result.SaveAsSearchablePdf()
Pré-processamentoClasses de comando separadas (DeskewCommand, DespeckleCommand, etc.)Métodos de filtro embutidos em OcrInput
TIFF de várias páginasIteração manual de quadro com CodecsLoadByteOrderinput.LoadImageFrames()
Saída estruturadaNível de página e zonaPágina, parágrafo, linha, palavra, caractere com coordenadas
Pontuação de confiançaOcrPageRecognizeStatus enumresult.Confidence como percentual
Leitura de código de barrasMódulo de código de barras LEADTOOLS separadoEmbutido (ReadBarCodes = true)
Segurança da roscaRequer gestão cuidadosaCompleto (um IronTesseract por thread)
Idiomas suportados60–120 (dependendo do motor)Mais de 125 idiomas disponíveis via pacotes NuGet
Implantação de idiomastessdata files or engine-bundled filesPacote NuGet por idioma
MultiplataformaCompatível com configuração de tempo de execução por plataforma.Windows, Linux, macOS, Docker, Azure, AWS
Implantação do DockerArquivos .KEY devem ser montados ou incorporadosPadrão dotnet publish
Apoio comercialSimSim

Guia rápido: Migração do OCR do LEADTOOLS para o IronOCR

Passo 1: Substitua o pacote NuGet

Remova todos os pacotes LEADTOOLS:

dotnet remove package Leadtools
dotnet remove package Leadtools.Ocr
dotnet remove package Leadtools.Codecs
dotnet remove package Leadtools.Forms.DocumentWriters
dotnet remove package Leadtools.Pdf
SHELL

Instale o IronOCR a partir do NuGet :

dotnet add package IronOcr

Etapa 2: Atualizar Namespaces

Substitua todas as diretivas LEADTOOLS using por uma única importação IronOCR:

// Before (LEADTOOLS)
using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;
using Leadtools.Forms.DocumentWriters;

// After (IronOCR)
using IronOcr;
C#

Etapa 3: Inicializar a licença

Remova todas as chamadas RasterSupport.SetLicense() e as referências aos arquivos .LIC / .LIC.KEY. Adicione a chave de licença do IronOCR na inicialização do aplicativo:

// Single line replaces the entire file-based license setup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

// Production pattern: pull from environment variable or secrets manager
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE");
C#

A chave de licença pode ser armazenada em qualquer padrão de gerenciamento de segredos .NET padrão — appsettings.json, Azure Key Vault, AWS Secrets Manager, ou um segredo Kubernetes. Não é necessário implantar nenhum arquivo junto com o binário do aplicativo.

Exemplos de migração de código

Remoção do ciclo de vida de inicialização e desligamento do motor

O LEADTOOLS exige um padrão rígido de classe de serviço porque o ciclo de vida do mecanismo deve ser gerenciado explicitamente. O construtor inicia o motor, Dispose() o desliga na ordem correta, e qualquer caminho de código que pule Shutdown() antes de Dispose() produz um erro de execução.

Abordagem OCR do LEADTOOLS:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

// Service class required purely to manage engine lifecycle
public class LeadtoolsOcrService : IDisposable
{
    private IOcrEngine _engine;
    private RasterCodecs _codecs;
    private readonly string _runtimePath;

    public LeadtoolsOcrService(string licPath, string keyPath, string runtimePath)
    {
        _runtimePath = runtimePath;

        // License setup — two files, both must be present
        RasterSupport.SetLicense(licPath, File.ReadAllText(keyPath));

        // Codec layer — required before engine creation
        _codecs = new RasterCodecs();

        // Engine factory — engine type determines capability and cost
        _engine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD);

        // Blocking startup — loads runtime into memory (500–2000ms)
        _engine.Startup(_codecs, null, null, _runtimePath);
    }

    public bool IsReady => _engine?.IsStarted ?? false;

    public string Process(string imagePath)
    {
        if (!IsReady)
            throw new InvalidOperationException("Engine not started");

        using var image = _codecs.Load(imagePath);
        using var doc = _engine.DocumentManager.CreateDocument();
        var page = doc.Pages.AddPage(image, null);
        page.Recognize(null);
        return page.GetText(-1);
    }

    public void Dispose()
    {
        // Order is mandatory: Shutdown before Dispose
        if (_engine?.IsStarted == true)
            _engine.Shutdown();

        _engine?.Dispose();
        _codecs?.Dispose();
    }
}
C#

Abordagem IronOCR:

using IronOcr;

// No lifecycle management needed — the service class becomes trivial
public class OcrService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    // Always ready — no IsStarted check needed
    public string Process(string imagePath) => _ocr.Read(imagePath).Text;

    // No Dispose() needed for the engine
    // No Startup(), no Shutdown(), no codec layer
}
C#

A instância IronTesseract inicializa no primeiro uso. Sem argumentos de construtor, sem caminho de execução, sem chamada Startup(). A classe de serviço acima não precisa implementar IDisposable de forma alguma — o motor é sem estado e os objetos OcrInput usados dentro de cada chamada Read() lidam com sua própria limpeza através do padrão using padrão. O guia de configuração do IronTesseract aborda opções de configuração, incluindo seleção de idioma e otimização de desempenho para cenários de produção.

Processamento em lote de TIFF com múltiplos quadros

LEADTOOLS processa arquivos TIFF com múltiplos quadros consultando o codec para a contagem total de quadros, depois iterando com parâmetros explícitos lastPage em cada chamada _codecs.Load(). Cada imagem de quadro deve ser descartada manualmente, caso contrário, a memória se acumula.

Abordagem OCR do LEADTOOLS:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsTiffBatchService
{
    private readonly IOcrEngine _engine;
    private readonly RasterCodecs _codecs;

    public List<string> ProcessMultiFrameTiff(string tiffPath)
    {
        var pageTexts = new List<string>();

        // Must query page count before iterating
        var info = _codecs.GetInformation(tiffPath, true);
        int frameCount = info.TotalPages;

        using var document = _engine.DocumentManager.CreateDocument();

        for (int frameNum = 1; frameNum <= frameCount; frameNum++)
        {
            // Load one frame at a time — must specify firstPage/lastPage
            using var frameImage = _codecs.Load(
                tiffPath,
                0,                            // bitsPerPixel
                CodecsLoadByteOrder.BgrOrGray,
                frameNum,                     // firstPage
                frameNum);                    // lastPage

            var page = document.Pages.AddPage(frameImage, null);
            page.Recognize(null);
            pageTexts.Add(page.GetText(-1));

            // GC pressure accumulates if disposal is missed on any frame
        }

        return pageTexts;
    }

    public Dictionary<string, List<string>> ProcessTiffDirectory(string directoryPath)
    {
        var results = new Dictionary<string, List<string>>();

        foreach (var tiffFile in Directory.GetFiles(directoryPath, "*.tiff"))
        {
            results[tiffFile] = ProcessMultiFrameTiff(tiffFile);

            // Manual GC between files to prevent memory growth
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        return results;
    }
}
C#

Abordagem IronOCR:

using IronOcr;

public class TiffBatchService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public List<string> ProcessMultiFrameTiff(string tiffPath)
    {
        using var input = new OcrInput();
        input.LoadImageFrames(tiffPath);  // All frames loaded automatically

        var result = _ocr.Read(input);

        // Per-frame text available through result.Pages
        return result.Pages.Select(p => p.Text).ToList();
    }

    public Dictionary<string, List<string>> ProcessTiffDirectory(string directoryPath)
    {
        var results = new Dictionary<string, List<string>>();

        foreach (var tiffFile in Directory.GetFiles(directoryPath, "*.tiff"))
        {
            results[tiffFile] = ProcessMultiFrameTiff(tiffFile);
        }

        return results;
    }

    // Parallel processing across files — thread-safe out of the box
    public Dictionary<string, List<string>> ProcessTiffDirectoryParallel(string directoryPath)
    {
        var concurrentResults = new System.Collections.Concurrent.ConcurrentDictionary<string, List<string>>();
        var tiffFiles = Directory.GetFiles(directoryPath, "*.tiff");

        Parallel.ForEach(tiffFiles, tiffFile =>
        {
            using var input = new OcrInput();
            input.LoadImageFrames(tiffFile);
            var result = new IronTesseract().Read(input);
            concurrentResults[tiffFile] = result.Pages.Select(p => p.Text).ToList();
        });

        return new Dictionary<string, List<string>>(concurrentResults);
    }
}
C#

LoadImageFrames() lê todos os quadros do TIFF em uma única chamada. Sem consulta de contagem de quadros, sem loop, sem descarte explícito por quadro. A versão paralela cria uma instância IronTesseract por thread, que é o padrão correto — veja o exemplo de multithreading para o modelo completo de threading. Para opções de entrada específicas para TIFF, o guia de entrada TIFF e GIF aborda a seleção de quadros e o processamento de múltiplos formatos.

Simplificação do fluxo de trabalho do redator de documentos

A criação de PDF pesquisável do LEADTOOLS requer a configuração de uma instância DocumentWriter no motor, construindo um objeto PdfDocumentOptions com tipo de saída e configurações de sobreposição, aplicando as opções via SetOptions(), e então chamando document.Save() com o enum de formato. Cada uma dessas etapas é um objeto separado e uma chamada de API separada.

Abordagem OCR do LEADTOOLS:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;
using Leadtools.Forms.DocumentWriters;

public class LeadtoolsDocumentWriterService
{
    private readonly IOcrEngine _engine;
    private readonly RasterCodecs _codecs;

    public void CreateSearchablePdfFromImages(string[] imagePaths, string outputPath)
    {
        using var document = _engine.DocumentManager.CreateDocument();

        foreach (var imagePath in imagePaths)
        {
            using var image = _codecs.Load(imagePath);
            var page = document.Pages.AddPage(image, null);
            page.Recognize(null);
        }

        // DocumentWriter configuration — four properties to set before save
        var pdfOptions = new PdfDocumentOptions
        {
            DocumentType = PdfDocumentType.Pdf,
            ImageOverText = true,     // Image layer visible, text layer searchable
            Linearized = false,
            Title = "Searchable Output"
        };

        // Apply options to the engine's writer instance
        _engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);

        // Save with format enum — the format must match the options set above
        document.Save(outputPath, DocumentFormat.Pdf, null);
    }

    public void CreateSearchablePdfFromPdf(string inputPdfPath, string outputPath)
    {
        var pdfInfo = _codecs.GetInformation(inputPdfPath, true);
        using var document = _engine.DocumentManager.CreateDocument();

        for (int i = 1; i <= pdfInfo.TotalPages; i++)
        {
            using var pageImage = _codecs.Load(inputPdfPath, 0,
                CodecsLoadByteOrder.BgrOrGray, i, i);

            var page = document.Pages.AddPage(pageImage, null);
            page.Recognize(null);
        }

        var pdfOptions = new PdfDocumentOptions
        {
            DocumentType = PdfDocumentType.Pdf,
            ImageOverText = true,
            Title = Path.GetFileNameWithoutExtension(inputPdfPath)
        };

        _engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);
        document.Save(outputPath, DocumentFormat.Pdf, null);
    }
}
C#

Abordagem IronOCR:

using IronOcr;

public class SearchablePdfService
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public void CreateSearchablePdfFromImages(string[] imagePaths, string outputPath)
    {
        using var input = new OcrInput();
        foreach (var imagePath in imagePaths)
            input.LoadImage(imagePath);

        var result = _ocr.Read(input);
        result.SaveAsSearchablePdf(outputPath);  // DocumentWriter pipeline: gone
    }

    public void CreateSearchablePdfFromPdf(string inputPdfPath, string outputPath)
    {
        using var input = new OcrInput();
        input.LoadPdf(inputPdfPath);

        var result = _ocr.Read(input);
        result.SaveAsSearchablePdf(outputPath);
    }

    // Get bytes directly — useful for streaming responses in ASP.NET
    public byte[] CreateSearchablePdfBytes(string inputPdfPath)
    {
        using var input = new OcrInput();
        input.LoadPdf(inputPdfPath);
        return _ocr.Read(input).SaveAsSearchablePdfBytes();
    }
}
C#

SaveAsSearchablePdf() substitui toda a cadeia PdfDocumentOptions + SetOptions() + document.Save(). O comportamento da camada de imagem sobre texto é automático. Para obter documentação completa sobre a saída de PDFs pesquisáveis, o guia prático de PDFs pesquisáveis ​​aborda as opções de saída e o exemplo de PDF pesquisável mostra a integração com fluxos de resposta do ASP.NET .

Migração de extração de campo multizona

O OCR baseado em zona do LEADTOOLS usa objetos OcrZone com limites LeadRect, OcrZoneType, e propriedades OcrZoneCharacterFilters. Várias zonas são adicionadas a uma única página e reconhecidas em uma chamada page.Recognize(), depois extraídas pelo índice da zona. O índice da zona corresponde à ordem de inserção, o que significa que o loop de extração deve manter essa ordem.

Abordagem OCR do LEADTOOLS:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsFormFieldExtractor
{
    private readonly IOcrEngine _engine;
    private readonly RasterCodecs _codecs;

    // Invoice field extraction using named zones
    public InvoiceFields ExtractInvoiceFields(string invoicePath)
    {
        using var image = _codecs.Load(invoicePath);
        using var document = _engine.DocumentManager.CreateDocument();
        var page = document.Pages.AddPage(image, null);

        // Must clear auto-detected zones before adding custom ones
        page.Zones.Clear();

        // Zone definitions — index order matters for extraction
        var zoneDefinitions = new[]
        {
            new { Name = "InvoiceNumber", X = 450, Y = 80,  W = 200, H = 30 },
            new { Name = "InvoiceDate",   X = 450, Y = 115, W = 200, H = 30 },
            new { Name = "VendorName",    X = 50,  Y = 150, W = 300, H = 40 },
            new { Name = "TotalAmount",   X = 450, Y = 600, W = 200, H = 30 }
        };

        foreach (var def in zoneDefinitions)
        {
            var zone = new OcrZone
            {
                Bounds = new LeadRect(def.X, def.Y, def.W, def.H),
                ZoneType = OcrZoneType.Text,
                CharacterFilters = OcrZoneCharacterFilters.None,
                RecognitionModule = OcrZoneRecognitionModule.Auto
            };
            page.Zones.Add(zone);
        }

        page.Recognize(null);

        // Extract by index — must match insertion order exactly
        return new InvoiceFields
        {
            InvoiceNumber = page.Zones[0].Text?.Trim(),
            InvoiceDate   = page.Zones[1].Text?.Trim(),
            VendorName    = page.Zones[2].Text?.Trim(),
            TotalAmount   = page.Zones[3].Text?.Trim()
        };
    }
}

public class InvoiceFields
{
    public string InvoiceNumber { get; set; }
    public string InvoiceDate   { get; set; }
    public string VendorName    { get; set; }
    public string TotalAmount   { get; set; }
}
C#

Abordagem IronOCR:

using IronOcr;

public class FormFieldExtractor
{
    private readonly IronTesseract _ocr = new IronTesseract();

    // Each field gets its own CropRectangle-scoped Read() call
    // No zone index management, no zone ordering dependency
    public InvoiceFields ExtractInvoiceFields(string invoicePath)
    {
        return new InvoiceFields
        {
            InvoiceNumber = ReadRegion(invoicePath, 450, 80,  200, 30),
            InvoiceDate   = ReadRegion(invoicePath, 450, 115, 200, 30),
            VendorName    = ReadRegion(invoicePath, 50,  150, 300, 40),
            TotalAmount   = ReadRegion(invoicePath, 450, 600, 200, 30)
        };
    }

    private string ReadRegion(string imagePath, int x, int y, int width, int height)
    {
        using var input = new OcrInput();
        input.LoadImage(imagePath, new CropRectangle(x, y, width, height));
        return _ocr.Read(input).Text.Trim();
    }

    // Batch: extract the same field from many invoices in parallel
    public Dictionary<string, string> ExtractInvoiceNumbersBatch(string[] invoicePaths)
    {
        var results = new System.Collections.Concurrent.ConcurrentDictionary<string, string>();

        Parallel.ForEach(invoicePaths, invoicePath =>
        {
            using var input = new OcrInput();
            input.LoadImage(invoicePath, new CropRectangle(450, 80, 200, 30));
            results[invoicePath] = new IronTesseract().Read(input).Text.Trim();
        });

        return new Dictionary<string, string>(results);
    }
}
C#

CropRectangle passado diretamente para LoadImage() substitui toda a configuração OcrZone. Não há índice de zona para rastrear, nenhuma chamada page.Zones.Clear() necessária, e nenhuma verificação de status de reconhecimento necessária. O guia de OCR baseado em regiões abrange padrões de extração de região única e de múltiplas regiões. Para um tutorial completo sobre extração de campos de faturas, consulte o tutorial de OCR de faturas .

Extração de dados estruturados com coordenadas de palavras

A saída estruturada do LEADTOOLS opera nos níveis de página e zona. Para obter dados ao nível de palavra com coordenadas da caixa delimitadora, o desenvolvedor acessa objetos OcrWord de dentro de uma zona reconhecida. A API exige que se trabalhe com a coleção de zonas após o reconhecimento e que se itere a lista de palavras por zona.

Abordagem OCR do LEADTOOLS:

using Leadtools;
using Leadtools.Ocr;
using Leadtools.Codecs;

public class LeadtoolsStructuredExtractor
{
    private readonly IOcrEngine _engine;
    private readonly RasterCodecs _codecs;

    public List<WordLocation> ExtractWordsWithLocations(string imagePath)
    {
        var wordLocations = new List<WordLocation>();

        using var image = _codecs.Load(imagePath);
        using var document = _engine.DocumentManager.CreateDocument();
        var page = document.Pages.AddPage(image, null);
        page.Recognize(null);

        // Access words through the zone collection
        foreach (OcrZone zone in page.Zones)
        {
            foreach (OcrWord word in zone.Words)
            {
                wordLocations.Add(new WordLocation
                {
                    Text       = word.Value,
                    X          = word.Bounds.X,
                    Y          = word.Bounds.Y,
                    Width      = word.Bounds.Width,
                    Height     = word.Bounds.Height,
                    Confidence = word.Confidence
                });
            }
        }

        return wordLocations;
    }
}

public class WordLocation
{
    public string Text       { get; set; }
    public int    X          { get; set; }
    public int    Y          { get; set; }
    public int    Width      { get; set; }
    public int    Height     { get; set; }
    public int    Confidence { get; set; }
}
C#

Abordagem IronOCR:

using IronOcr;

public class StructuredExtractor
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public List<WordLocation> ExtractWordsWithLocations(string imagePath)
    {
        var result = _ocr.Read(imagePath);

        // Five-level hierarchy: Pages > Paragraphs > Lines > Words > Characters
        return result.Pages
            .SelectMany(page => page.Paragraphs)
            .SelectMany(para => para.Lines)
            .SelectMany(line => line.Words)
            .Select(word => new WordLocation
            {
                Text       = word.Text,
                X          = word.X,
                Y          = word.Y,
                Width      = word.Width,
                Height     = word.Height,
                Confidence = (int)word.Confidence
            })
            .ToList();
    }

    // Paragraph-level extraction with position data
    public void PrintDocumentStructure(string imagePath)
    {
        var result = _ocr.Read(imagePath);
        Console.WriteLine($"Document confidence: {result.Confidence}%");

        foreach (var page in result.Pages)
        {
            Console.WriteLine($"Page {page.PageNumber}:");
            foreach (var paragraph in page.Paragraphs)
            {
                Console.WriteLine($"  Paragraph at ({paragraph.X}, {paragraph.Y}):");
                Console.WriteLine($"  {paragraph.Text}");
            }
        }
    }
}
C#

A hierarquia de resultados do IronOCR desce de Pages através de Paragraphs, Lines, Words, e Characters. Cada nível expõe X, Y, Width, Height, Text, e Confidence. O padrão de acesso baseado em zonas do LEADTOOLS desaparece — nenhuma iteração de zona é necessária para acessar os dados das palavras. O guia prático de leitura de resultados abrange o modelo de saída completo com padrões de acesso a coordenadas. A documentação de referência da API OcrResult descreve todas as propriedades da hierarquia de resultados.

Referência de mapeamento da API OCR da LEADTOOLS para o IronOCR

OCR do LeadtoolsIronOCR
RasterSupport.SetLicense(licPath, keyContent)IronOcr.License.LicenseKey = "key"
new RasterCodecs()Não é necessário
OcrEngineManager.CreateEngine(OcrEngineType.LEAD)new IronTesseract()
engine.Startup(codecs, null, null, runtimePath)Não é necessário
engine.IsStartedNão é necessário (sempre pronto)
engine.Shutdown()Não é necessário
engine.Dispose()Não é necessário
_codecs.Load(imagePath)input.LoadImage(imagePath)
_codecs.Load(path, 0, BgrOrGray, page, page)input.LoadPdf(path) or input.LoadImageFrames(path)
_codecs.GetInformation(path, true).TotalPagesNão é necessário — automático
engine.DocumentManager.CreateDocument()Não é necessário
document.Pages.AddPage(image, null)input.LoadImage(imagePath)
page.Recognize(null)ocr.Read(input) (o reconhecimento faz parte de Read())
page.GetText(-1)result.Text
page.RecognizeStatusresult.Confidence (porcentagem)
OcrZone { Bounds = new LeadRect(x, y, w, h) }new CropRectangle(x, y, w, h)
page.Zones.Clear()Não é necessário
page.Zones.Add(zone)input.LoadImage(path, cropRect)
zone.Words / word.Boundsresult.Pages[n].Words / word.X, word.Y
DeskewCommand().Run(image)input.Deskew()
DespeckleCommand().Run(image)input.DeNoise()
AutoBinarizeCommand().Run(image)input.Binarize()
ContrastBrightnessCommand().Run(image)input.Contrast()
new PdfDocumentOptions { ImageOverText = true }Manipulado automaticamente por SaveAsSearchablePdf()
engine.DocumentWriterInstance.SetOptions(format, opts)Não é necessário
document.Save(path, DocumentFormat.Pdf, null)result.SaveAsSearchablePdf(path)
_codecs.Options.Pdf.Load.Password = passwordinput.LoadPdf(path, Password: password)
RasterSupport.IsLocked(RasterSupportType.Document)IronOcr.License.IsLicensed

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

Problema 1: Falhas na resolução do caminho do arquivo de licença

LEADTOOLS: RasterSupport.SetLicense() resolve os caminhos de arquivo .LIC e .LIC.KEY relativos ao diretório de trabalho, que difere entre bin/Debug, bin/Release, contêineres Docker, e pools de aplicativos IIS. Um modo comum de falha é um caminho que funciona em desenvolvimento, mas lança "License file not found" em produção porque o diretório de trabalho mudou.

Solução: Apague ambos os arquivos de licença e a chamada SetLicense() inteiramente. Substitua por uma atribuição de string única que lê de uma variável de ambiente:

// Remove this:
// RasterSupport.SetLicense(licPath, File.ReadAllText(keyPath));

// Replace with this:
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE")
    ?? throw new InvalidOperationException("IRONOCR_LICENSE environment variable not set");
C#

A chave de string se comporta da mesma forma em todos os ambientes. Armazene-o no mesmo gerenciador de segredos já utilizado para as strings de conexão do banco de dados.

Problema 2: Exceção de motor não iniciado

LEADTOOLS: Chamar qualquer método de reconhecimento antes que engine.Startup() seja concluído, ou depois que engine.Shutdown() tenha sido chamado (por exemplo, em uma condição de corrida de descarte antes de uso durante o desligamento), lança um InvalidOperationException com "Engine not started." As classes de serviço de longa duração devem se proteger contra isso com verificações IsStarted.

Solução: IronTesseract não requer chamada de inicialização e não tem estado iniciado/parado. O guardião IsStarted e toda a classe de serviço de ciclo de vida podem ser deletados:

// Remove the guard:
// if (!_engine.IsStarted)
//     throw new InvalidOperationException("Engine not started");

// IronTesseract is always ready — just call Read()
var result = _ocr.Read(imagePath);
C#

Problema 3: Acumulação de memória de imagens raster no processamento em lote

LEADTOOLS: O processamento em lote que itera sobre páginas de PDF ou arquivos de imagem cria instâncias RasterImage em um loop. Se qualquer caminho de código falhar em descartar um RasterImage — devido a uma exceção lançada antes que o bloco using saia ou um padrão de descarte manual com uma chamada ausente — as imagens não liberadas se acumulam na memória. O código de produção do LEADTOOLS comumente inclui chamadas GC.Collect() / GC.WaitForPendingFinalizers() entre lotes como um mecanismo compensatório.

Solução: Remova todas as chamadas GC.Collect(). OcrInput é o único IDisposable no pipeline do IronOCR, e é restrito a cada operação em lote com um bloco padrão using:

// Remove this pattern:
// GC.Collect();
// GC.WaitForPendingFinalizers();

// Replace with standard using scope:
foreach (var filePath in filePaths)
{
    using var input = new OcrInput();
    input.LoadImage(filePath);
    var text = _ocr.Read(input).Text;
    // input disposed here — no accumulation
}
C#

Para obter orientações adicionais sobre otimização de memória, consulte a postagem do blog sobre redução de alocação de memória .

Problema 4: As opções da instância DocumentWriter persistem entre chamadas

LEADTOOLS: engine.DocumentWriterInstance.SetOptions() modifica o estado na instância de escritor compartilhada do motor. Se um caminho de código define PdfDocumentOptions com DocumentType = PdfDocumentType.PdfA e uma chamada subsequente não redefinir essas opções antes de chamar document.Save(), o formato de saída da chamada anterior persiste. Este é um efeito colateral com estado na instância do mecanismo compartilhado.

Solução: O IronOCR não possui estado de gravação compartilhado. Cada chamada SaveAsSearchablePdf() é independente:

// Remove the options setup:
// var pdfOptions = new PdfDocumentOptions { ... };
// _engine.DocumentWriterInstance.SetOptions(DocumentFormat.Pdf, pdfOptions);
// document.Save(outputPath, DocumentFormat.Pdf, null);

// Replace with:
result.SaveAsSearchablePdf(outputPath);
C#

Cada chamada gera um arquivo PDF padrão com uma imagem sobreposta e uma camada de texto pesquisável. Não existe um estado de opções compartilhado para redefinir entre chamadas.

Problema 5: Pacote incorreto — Módulo ausente em tempo de execução

LEADTOOLS: Equipes que compraram o Document Imaging SDK podem descobrir que os tipos Leadtools.Pdf estão indisponíveis ou que páginas de PDF criptografadas lançam RasterException com RasterExceptionCode.FeatureNotSupported. Isso ocorre quando o pacote adquirido não inclui o módulo PDF, e o erro só aparece em tempo de execução em produção.

Solução: O IronOCR inclui todos os recursos em todos os níveis de licença. Não há módulo PDF separado, nenhum complemento para documentos criptografados, e nenhum fornecedor secundário para um motor de maior precisão. Após instalar o pacote único IronOcr, o conjunto completo de recursos está disponível sem qualquer compra adicional:

dotnet add package IronOcr

Problema 6: Incompatibilidade do índice de zona após reordenação

LEADTOOLS: A extração de zona usa indexação posicional — page.Zones[0].Text, page.Zones[1].Text — que vincula a lógica de extração à ordem de inserção em page.Zones.Add(). Reordenar as definições de zona para corresponder a um layout de formulário alterado interrompe silenciosamente a extração, deslocando todos os índices subsequentes.

**Solução:**IronOCR usa variáveis nomeadas com CropRectangle por campo. Reordenar as definições de campo não afeta a extração, pois cada campo possui escopo independente:

// Each field is independent — reorder freely without breaking extraction
var invoiceNumber = ReadRegion(imagePath, 450, 80,  200, 30);
var invoiceDate   = ReadRegion(imagePath, 450, 115, 200, 30);
var vendorName    = ReadRegion(imagePath, 50,  150, 300, 40);
var totalAmount   = ReadRegion(imagePath, 450, 600, 200, 30);
C#

Lista de verificação para migração de OCR do LEADTOOLS

Pré-migração

Antes de fazer qualquer alteração, audite o código-fonte para identificar todo o uso do LEADTOOLS:

# Find all LEADTOOLS namespace imports
grep -rn "using Leadtools" --include="*.cs" .

# Find engine lifecycle calls
grep -rn "OcrEngineManager\|\.Startup(\|\.Shutdown()" --include="*.cs" .

# Find license file references
grep -rn "SetLicense\|LEADTOOLS\.LIC\|\.LIC\.KEY" --include="*.cs" .

# Find RasterCodecs usage
grep -rn "RasterCodecs\|_codecs\.Load\|GetInformation" --include="*.cs" .

# Find DocumentWriter usage
grep -rn "DocumentWriterInstance\|PdfDocumentOptions\|DocumentFormat\." --include="*.cs" .

# Find zone-based OCR
grep -rn "OcrZone\|page\.Zones\|LeadRect\|ZoneType" --include="*.cs" .

# Find GC workarounds to remove
grep -rn "GC\.Collect\|WaitForPendingFinalizers" --include="*.cs" .
SHELL

Anote qual pacote do LEADTOOLS foi adquirido — módulo OCR, módulo PDF e tipo de mecanismo (LEAD vs Tesseract vs OmniPage) — para garantir que os recursos equivalentes do IronOCR sejam testados durante a validação pós-migração.

Migração de código

  1. Remova todos os pacotes NuGet do LEADTOOLS: Leadtools, Leadtools.Ocr, Leadtools.Codecs, Leadtools.Forms.DocumentWriters, Leadtools.Pdf
  2. Instale o pacote NuGet IronOcr
  3. Substitua todas as diretivas LEADTOOLS using por using IronOcr;
  4. Remova os arquivos .LIC e .LIC.KEY do projeto e dos artefatos de implantação
  5. Substitua RasterSupport.SetLicense(licPath, keyContent) por IronOcr.License.LicenseKey = "key" na inicialização do aplicativo
  6. Exclua todas as classes de serviço IDisposable que existem apenas para gerenciar o ciclo de vida IOcrEngine e RasterCodecs
  7. Substitua OcrEngineManager.CreateEngine() + engine.Startup() por new IronTesseract()
  8. Substitua _codecs.Load(imagePath) por input.LoadImage(imagePath) dentro de um bloco using var input = new OcrInput()
  9. Substitua os loops de página TIFF de múltiplos quadros por input.LoadImageFrames(tiffPath)
  10. Substitua o loop de iteração de página PDF por input.LoadPdf(pdfPath)
  11. Substitua document.Pages.AddPage() + page.Recognize(null) + page.GetText(-1) por ocr.Read(input).Text
  12. Substitua padrões OcrZone + page.Zones.Add() por input.LoadImage(path, new CropRectangle(x, y, w, h))
  13. Substitua PdfDocumentOptions + DocumentWriterInstance.SetOptions() + document.Save() por result.SaveAsSearchablePdf(path)
  14. Substitua classes de comando de pré-processamento (DeskewCommand, DespeckleCommand, AutoBinarizeCommand) por input.Deskew(), input.DeNoise(), input.Binarize() na instânciaOcrInput
  15. Remova todas as chamadas GC.Collect() / GC.WaitForPendingFinalizers() adicionadas para compensar o gerenciamento de memória do LEADTOOLS

Pós-migração

  • Verificar se o texto reconhecido corresponde à saída do LEADTOOLS em uma amostra representativa de imagens e PDFs.
  • Confirme se as pontuações de confiança estão dentro dos intervalos esperados usando result.Confidence
  • O teste de processamento TIFF com múltiplos quadros produz o mesmo número de páginas que o loop de iteração de quadros do LEADTOOLS.
  • Validar se o PDF pesquisável permite a busca de texto em um leitor de PDF (Adobe Acrobat ou equivalente)
  • Testar a extração de campos baseada em zonas comparando-a com valores de campos confiáveis ​​provenientes de faturas ou formulários de produção.
  • Verifique se a descriptografia de PDF protegido por senha funciona sem o módulo Leadtools.Pdf separado
  • Execute o processamento em lote sob carga e confirme se não há crescimento de memória (remova todos os GC.Collect() primeiro)
  • Teste a implantação do Docker e do CI/CD sem arquivos de licença — confirme se a chave de licença (string) é resolvida corretamente a partir da variável de ambiente.
  • Teste o processamento paralelo com Parallel.ForEach para verificar a segurança do thread
  • Confirme se a extração de dados estruturados (result.Pages, page.Paragraphs, page.Words) retorna coordenadas corretas

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

Implantação Torna-se Sem Estado. Os arquivos .LIC e .LIC.KEY do LEADTOOLS são artefatos que cada ambiente de implantação deve carregar. Os contêineres que os incorporam expõem os dados de licença no histórico da imagem. Os contêineres que os acomodam precisam de coordenação de volume. Após a migração para o IronOCR, a licença passa a ser uma string em uma variável de ambiente. O artefato de implantação é uma referência padrão do NuGet . Sem arquivos, sem caminhos, sem estratégia de montagem. O guia de implantação do Docker e o guia de implantação do Azure mostram a configuração completa para ambientes conteinerizados.

Quatro Pacotes Tornam-se Um. A migração reduz Leadtools, Leadtools.Ocr, Leadtools.Codecs, Leadtools.Forms.DocumentWriters, e opcionalmente Leadtools.Pdf a uma única referência IronOcr. Todas as funcionalidades — pré-processamento, entrada nativa de PDF, saída de PDF pesquisável, leitura de código de barras, extração de dados estruturados, suporte a mais de 125 idiomas — estão incluídas nesse pacote. O conjunto de funcionalidades não depende do pacote adquirido.

O Processamento em Lote Elimina o Gerenciamento Manual de Memória. O código de lote do LEADTOOLS carrega chamadas defensivas GC.Collect() e descarte explícito RasterImage para prevenir o acúmulo de memória durante execuções multi-documento. O OcrInput do IronOCR delimitado com um bloco using lida com a limpeza automaticamente. Processamento paralelo seguro para threads com Parallel.ForEach — uma instância IronTesseract por thread — fornece throughput multi-core sem código de sincronização. Consulte o guia de otimização de velocidade para ajustar o rendimento da produção.

Custo Total Previsível. O custo estimado do LEADTOOLS para uma equipe de cinco desenvolvedores varia de US$ 15.000 a US$ 40.000 no primeiro ano, com uma taxa anual de manutenção de aproximadamente 20 a 25% do custo da licença para receber atualizações. O IronOCR Professional, por US$ 2.999, cobre dez desenvolvedores e dez locais de implantação em uma compra única e perpétua. Inclui um ano de atualizações. O uso continuado após o período de atualização não requer pagamento adicional. A página de licenciamento do IronOCR publica os preços de todos os níveis diretamente, sem necessidade de consulta de vendas.

Dados Estruturados Sem Configuração de Zona. Após a migração, dados em nível de palavra, linha e parágrafo com coordenadas de caixa delimitadora estão disponíveis diretamente em OcrResult — nenhuma definição de zona é necessária. A hierarquia de cinco níveis (Pages, Paragraphs, Lines, Words, Characters) expõe cada uma coordenadas de posição e pontuações de confiança por elemento. Aplicações que necessitavam de configuração de zona do LEADTOOLS para obter extração estruturada conseguem obter dados mais ricos a partir de uma API mais simples. A página de resultados do OCR resume o modelo de saída completo.

Observe: Adobe Acrobat, Kofax OmniPage, LEADTOOLS e Tesseract são marcas registradas de seus respectivos proprietários. Este site não é afiliado, endossado ou patrocinado por Adobe Inc., Apryse, Google, Kofax, ou LEAD Technologies. Todos os nomes de produtos, logotipos e marcas são propriedade de seus respectivos proprietários. As comparações são apenas para fins informativos e refletem informações disponíveis publicamente no momento da redação.

Artigos relacionados

Key in blue circle

Obtenha sua chave de avaliação gratuita de 30 dias instantaneamente.

Your trial license will be sent to your email address

Sem limitações. 100% desbloqueado. Sem cartão de crédito.

bullet_checkedNão é necessário cartão de crédito nem criação de conta.Sem limitações. 100% desbloqueado. Sem cartão de crédito.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Agende sua consulta sem compromisso.
Preencha o formulário abaixo ou envie um e-mail para sales@ironsoftware.com
Os seus dados serão sempre mantidos em sigilo.
Aprovado por milhões de engenheiros em todo o mundo.
Logotipos dos clientes da Iron Software
Obtenha sua chave de avaliação gratuita de 30 dias instantaneamente.
Não é necessário cartão de crédito nem criação de conta.