IRONSOFTWAREHOME
VÍDEOS

Como usar Async e Multithreading em C#

Kannaopat Udonpant
Kannapat Udonpant
Updated: 1 de agosto de 2026

A migração doMindeepara o IronOCR transfere o processamento de documentos de servidores em nuvem externos para sua própria infraestrutura, eliminando a cobrança por página, a transmissão de dados por terceiros e a disponibilidade de rede como dependências de tempo de execução. As seções abaixo abordam a substituição de pacotes, atualizações de namespace e quatro cenários práticos de código antes e depois: extração da zona de faturas, processamento de PDFs de recibos com várias páginas, pré-processamento de documentos financeiros e arquivamento de PDFs pesquisáveis.

Por que migrar do Mindee?

Mindee resolve um problema real de forma elegante: envie um documento e receba campos JSON estruturados. Para equipes em que a transmissão de documentos financeiros para uma API externa é aceitável e o volume permanece moderado, isso proporciona resultados rápidos. O gatilho da migração geralmente surge quando uma das várias condições se altera.

Os dados financeiros cruzam uma fronteira de conformidade. O ParseAsync<InvoiceV4> doMindeefaz o upload do documento completo para servidores externos. Códigos IBAN, números de roteamento, EINs de fornecedores e itens de linha detalhados trafegam pela internet pública e são processados ​​em hardware fora do seu controle. A certificação SOC 2 Tipo II confirma que aMindeesegue as práticas de segurança; Não mantém seus documentos dentro do perímetro de segurança. Quando uma revisão de conformidade, um novo contrato com um cliente ou uma regulamentação de residência de dados estabelece um limite no processamento em nuvem de terceiros, a arquitetura daMindeetorna-se desqualificante, independentemente da precisão de sua extração.

O custo por página aumenta gradativamente. O plano inicial oferece 1.000 páginas por mês por US$ 49/mês. O plano Pro oferece 5.000 páginas por mês por US$ 499/mês. PDFs com várias páginas contabilizam todas as páginas. Os processos de desenvolvimento contam para o limite de execução. Uma equipe que processa 4.000 faturas por mês paga US$ 499/mês — US$ 5.988/ano — sendo esse valor zerado anualmente e aumentando proporcionalmente ao crescimento do volume. Com 24.000 páginas por mês, você está negociando preços para Enterprise . A licença perpétua do IronOCR, a US$ 1.499 (nível Professional ), cobre um volume ilimitado de documentos e recupera o investimento em comparação com oMindeePro em menos de quatro meses.

A sondagem assíncrona se propaga por toda a sua pilha. Cada operação doMindeeé assíncrona porque cada operação é uma requisição de rede. Essa cadeia assíncrona obrigatória se propaga em cascata através de controladores, camadas de serviço e classes de trabalho. Quando a rede está indisponível ou o serviço daMindeesofre uma interrupção, o resultado em cascata é uma falha sem alternativa local.IronOCR processa de forma síncrona — trabalho de CPU local — e envolve em Task.Run onde interfaces assíncronas são necessárias para consistência arquitetônica.

**O catálogo de API pré-construído tem um limite rígido.**Mindeecobre InvoiceV4, ReceiptV5, PassportV1, e um pequeno catálogo de outros tipos de documentos. Qualquer tipo de documento fora dessa lista exige treinamento de modelo personalizado do plano Enterprise: coleta de amostras, rotulagem, tempo de treinamento e tempo de resposta antes que a API esteja disponível. Cada novo tipo de documento que sua empresa necessita representa um contrato com um fornecedor diferente.IronOCR processa qualquer tipo de documento usando a mesma chamada IronTesseract().Read(); Adicionar um novo tipo de documento significa escrever padrões de extração, não negociar um contrato de treinamento.

O gerenciamento de chaves de API aumenta a capacidade operacional. As credenciais do usuário devem ser armazenadas com segurança no servidor, rotacionadas periodicamente e protegidas contra exposição. As regras de saída da rede devem permitir HTTPS de saída para os endpoints do Mindee. A lógica de repetição deve lidar com HttpRequestException e MindeeException das inevitáveis falhas de rede. Remover oMindeeelimina toda essa superfície operacional: sem credenciais, sem regras de saída, sem mecanismos de repetição em torno de operações de E/S de rede.

Ambientes isolados da internet e com restrições estão excluídos. Contratados do governo, subcontratados da área de defesa, redes de saúde com controles rígidos de saída para a internet e sistemas industriais implantados em instalações sem conectividade confiável à internet não podem usar oMindeeconforme projetado. O IronOCR funciona de forma idêntica em contêineres Docker sem acesso externo, em Azure Functions com restrições de saída e em ambientes totalmente isolados da internet. Não há dependência da nuvem em tempo de execução. Consulte a página de licenciamento do IronOCR para obter detalhes sobre os níveis de implantação.

O problema fundamental

Todos os documentos financeiros processados ​​pelaMindeeatravessam uma fronteira de rede que você não controla:

// Mindee: invoice with bank details leaves your infrastructure on this line
var response = await _client.ParseAsync<InvoiceV4>(new LocalInputSource("invoice.pdf"));
// IBAN, routing number, EIN, line items — all transmitted toMindeecloud
C#
// IronOCR: same invoice, same result, zero data transmission
var result = new IronTesseract().Read("invoice.pdf");
// All processing local — bank details never leave your machine
C#

##IronOCR vs Mindee: Comparação de Recursos

A tabela a seguir apresenta as diferenças arquitetônicas e de capacidade que influenciam as decisões de migração.

RecursoMindeeIronOCR
Local de processamentoServidores em nuvemMindeeMáquina local / sua infraestrutura
É necessário ter internet durante a execução do programa.SempreNunca
Transmissão de dadosDocumento completo carregado por chamadaNone
Custo por documentoSim (por página, de acordo com o plano)Não (licença perpétua)
Preço inicialUS$ 49/mês (1.000 páginas)$999 uma vez (Lite)
Suporte offline/isolado da internetNão suportadoSuporte total
Implantação localNão disponívelÚnica opção
Análise de faturasAPI pré-construída estruturada (InvoiceV4)OCR + extração baseada em região ou expressão regular
Análise de recibosAPI pré-construída estruturada (ReceiptV5)OCR + padrões de extração
Tipos de documentos arbitráriosNão é compatível sem treinamento personalizado.Suporte completo, qualquer documento.
Treinamento de modelo personalizadoPlano Enterprise + prazo de entregaNão é necessário
padrão de chamada de APIAssíncrono obrigatório (E/S de rede)Síncrono (assíncrono opcional)
Limitação de taxaDependente do planoNone
Entrada de PDFSimSim (nativo, sem conversão)
Processamento de PDFs com várias páginasSimSim
Saída em PDF pesquisávelNãoSim (result.SaveAsSearchablePdf())
Pré-processamento de imagensNenhum expostoCorreção de distorção, redução de ruído, contraste, binarização, nitidez, escala
Extração baseada em regiãoCoordenadas do campo em respostaCropRectangle na entrada
Suporte para mais de 125 idiomasLimitadoSim (agrupado, sem gerenciamento de tessdata)
Leitura de código de barrasNãoSim (simultaneamente com OCR)
Coordenadas de palavras estruturadasNãoSim (Páginas, Parágrafos, Linhas, Palavras)
Segurança da roscaN/A (entrada/saída de rede por chamada)Embutido
MultiplataformaNuvem (independente de plataforma)Windows, Linux, macOS, Docker, Azure, AWS
Compatibilidade com .NET.NET Standard 2.0+.NET Framework 4.6.2+, .NET 5/6/7/8/9
Apoio comercialSimSim

Guia rápido: Migração doMindeepara o IronOCR

Passo 1: Substitua o pacote NuGet

Remova o pacote Mindee:

dotnet remove package Mindee
SHELL

Instale o IronOCR a partir do NuGet :

dotnet add package IronOcr

Etapa 2: Atualizar Namespaces

Substitua o bloco de namespaceMindeepelo namespace IronOCR:

// Before (Mindee)
using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;
using Mindee.Product.Receipt;
using Mindee.Product.FinancialDocument;

// After (IronOCR)
using IronOcr;
C#

Etapa 3: Inicializar a licença

Adicione a chave de licença na inicialização do aplicativo (antes da primeira chamada de OCR):

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

Exemplos de migração de código

Extração de campos de fatura usando zonas de documento

OMindeeretorna campos pré-analisados ​​em locais conhecidos porque seu modelo do lado do servidor sabe onde os números de faturas, datas e totais normalmente aparecem. O equivalente do IronOCR usa CropRectangle para ler zonas específicas do documento, correspondendo à consciência espacial da extração doMindeesem transmitir o documento.

Abordagem Mindee:

using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;

public class MindeeZoneExtractor
{
    private readonly MindeeClient _client;

    public MindeeZoneExtractor(string apiKey)
    {
        _client = new MindeeClient(apiKey);
    }

    public async Task<(string invoiceNumber, string supplierName, decimal? total)>
        ExtractKeyFieldsAsync(string filePath)
    {
        // Document transmitted toMindee— spatial field detection happens server-side
        var inputSource = new LocalInputSource(filePath);
        var response    = await _client.ParseAsync<InvoiceV4>(inputSource);
        var prediction  = response.Document.Inference.Prediction;

        // Fields arrive pre-parsed; no zone configuration required on your end
        return (
            prediction.InvoiceNumber?.Value,
            prediction.SupplierName?.Value,
            prediction.TotalAmount?.Value
        );
    }
}
C#

Abordagem IronOCR:

using IronOcr;
using System.Text.RegularExpressions;

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

    public (string invoiceNumber, string supplierName, string total)
        ExtractKeyFields(string filePath)
    {
        // Zone 1: supplier name — top 12% of document, full width
        var headerRegion = new CropRectangle(0, 0, 850, 120);
        using var headerInput = new OcrInput();
        headerInput.LoadImage(filePath, headerRegion);
        var supplierResult = _ocr.Read(headerInput);

        // Zone 2: invoice number and date — upper-right quadrant
        var metaRegion = new CropRectangle(450, 80, 400, 100);
        using var metaInput = new OcrInput();
        metaInput.LoadImage(filePath, metaRegion);
        var metaResult = _ocr.Read(metaInput);

        // Zone 3: totals block — bottom-right 20%
        var totalsRegion = new CropRectangle(500, 800, 350, 200);
        using var totalsInput = new OcrInput();
        totalsInput.LoadImage(filePath, totalsRegion);
        var totalsResult = _ocr.Read(totalsInput);

        var invoiceNumber = Regex.Match(
            metaResult.Text,
            @"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
            RegexOptions.IgnoreCase).Groups[1].Value;

        var total = Regex.Match(
            totalsResult.Text,
            @"Total\s*(?:Due)?\s*:?\s*\$?([\d,]+\.?\d*)",
            RegexOptions.IgnoreCase).Groups[1].Value;

        // Supplier name is the first substantial text line in the header zone
        var supplierName = supplierResult.Text
            .Split('\n')
            .FirstOrDefault(l => l.Trim().Length > 4)
            ?.Trim();

        return (invoiceNumber, supplierName, total);
    }
}
C#

O OCR baseado em zonas corresponde à intenção da detecção de campos espaciais do Mindee: ler áreas específicas do documento em vez de aplicar expressões regulares à página inteira. CropRectangle(x, y, width, height) aceita coordenadas de pixels, então o ajuste requer medição contra uma fatura de amostra representativa. O guia de OCR baseado em região cobre a medição de coordenadas e estratégias de sobreposição de zonas. Para faturas com layouts variáveis, combinar extração de zonas com regex de página inteira em result.Text produz os resultados mais confiáveis.

Processamento de relatórios de despesas com várias páginas em PDF

OMindeeaceita um arquivo PDF e processa cada página como uma unidade de documento discreta, retornando um resultado estruturado por página.IronOCR lê PDFs de várias páginas nativamente através do OcrInput.LoadPdf(), processando todas as páginas em uma única chamada e retornando result.Pages com conteúdo por página e coordenadas de palavras.

Abordagem Mindee:

using Mindee;
using Mindee.Input;
using Mindee.Product.Receipt;

public class MindeeExpenseReportProcessor
{
    private readonly MindeeClient _client;

    public MindeeExpenseReportProcessor(string apiKey)
    {
        _client = new MindeeClient(apiKey);
    }

    public async Task<List<ExpenseSummary>> ProcessExpenseReportAsync(string pdfPath)
    {
        var summaries = new List<ExpenseSummary>();

        //Mindeeprocesses per-document; each page of a PDF is a separate upload
        // For a 10-page expense report: 10 API calls, 10 pages billed
        var inputSource = new LocalInputSource(pdfPath);
        var response    = await _client.ParseAsync<ReceiptV5>(inputSource);

        var prediction = response.Document.Inference.Prediction;

        summaries.Add(new ExpenseSummary
        {
            MerchantName  = prediction.SupplierName?.Value,
            Date          = prediction.Date?.Value?.ToString(),
            TotalAmount   = prediction.TotalAmount?.Value ?? 0m,
            Category      = prediction.Category?.Value
        });

        return summaries;
    }
}
C#

Abordagem IronOCR:

using IronOcr;
using System.Text.RegularExpressions;

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

    public List<ExpenseSummary> ProcessExpenseReport(string pdfPath)
    {
        // Load entire multi-page PDF in one call — no per-page upload
        using var input = new OcrInput();
        input.LoadPdf(pdfPath);    // all pages loaded locally

        var result    = _ocr.Read(input);
        var summaries = new List<ExpenseSummary>();

        // Each page maps to one receipt in the expense report
        foreach (var page in result.Pages)
        {
            var pageText = page.Text;

            // Skip pages without receipt content
            if (!pageText.Contains("Total", StringComparison.OrdinalIgnoreCase))
                continue;

            var merchantName = page.Lines
                .FirstOrDefault(l => l.Text.Trim().Length > 4)
                ?.Text.Trim();

            var totalMatch = Regex.Match(
                pageText,
                @"(?:Total|Amount\s+Due|Grand\s+Total)\s*:?\s*\$?([\d,]+\.\d{2})",
                RegexOptions.IgnoreCase);

            var dateMatch = Regex.Match(
                pageText,
                @"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})\b");

            var categoryMatch = Regex.Match(
                pageText,
                @"(?:Category|Dept|Department)\s*:?\s*(.+)",
                RegexOptions.IgnoreCase);

            summaries.Add(new ExpenseSummary
            {
                PageNumber   = page.PageNumber,
                MerchantName = merchantName,
                Date         = dateMatch.Success ? dateMatch.Value : null,
                TotalAmount  = totalMatch.Success
                    ? decimal.Parse(totalMatch.Groups[1].Value.Replace(",", ""))
                    : 0m,
                Category     = categoryMatch.Success
                    ? categoryMatch.Groups[1].Value.Trim()
                    : null,
                Confidence   = page.Words.Any()
                    ? page.Words.Average(w => (double)w.Confidence)
                    : 0
            });
        }

        return summaries;
    }
}

public class ExpenseSummary
{
    public int    PageNumber   { get; set; }
    public string MerchantName { get; set; }
    public string Date         { get; set; }
    public decimal TotalAmount { get; set; }
    public string Category     { get; set; }
    public double Confidence   { get; set; }
}
C#

O processamento de um relatório de despesas em PDF de 10 páginas com oMindeegera 10 chamadas de API e 10 páginas faturadas. O IronOCR processa o mesmo arquivo em uma única chamada local, sem custo por página e sem viagens de ida e volta na rede por página. A coleção result.Pages fornece texto por página, caixas de delimitação em nível de palavra e posições de linha para extração consciente de layout. Consulte o guia de entrada de PDF para carregamento de PDFs protegidos por senha e seleção de intervalo de páginas, e o guia de resultados de leitura estruturada para trabalhar com coordenadas de palavras.

Fluxo de pré-processamento de faturas digitalizadas

O processamento em nuvem doMindeeaplica sua própria normalização de imagem antes de executar a extração de campos. A qualidade dessa normalização é opaca — você não tem controle sobre ela nem visibilidade sobre qual pré-processamento foi executado. Quando uma fatura digitalizada apresenta distorção, sombra ou baixo contraste, oMindeeretorna pontuações de confiança mais baixas, sem nenhum mecanismo para que você possa melhorar a digitalização antes do envio. O IronOCR expõe explicitamente o pipeline de pré-processamento, permitindo que você aplique exatamente as correções necessárias a um determinado documento antes da execução do reconhecimento.

Abordagem Mindee:

using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;

public class MindeeScanProcessor
{
    private readonly MindeeClient _client;

    public MindeeScanProcessor(string apiKey)
    {
        _client = new MindeeClient(apiKey);
    }

    public async Task<ScanResult> ProcessScannedInvoiceAsync(string scanPath)
    {
        //Mindeeapplies internal normalization — no developer control over preprocessing
        var inputSource = new LocalInputSource(scanPath);
        var response    = await _client.ParseAsync<InvoiceV4>(inputSource);
        var prediction  = response.Document.Inference.Prediction;

        return new ScanResult
        {
            InvoiceNumber = prediction.InvoiceNumber?.Value,
            Total         = prediction.TotalAmount?.Value,
            // Per-field confidence: only proxy for scan quality
            InvoiceNumberConfidence = prediction.InvoiceNumber?.Confidence,
            TotalConfidence         = prediction.TotalAmount?.Confidence
        };
    }
}
C#

Abordagem IronOCR:

using IronOcr;
using System.Text.RegularExpressions;

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

    public ScanResult ProcessScannedInvoice(string scanPath)
    {
        // First pass: read without preprocessing
        var quickResult = _ocr.Read(scanPath);

        OcrResult result;

        if (quickResult.Confidence < 75)
        {
            // Low confidence — apply full preprocessing pipeline
            using var input = new OcrInput();
            input.LoadImage(scanPath);
            input.Deskew();       // correct page rotation up to ±45 degrees
            input.DeNoise();      // remove scanner artifacts and speckle
            input.Contrast();     // normalize contrast for faded or overexposed scans
            input.Sharpen();      // sharpen blurred text edges

            result = _ocr.Read(input);
        }
        else
        {
            result = quickResult;
        }

        var invoiceNumber = Regex.Match(
            result.Text,
            @"Invoice\s*(?:Number|#|No\.?)?\s*:?\s*([A-Z0-9\-]+)",
            RegexOptions.IgnoreCase).Groups[1].Value;

        var total = Regex.Match(
            result.Text,
            @"(?:Total|Amount\s+Due)\s*:?\s*\$?([\d,]+\.\d{2})",
            RegexOptions.IgnoreCase).Groups[1].Value;

        return new ScanResult
        {
            InvoiceNumber    = invoiceNumber,
            Total            = total,
            DocumentConfidence = result.Confidence,
            PreprocessingApplied = quickResult.Confidence < 75
        };
    }
}

public class ScanResult
{
    public string InvoiceNumber        { get; set; }
    public string Total                { get; set; }
    public double DocumentConfidence   { get; set; }
    public bool   PreprocessingApplied { get; set; }
}
C#

O padrão de duas passagens — leitura rápida primeiro, pré-processamento em baixa confiança — evita a sobrecarga do pré-processamento completo em varreduras limpas. Para cenários de qualidade de digitalização mais comuns em contas a pagar (digitalizações de mesa levemente inclinadas, artefatos de fax, faturas fotocopiadas), Deskew() e DeNoise() juntos recuperam a maioria da precisão de reconhecimento. O guia de correção da qualidade da imagem documenta todos os filtros disponíveis, com orientações sobre quais combinações funcionam melhor para diferentes defeitos de digitalização. O guia de correção de orientação de imagem abrange a rotação automática de documentos digitalizados de cabeça para baixo.

Arquivamento de PDFs pesquisáveis ​​para documentos financeiros

OMindeenão gera nenhum arquivo PDF. Sua arquitetura é somente de entrada: envie um documento e receba campos JSON. As equipes que arquivam faturas digitalizadas em um formato pesquisável devem manter esse fluxo de trabalho separadamente da extração do Mindee. O IronOCR gera PDFs pesquisáveis ​​diretamente a partir da mesma etapa de reconhecimento usada para extração de campos — sem biblioteca adicional, sem segunda etapa de processamento.

Abordagem Mindee:

using Mindee;
using Mindee.Input;
using Mindee.Product.Invoice;

public class MindeeArchiveProcessor
{
    private readonly MindeeClient _client;

    public MindeeArchiveProcessor(string apiKey)
    {
        _client = new MindeeClient(apiKey);
    }

    public async Task ArchiveInvoiceAsync(string scanPath, string archivePath)
    {
        // Extract fields viaMindee(document transmitted to cloud)
        var inputSource = new LocalInputSource(scanPath);
        var response    = await _client.ParseAsync<InvoiceV4>(inputSource);
        var prediction  = response.Document.Inference.Prediction;

        //Mindeereturns no PDF output — searchable PDF requires a separate library
        // (e.g., iTextSharp, PdfSharp, or a separate OCR library)
        // The scan at scanPath is the only PDF available for archiving;
        // it remains image-only with no embedded text layer
        Console.WriteLine($"Fields extracted. Searchable PDF: not available from Mindee.");
        Console.WriteLine($"Invoice: {prediction.InvoiceNumber?.Value}");
    }
}
C#

Abordagem IronOCR:

using IronOcr;
using System.Text.RegularExpressions;

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

    public ArchiveResult ArchiveInvoice(string scanPath, string archiveOutputPath)
    {
        // Apply preprocessing before recognition and archiving
        using var input = new OcrInput();
        input.LoadPdf(scanPath);   // works with both PDF scans and image files
        input.Deskew();
        input.DeNoise();

        var result = _ocr.Read(input);

        // Extract fields from the same recognition pass
        var invoiceNumber = Regex.Match(
            result.Text,
            @"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
            RegexOptions.IgnoreCase).Groups[1].Value;

        var vendor = result.Pages.FirstOrDefault()?.Lines
            .FirstOrDefault(l => l.Text.Trim().Length > 4)
            ?.Text.Trim();

        var totalMatch = Regex.Match(
            result.Text,
            @"Total\s*(?:Due)?\s*:?\s*\$?([\d,]+\.\d{2})",
            RegexOptions.IgnoreCase);

        // Write searchable PDF to archive in one call — no separate library needed
        result.SaveAsSearchablePdf(archiveOutputPath);

        return new ArchiveResult
        {
            InvoiceNumber    = invoiceNumber,
            VendorName       = vendor,
            Total            = totalMatch.Success ? totalMatch.Groups[1].Value : null,
            ArchivePath      = archiveOutputPath,
            DocumentConfidence = result.Confidence,
            PageCount        = result.Pages.Count()
        };
    }
}

public class ArchiveResult
{
    public string InvoiceNumber      { get; set; }
    public string VendorName         { get; set; }
    public string Total              { get; set; }
    public string ArchivePath        { get; set; }
    public double DocumentConfidence { get; set; }
    public int    PageCount          { get; set; }
}
C#

result.SaveAsSearchablePdf() insere a camada de texto reconhecido diretamente no PDF de saída, produzindo um arquivo onde cada palavra é selecionável e pesquisável em qualquer visualizador de PDF ou sistema de gerenciamento de conteúdo empresarial. A extração de campo e o arquivamento são executados na mesma passagem — uma chamada _ocr.Read(input) fornece tanto result.Text para correspondência de padrões quanto result.SaveAsSearchablePdf() para o arquivo. O guia de PDF pesquisável cobre opções de saída, incluindo exportação HOCR e a página de caso de uso do PDF OCR cobre padrões de implantação de produção para pipelines de arquivamento de documentos.

Removendo o endpoint personalizado FinancialDocumentV1

A API FinancialDocumentV1 doMindeelida tanto com faturas quanto com recibos detectando automaticamente o tipo de documento. As equipes que o utilizam eliminam a lógica de ramificação, ao custo de uma maior dependência da nuvem — todos os documentos, independentemente do tipo, são carregados. A substituição pelo IronOCR utiliza dados posicionais em nível de palavra para detectar a estrutura do documento e direcionar a lógica de extração sem qualquer chamada à nuvem.

Abordagem Mindee:

using Mindee;
using Mindee.Input;
using Mindee.Product.FinancialDocument;

public class MindeeFinancialRouter
{
    private readonly MindeeClient _client;

    public MindeeFinancialRouter(string apiKey)
    {
        _client = new MindeeClient(apiKey);
    }

    public async Task<FinancialSummary> ProcessFinancialDocumentAsync(string filePath)
    {
        // All financial documents uploaded for auto-detection and parsing
        var inputSource = new LocalInputSource(filePath);
        var response    = await _client.ParseAsync<FinancialDocumentV1>(inputSource);
        var prediction  = response.Document.Inference.Prediction;

        return new FinancialSummary
        {
            DocumentType  = prediction.DocumentType?.Value,  // "INVOICE" or "RECEIPT"
            InvoiceNumber = prediction.InvoiceNumber?.Value,
            Date          = prediction.Date?.Value?.ToString(),
            TotalAmount   = prediction.TotalAmount?.Value,
            SupplierName  = prediction.SupplierName?.Value,
            CustomerName  = prediction.CustomerName?.Value
        };
    }
}
C#

Abordagem IronOCR:

using IronOcr;
using System.Text.RegularExpressions;

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

    public FinancialSummary ProcessFinancialDocument(string filePath)
    {
        var result = _ocr.Read(filePath);
        var text   = result.Text;

        // Detect document type using structural keywords from word data
        var isInvoice = DetectInvoice(result);

        if (isInvoice)
        {
            return new FinancialSummary
            {
                DocumentType  = "INVOICE",
                InvoiceNumber = Regex.Match(text,
                    @"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
                    RegexOptions.IgnoreCase).Groups[1].Value,
                Date          = Regex.Match(text,
                    @"(?:Invoice\s+)?Date\s*:?\s*(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})",
                    RegexOptions.IgnoreCase).Groups[1].Value,
                TotalAmount   = ParseAmount(text,
                    @"Total\s*(?:Due|Amount)?\s*:?\s*\$?([\d,]+\.\d{2})"),
                SupplierName  = ExtractTopLine(result),
                CustomerName  = Regex.Match(text,
                    @"Bill\s+To\s*:?\s*\n?(.+)",
                    RegexOptions.IgnoreCase).Groups[1].Value.Trim()
            };
        }
        else
        {
            // Receipt structure: merchant at top, no "Bill To" section
            return new FinancialSummary
            {
                DocumentType = "RECEIPT",
                Date         = Regex.Match(text,
                    @"\b(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})\b").Value,
                TotalAmount  = ParseAmount(text,
                    @"(?:Total|Amount\s+Due|Grand\s+Total)\s*:?\s*\$?([\d,]+\.\d{2})"),
                SupplierName = ExtractTopLine(result)
            };
        }
    }

    private bool DetectInvoice(OcrResult result)
    {
        // Invoice indicators: "Invoice", "Bill To", "Due Date", line items with quantities
        var text = result.Text;
        var invoiceSignals = new[] { "Invoice", "Bill To", "Due Date", "Purchase Order" };
        return invoiceSignals.Any(s =>
            text.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0);
    }

    private string ExtractTopLine(OcrResult result)
    {
        return result.Pages
            .FirstOrDefault()
            ?.Lines
            .FirstOrDefault(l => l.Text.Trim().Length > 4)
            ?.Text.Trim();
    }

    private decimal? ParseAmount(string text, string pattern)
    {
        var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
        if (match.Success &&
            decimal.TryParse(match.Groups[1].Value.Replace(",", ""), out var val))
            return val;
        return null;
    }
}

public class FinancialSummary
{
    public string   DocumentType  { get; set; }
    public string   InvoiceNumber { get; set; }
    public string   Date          { get; set; }
    public decimal? TotalAmount   { get; set; }
    public string   SupplierName  { get; set; }
    public string   CustomerName  { get; set; }
}
C#

A lógica de detecção de tipo de documento substitui o campo DocumentType doMindeeno servidor por uma simples verificação de palavras-chave contra result.Text. Na grande maioria dos documentos financeiros, a presença de "Fatura" ou "Cobrar de" identifica inequivocamente as faturas; a ausência identifica recibos. Dados de posição em nível de palavra em result.Pages permitem detecção baseada em layout mais sofisticada se seu conjunto de documentos incluir casos extremos. O guia de leitura de resultados explica o modelo de objeto completo, incluindo Words, Lines, e Paragraphs com suas coordenadas delimitadoras.

Referência de mapeamento da API doMindeepara o IronOCR

MindeeEquivalente de IronOCR
new MindeeClient(apiKey)new IronTesseract() — não é necessária chave da API
new LocalInputSource(filePath)new OcrInput() + input.LoadImage(filePath) ou ocr.Read(filePath)
_client.ParseAsync<InvoiceV4>(input)_ocr.Read(filePath) + extração regex em result.Text
_client.ParseAsync<ReceiptV5>(input)_ocr.Read(filePath) + padrões de extração de recibos
_client.ParseAsync<PassportV1>(input)_ocr.Read(filePath) + extração de zona MRZ via CropRectangle
_client.ParseAsync<FinancialDocumentV1>(input)_ocr.Read(filePath) + detecção de tipo de documento em result.Text
response.Document.Inference.Predictionresult.Text, result.Pages, result.Lines, result.Words
prediction.InvoiceNumber?.ValueRegex.Match(result.Text, @"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)")
prediction.SupplierName?.ValueLinha superior da primeira página via result.Pages[0].Lines.First()
prediction.TotalAmount?.ValueRegex.Match(result.Text, @"Total\s*:?\s*\$?([\d,]+\.\d{2})")
prediction.LineItemsresult.Lines filtrados por padrões de regex de item de linha
prediction.SupplierPaymentDetails[].IbanRegex.Match(result.Text, @"IBAN\s*:?\s*([\w\s]+)")
prediction.InvoiceDate?.ValueRegex.Match(result.Text, @"Date\s*:?\s*(\d{1,2}[/-]\d{1,2}[/-]\d{4})")
field.Confidenceresult.Confidence (nível de documento) ou word.Confidence (por palavra)
catch (MindeeException ex)Não há equivalente — nenhum erro de rede no momento do reconhecimento.
await Task.Delay(100) (limite de taxa)Não é obrigatório — sem limites de taxa
input.LoadPdf(path)ocrInput.LoadPdf(path) — mesma operação, totalmente local
Chave de API na configuraçãoChave de licença via IronOcr.License.LicenseKey = "..." — não há necessidade de rotação

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

Problema 1: As coordenadas do retângulo de recorte não correspondem ao layout do documento

Mindee: As coordenadas dos campos espaciais são gerenciadas no servidor. O modelo doMindeese adapta a diferentes layouts de faturas sem qualquer configuração de coordenadas por parte do desenvolvedor.

Solução: Meça as coordenadas da zona em relação a uma amostra representativa de documentos do conjunto de documentos do seu fornecedor. Abra uma fatura de amostra em qualquer editor de imagens, leia as dimensões dos pixels e defina CropRectangle(x, y, width, height) de acordo. Para faturas com layouts variáveis, leia primeiro o documento completo e utilize os dados de posição da palavra para localizar as zonas dinamicamente:

var result  = _ocr.Read("invoice.jpg");
var allWords = result.Pages.First().Words;

// Find the word "Total" and read the region 50px to its right
var totalLabel = allWords.FirstOrDefault(w =>
    w.Text.Equals("Total", StringComparison.OrdinalIgnoreCase));

if (totalLabel != null)
{
    var valueRegion = new CropRectangle(
        totalLabel.X + totalLabel.Width + 5,
        totalLabel.Y - 5,
        200,
        totalLabel.Height + 10);

    using var valueInput = new OcrInput();
    valueInput.LoadImage("invoice.jpg", valueRegion);
    var valueResult = _ocr.Read(valueInput);
    Console.WriteLine($"Total: {valueResult.Text.Trim()}");
}
C#

O exemplo de OCR baseado em regiões demonstra esse padrão de zona dinâmica em um exemplo completo e funcional.

Problema 2: Sites de chamadas assíncronas param de funcionar após a remoção do Mindee

Mindee: Toda a superfície da API doMindeeé assíncrona porque se trata de entrada/saída de rede. Controladores e métodos de serviço construídos em await _client.ParseAsync<t>() são assíncronos ao longo da cadeia de chamada.

Solução: O método Read() do IronOCR é síncrono. Os sites de chamadas assíncronas existentes funcionam imediatamente ao envolver a chamada síncrona em Task.Run:

// Existing async signature preserved for callers
public async Task<string> ExtractInvoiceNumberAsync(string filePath)
{
    return await Task.Run(() =>
    {
        var result = new IronTesseract().Read(filePath);
        return Regex.Match(result.Text,
            @"Invoice\s*#?\s*:?\s*([A-Z0-9\-]+)",
            RegexOptions.IgnoreCase).Groups[1].Value;
    });
}
C#

Para cenários ASP.NET de alta capacidade, revise o guia de OCR assíncrono antes de decidir entre invólucros Task.Run e o caminho assíncrono nativo.

Problema 3: A precisão da extração diminui em digitalizações de baixa qualidade.

Mindee: O pré-processamento doMindeeé interno e automático. Problemas na qualidade da digitalização reduzem os índices de confiança em campo, sem que o desenvolvedor possa intervir antes do reenvio.

Solução: Aplique o pipeline de pré-processamento do IronOCR antes do reconhecimento. A combinação de Deskew() e DeNoise() recupera a maior parte da precisão nos defeitos típicos de digitalização plana vistos em fluxos de trabalho de contas a pagar:

using var input = new OcrInput();
input.LoadImage("faded-invoice.jpg");
input.Deskew();
input.DeNoise();
input.Contrast();    // for faded or low-contrast thermal paper receipts
input.Binarize();    // convert to clean black-and-white before recognition
var result = new IronTesseract().Read(input);
C#

Para digitalizações severamente degradadas, input.DeepCleanBackgroundNoise() aplica uma passagem mais intensa de remoção de fundo. O guia de correção da qualidade da imagem documenta os limites e o assistente de filtros ajuda a identificar quais filtros melhoram a precisão em uma determinada amostra de documento.

Problema 4: Chave de API e configuração de saída de rede removidas

Mindee: A chave da API armazenada nas configurações do aplicativo, as regras de saída da rede permitindo HTTPS de saída para api.mindee.net, e a lógica de repetição envolvendo HttpRequestException são todas infraestruturas necessárias.

Solução: Os três são removidos juntos. A entrada da chave da API doMindeefoi excluída da configuração. A regra de saída de rede foi revogada. O bloco try/catch (HttpRequestException) é removido. A única credencial restante é a chave de licença do IronOCR, definida uma única vez na inicialização:

// appsettings.json: remove "Mindee:ApiKey"
// Firewall: revoke egress rule for api.mindee.net
// Startup.cs or Program.cs:
IronOcr.License.LicenseKey = Configuration["IronOcr:LicenseKey"];
// Não rotation schedule, no secure storage beyond standard config secret management
C#

Problema 5: Cobrança por contagem de páginas em PDFs com várias páginas

Mindee: Um extrato de fornecedor de 12 páginas carregado noMindeeconsome 12 páginas da cota mensal. Não plano Pro, com as tarifas adicionais, esse documento individual gera um custo extra de US$ 1,20 além da franquia mensal, caso você esteja próximo do limite.

Solução: O IronOCR processa PDFs com várias páginas sem custo por página. Carregue o documento inteiro e processe as páginas em sequência:

using var input = new OcrInput();
input.LoadPdf("vendor-statement.pdf");   // 12 pages — no billing unit increment
var result = new IronTesseract().Read(input);

foreach (var page in result.Pages)
    Console.WriteLine($"Page {page.PageNumber}: {page.Text.Length} characters recognized");
C#

Problema 6: A dependência do FinancialDocumentV1 não pode ser substituída por um único padrão.

Mindee: FinancialDocumentV1 detecta automaticamente o tipo de documento e extrai campos sem que o código de chamada precise condicionar com base no tipo de documento.

Solução: Construir um detector leve usando a presença de palavras-chave. Os documentos financeiros dividem-se claramente em faturas (que contêm "Fatura", "Cobrar de" ou "Data de Vencimento") e recibos (que contêm "Recibo", "Agradecimento" ou não possuem as indicações de fatura). Dois métodos de extração, Plus de um detector de três linhas, substituem a chamada da APIMindeesem comprometer a precisão em documentos bem formados:

var result  = _ocr.Read(filePath);
var summary = result.Text.IndexOf("Invoice", StringComparison.OrdinalIgnoreCase) >= 0
    ? ExtractInvoiceFields(result)
    : ExtractReceiptFields(result);
C#

Lista de verificação para migração de Mindee

Pré-migração

Audite toda a utilização doMindeeem toda a base de código:

grep -r "using Mindee" --include="*.cs" .
grep -r "MindeeClient\|ParseAsync\|InvoiceV4\|ReceiptV5\|PassportV1\|FinancialDocumentV1" --include="*.cs" .
grep -r "LocalInputSource\|MindeeException" --include="*.cs" .
grep -r "Mindee:ApiKey\|mindee_api_key\|MINDEE_API_KEY" --include="*.json" --include="*.env" --include="*.yml" .
SHELL

Resultados do inventário:

  • Conte sites de chamadas únicos usando ParseAsync<t>
  • Anote quais tipos de documentos são usados (InvoiceV4, ReceiptV5, PassportV1, FinancialDocumentV1)
  • Identificar todas as cadeias de métodos assíncronos que se propagam a partir de chamadas do Mindee
  • Localize as referências às chaves de API nos arquivos de configuração e nos cofres de segredos.
  • Identificar a lógica de repetição que envolve as chamadas de rede do Mindee
  • Identificar regras de saída de rede que permitam tráfego de saída para os endpoints do Mindee

Migração de código

  1. Remova o pacote NuGet Mindee do arquivo de projeto
  2. Execute dotnet add package IronOcr para instalar o IronOCR
  3. Adicione IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY" ao início do aplicativo
  4. Remova todas as diretivas using Mindee, using Mindee.Input e using Mindee.Product.*
  5. Substitua a injeção de construtor MindeeClient por instância IronTesseract ou registro DI
  6. Substitua cada chamada ParseAsync<InvoiceV4> por _ocr.Read(filePath) mais métodos de extração de faturas
  7. Substitua cada chamada ParseAsync<ReceiptV5> por _ocr.Read(filePath) mais métodos de extração de recibos
  8. Substitua cada chamada ParseAsync<PassportV1> por OCR baseado em zona usando CropRectangle na área MRZ
  9. Substitua cada chamada ParseAsync<FinancialDocumentV1> pelo detector de tipo de documento + padrão de roteamento
  10. Remova todas as linhas de conformidade de limite de taxa await Task.Delay(...)
  11. Remova todos os blocos catch (MindeeException) e catch (HttpRequestException) dos caminhos de OCR
  12. Adicione chamadas de pré-processamento OcrInput (Deskew, DeNoise, Contrast) para caminhos de documentos digitalizados
  13. Adicione result.SaveAsSearchablePdf(archivePath) a quaisquer caminhos de arquivamento de documentos
  14. Remova a chave da API doMindeede todos os arquivos de configuração e cofres de segredos.
  15. Atualize os testes de integração para serem executados de forma síncrona, sem simulação de rede.

Pós-migração

  • Verificar a precisão da extração em um conjunto de amostra de 20 a 30 documentos, abrangendo cada tipo de documento.
  • Confirme valores result.Confidence acima de 80 em digitalizações limpas representativas; Aplicar pré-processamento se abaixo
  • Teste o pipeline de pré-processamento (Deskew, DeNoise) em amostras de digitalização inclinadas e degradadas
  • Verifique se PDFs de várias páginas produzem result.Pages.Count e conteúdo por página corretos
  • Confirme que a saída result.SaveAsSearchablePdf() é pesquisável no Adobe Acrobat e visualizadores de PDF do sistema
  • Teste toda extração baseada em zona (CropRectangle) contra variações de layout de documentos no seu conjunto de fornecedores
  • Execute processamento em lote sem chamadas Task.Delay e verifique se não há problemas de encadeamento
  • Confirme se o aplicativo inicia e funciona corretamente sem acesso à internet.
  • Verifique se a inicialização da chave de licença é executada antes da primeira chamada _ocr.Read() em cada ponto de entrada
  • Verifique se não restam referências à chave da API doMindeenas configurações, variáveis ​​de ambiente ou segredos.

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

Soberania total sobre os dados dos documentos financeiros. Após a migração, os códigos IBAN dos fornecedores, os números de roteamento, os EINs dos clientes e os itens detalhados das transações permanecem intactos em sua infraestrutura. O âmbito da conformidade abrange apenas a sua organização. Os contratos de processamento com fornecedores terceirizados de IA são removidos do seu histórico de auditoria. Equipes que operam sob os requisitos de GLBA, CMMC, FedRAMP ou de residência de dados podem processar documentos financeiros sem a revisão de conformidade exigida pela transmissão externa para a nuvem.

Custo previsível independentemente do volume. A licença Lite do IronOCR em $999 cobre um desenvolvedor com processamento ilimitado de documentos. Aumentar a produção de 500 faturas por mês para 50.000 faturas por mês não acarreta custos adicionais. Os picos de processamento de fim de ano, as execuções de correção em lote e os ciclos de teste de desenvolvimento não incrementam nenhum contador de faturamento. O custo total de propriedade em três anos para uma equipe que processa 5.000 páginas por mês cai de aproximadamente US$ 17.964 (Mindee Pro) para US$ 1.499 a US$ 2.999 (licença perpétua do IronOCR). Consulte a página completa do produto IronOCR para obter detalhes sobre os níveis de qualidade.

Lógica de extração que você possui permanentemente. Os padrões de extração do IronOCR são código C# simples em seu repositório. Eles possuem controle de versão, são revisáveis, testáveis ​​e implantáveis ​​independentemente do cronograma de lançamentos ou das decisões de versionamento de API de qualquer fornecedor externo. Quando oMindeelança InvoiceV5 e desativa InvoiceV4, isso é um prazo de migração imposto pelo fornecedor. Quando você mantém padrões de extração, a melhoria é um git commit.

Controle de pré-processamento para qualidade de digitalização no mundo real. As operações de contas a pagar recebem faturas de dezenas ou centenas de fornecedores, cada uma digitalizada com equipamentos diferentes e em configurações distintas. O pipeline de pré-processamento do IronOCR— Deskew(), DeNoise(), Contrast(), Sharpen(), Binarize() — aborda os defeitos específicos em cada categoria de digitalização. Uma fotografia térmica de um recibo apresenta defeitos diferentes de uma fatura digitalizada com várias páginas; você aplica os filtros apropriados para cada caso. O pré-processamento doMindeeé invisível e não configurável. Consulte a página de recursos de pré-processamento para obter o catálogo completo de filtros.

Armazenamento de PDF pesquisável em uma etapa. Cada fatura processada pelo IronOCR pode ser arquivada como um PDF pesquisável com result.SaveAsSearchablePdf(). A camada de texto reconhecida é incorporada ao arquivo de saída, tornando cada palavra pesquisável por texto completo em sistemas de gerenciamento de documentos, bibliotecas do SharePoint e repositórios de conteúdo Enterprise . OMindeenão gera nenhum arquivo PDF; Anteriormente, o arquivamento pesquisável exigia uma biblioteca separada, uma etapa de processamento separada e manutenção adicional. Após a migração, extração e arquivamento se unem em uma única chamada _ocr.Read(input).

Implantação em qualquer lugar sem alterações de arquitetura. O IronOCR pode ser implantado no Windows, Linux, macOS, Docker, Azure App Service, AWS Lambda e Google Cloud Run usando o mesmo pacote NuGet e a mesma inicialização. Ambientes isolados por ar, sistemas de chão de fábrica e instalações governamentais de segurança funcionam sem modificações. O guia de implantação do Docker , o guia do Azure e o guia da AWS abrangem a configuração específica de cada ambiente para cada plataforma.

Observe: Adobe Acrobat, Mindee, PDFSharp, Tesseract e iText são marcas registradas de seus respectivos proprietários. Este site não é afiliado, endossado ou patrocinado por Adobe Inc., Google, Mindee, empira Software GmbH, ou iText Group. 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.