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

Como corrigir as cores da imagem para leitura em C#

Este guia orienta os desenvolvedores .NET na substituição da integração da API REST do OCR.space pelo IronOCR , uma biblioteca nativa do .NET distribuída como um único pacote NuGet . Abrange a troca de pacotes, a limpeza do espaço de nomes e quatro cenários concretos de migração de código específicos para a transição de REST para local: eliminação do upload multipart, remoção da codificação base64, substituição da seleção do mecanismo de OCR e extração de dados estruturados. Os desenvolvedores que leram o artigo comparativo da Fase 1 acharão este guia focado nos passos práticos da migração em si, e não na comparação de funcionalidades.

Por que migrar do OCR.space?

O OCR.space preenche um nicho genuíno: experimentação sem custo para desenvolvedores que desejam testar OCR em uma tarde sem precisar instalar nada. O problema é que a versão gratuita foi concebida para prototipagem, não para produção. Quando uma aplicação .NET começa a lidar com volumes reais de documentos, requisitos de conformidade ou desenvolvimento em equipe, todas as características da integração com o OCR.space passam a prejudicar a aplicação.

Sem um pacote NuGet , não há SDK nem IntelliSense. O OCR.space fornece um endpoint REST e documentação. A integração com o .NET — construção do cliente HTTP, serialização de requisições, desserialização de respostas, tratamento de erros e lógica de repetição — é de inteira responsabilidade do desenvolvedor. Isso não é um pequeno inconveniente. O cliente mínimo viável possui mais de 80 linhas de código de infraestrutura antes mesmo de o primeiro método de lógica de negócios ser escrito. Esse código não é diferenciado em todas as integrações do OCR.space em todas as bases de código .NET e, com o tempo, acumula erros e sobrecarga de manutenção.

Os limites de taxa impõem tetos artificiais às aplicações de produção. O plano gratuito impõe um limite de 60 requisições por minuto e 500 requisições por dia por endereço IP. Ambos os limites são paredes intransponíveis. Uma aplicação que ultrapassa 500 requisições entre a meia-noite e a meia-noite seguinte recebe respostas de erro até que o contador seja reiniciado. Sistemas de produção executados em redes de escritório compartilhadas ou em ambientes CI/CD compartilhados podem esgotar a cota diária antes do término do expediente.

Os documentos saem da sua infraestrutura a cada chamada. O OCR.space não oferece opção de implantação local. Cada solicitação transmite o documento — faturas, registros médicos, contratos, documentos de identidade — para os servidores em nuvem da OCR.space. As políticas HIPAA, GDPR e as políticas internas de classificação de dados que proíbem a transmissão de documentos sensíveis a terceiros tornam o OCR.space arquiteturalmente incompatível, independentemente dos controles contratuais.

O plano gratuito gera PDFs pesquisáveis ​​com marca d'água. Aplicativos que geram PDFs pesquisáveis ​​como resultado final — sistemas de arquivamento de documentos, plataformas de conformidade, portais de documentos voltados para o cliente — não podem usar o plano gratuito do OCR.space para essa finalidade. A marca d'água está incorporada no PDF de saída e não pode ser removida sem um plano pago.

**O preço da assinatura aumenta com o volume; a camada PRO do OCR.space por $144 por ano cruza o preço de entrada perpétua do IronOCR antes do ano seis. As equipes que projetam o crescimento do volume de documentos além do limite da camada gratuita enfrentam custos de assinatura compostos contra uma licença perpétua fixa. A licença Lite cobre um desenvolvedor e um local de implantação sem cobranças por solicitação em qualquer volume. Consulte a página de licenciamento do IronOCR para obter detalhes sobre os níveis de licenciamento.

O problema fundamental

O OCR.space exige que você crie um cliente HTTP completo antes de processar um único documento:

// OCR.space: 80+ lines of infrastructure before business logic
public class OcrSpaceApiClient : IDisposable
{
    private readonly HttpClient _httpClient;
    private readonly string _apiKey;
    private readonly SemaphoreSlim _rateLimiter; // You implement this

    public OcrSpaceApiClient(string apiKey)
    {
        _httpClient = new HttpClient();
        _httpClient.Timeout = TimeSpan.FromSeconds(120);
        _rateLimiter = new SemaphoreSlim(60, 60); // Free tier: 60/min
    }
    // ... 70+ more lines of HTTP plumbing follow
}
// OCR.space: 80+ lines of infrastructure before business logic
public class OcrSpaceApiClient : IDisposable
{
    private readonly HttpClient _httpClient;
    private readonly string _apiKey;
    private readonly SemaphoreSlim _rateLimiter; // You implement this

    public OcrSpaceApiClient(string apiKey)
    {
        _httpClient = new HttpClient();
        _httpClient.Timeout = TimeSpan.FromSeconds(120);
        _rateLimiter = new SemaphoreSlim(60, 60); // Free tier: 60/min
    }
    // ... 70+ more lines of HTTP plumbing follow
}
Imports System
Imports System.Net.Http
Imports System.Threading

' OCR.space: 80+ lines of infrastructure before business logic
Public Class OcrSpaceApiClient
    Implements IDisposable

    Private ReadOnly _httpClient As HttpClient
    Private ReadOnly _apiKey As String
    Private ReadOnly _rateLimiter As SemaphoreSlim ' You implement this

    Public Sub New(apiKey As String)
        _httpClient = New HttpClient()
        _httpClient.Timeout = TimeSpan.FromSeconds(120)
        _rateLimiter = New SemaphoreSlim(60, 60) ' Free tier: 60/min
    End Sub
    ' ... 70+ more lines of HTTP plumbing follow

    Public Sub Dispose() Implements IDisposable.Dispose
        _httpClient.Dispose()
        _rateLimiter.Dispose()
    End Sub
End Class
$vbLabelText   $csharpLabel

IronOCR é um pacote NuGet . Todo o código do cliente já está escrito:

// IronOCR: no client to build, no rate limiter to manage
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("document.jpg");
Console.WriteLine(result.Text);
// IronOCR: no client to build, no rate limiter to manage
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
var result = new IronTesseract().Read("document.jpg");
Console.WriteLine(result.Text);
Imports IronOcr

' IronOCR: no client to build, no rate limiter to manage
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim result = New IronTesseract().Read("document.jpg")
Console.WriteLine(result.Text)
$vbLabelText   $csharpLabel

IronOCR vs OCR.space: Comparação de Recursos

A tabela abaixo mapeia os conceitos e restrições do OCR.space diretamente para os equivalentes no IronOCR.

Recurso OCR.space IronOCR
Pacote NuGet Nenhuma — somente API REST — .NET nativo
SDK / IntelliSense Nenhum — JSON manual API completa e tipada
Modelos personalizados necessários Não Não
Local de processamento Servidores em nuvem OCR.space Local — em processo
Dependência da Internet Obrigatório para todas as chamadas None
Implantação isolada da internet Não suportado Suporte completo
Limites de taxa 60/min, 500/dia (grátis) None
Limite de tamanho do arquivo 5 MB (nível gratuito) Somente memória disponível
Entrada de PDF Sim (limitado, 5 MB) Sim — nativo, sem limite de tamanho.
Saída em PDF pesquisável Com marca d'água na versão gratuita. Saída limpa, em todos os níveis.
Pré-processamento automático Lado do servidor, sem controle do desenvolvedor Correção de distorção, redução de ruído, contraste, binarização, nitidez
Suporte linguístico aproximadamente 25 idiomas Mais de 125 idiomas disponíveis através dos pacotes NuGet.
Vários idiomas por documento Não suportado Sim —
Saída estruturada (palavras, linhas) Somente texto simples Páginas, parágrafos, linhas, palavras com coordenadas
pontuações de confiança ao nível da palavra Não disponível Sim —
OCR baseado em região Não suportado Sim —
Leitura de código de barras Não suportado Sim —
Geração de PDF pesquisável Com marca d'água (gratuito), versão limpa (pago) Saída limpa — todos os níveis de licença
Compatibilidade com HIPAA/GDPR Risco — dados transmitidos externamente Sim — sem transmissão externa de dados
Modelo de preços Assinatura mensal Uma vez perpétuo
Preço de entrada US$ 12/mês (US$ 144/ano) uma vez
Compatibilidade com .NET — qualquer .NET .NET 4.6.2+, .NET 5/6/7/8/9
Implantação multiplataforma Requer conexão de internet de saída. Windows, Linux, macOS, Docker, Azure, AWS

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

Passo 1: Substitua o pacote NuGet

O OCR.space não possui nenhum pacote NuGet para desinstalar. Remova todo o código de infraestrutura relacionado ao OCR.space do projeto: a classe wrapper, o limitador de taxa, os modelos de resultados personalizados e os tipos de exceção personalizados. Todos estes são substituídos pelo pacote NuGet do IronOCR.

Instale o IronOCR a partir da página do IronOCR no NuGet :

dotnet add package IronOcr

Etapa 2: Atualizar Namespaces

Remover os namespaces HTTP e JSON do OCR.space. Adicione o namespace IronOCR:

// Before (OCR.space — manually written infrastructure)
using System.Net.Http;
using System.Text.Json;
using System.Threading;

// After (IronOCR)
using IronOcr;
// Before (OCR.space — manually written infrastructure)
using System.Net.Http;
using System.Text.Json;
using System.Threading;

// After (IronOCR)
using IronOcr;
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading

Imports IronOcr
$vbLabelText   $csharpLabel

Etapa 3: Inicializar a licença

Adicionar a inicialização da licença uma única vez na inicialização do aplicativo — não a cada solicitação:

// Program.cs or application startup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
// Program.cs or application startup
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronOcr

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

Exemplos de migração de código

Substituindo o upload de arquivos MultipartFormDataContent

O OCR.space exige construir com os bytes do arquivo e a chave de API e, em seguida, enviar um POST para o endpoint na nuvem. O documento deixa sua infraestrutura a cada chamada.

Abordagem OCR.space:

// MultipartFormDataContent: file upload to cloud on every request
public async Task<string> UploadAndExtract(string imagePath)
{
    using var content = new MultipartFormDataContent();
    var imageBytes = File.ReadAllBytes(imagePath);

    // Document is transmitted to OCR.space servers here
    content.Add(new ByteArrayContent(imageBytes), "file", Path.GetFileName(imagePath));
    content.Add(new StringContent(_apiKey), "apikey");
    content.Add(new StringContent("eng"), "language");
    content.Add(new StringContent("2"), "OCREngine"); // Select Engine 2

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
    response.EnsureSuccessStatusCode();

    string json = await response.Content.ReadAsStringAsync();
    using var doc = JsonDocument.Parse(json);

    // Navigate JSON tree manually — no typed result
    return doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("ParsedText")
        .GetString() ?? string.Empty;
}
// MultipartFormDataContent: file upload to cloud on every request
public async Task<string> UploadAndExtract(string imagePath)
{
    using var content = new MultipartFormDataContent();
    var imageBytes = File.ReadAllBytes(imagePath);

    // Document is transmitted to OCR.space servers here
    content.Add(new ByteArrayContent(imageBytes), "file", Path.GetFileName(imagePath));
    content.Add(new StringContent(_apiKey), "apikey");
    content.Add(new StringContent("eng"), "language");
    content.Add(new StringContent("2"), "OCREngine"); // Select Engine 2

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
    response.EnsureSuccessStatusCode();

    string json = await response.Content.ReadAsStringAsync();
    using var doc = JsonDocument.Parse(json);

    // Navigate JSON tree manually — no typed result
    return doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("ParsedText")
        .GetString() ?? string.Empty;
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks

Public Class YourClassName
    Private _apiKey As String
    Private _httpClient As HttpClient

    Public Async Function UploadAndExtract(imagePath As String) As Task(Of String)
        Using content As New MultipartFormDataContent()
            Dim imageBytes = File.ReadAllBytes(imagePath)

            ' Document is transmitted to OCR.space servers here
            content.Add(New ByteArrayContent(imageBytes), "file", Path.GetFileName(imagePath))
            content.Add(New StringContent(_apiKey), "apikey")
            content.Add(New StringContent("eng"), "language")
            content.Add(New StringContent("2"), "OCREngine") ' Select Engine 2

            Dim response = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", content)
            response.EnsureSuccessStatusCode()

            Dim json As String = Await response.Content.ReadAsStringAsync()
            Using doc = JsonDocument.Parse(json)
                ' Navigate JSON tree manually — no typed result
                Return doc.RootElement _
                    .GetProperty("ParsedResults")(0) _
                    .GetProperty("ParsedText") _
                    .GetString() OrElse String.Empty
            End Using
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

// OcrInput replaces the entire upload + JSON pipeline
public string ExtractFromFile(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath); // Stays local — no network call

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    return result.Text; // Typed property — no JSON navigation
}
// OcrInput replaces the entire upload + JSON pipeline
public string ExtractFromFile(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath); // Stays local — no network call

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    return result.Text; // Typed property — no JSON navigation
}
Imports IronTesseract

Public Function ExtractFromFile(ByVal imagePath As String) As String
    Using input As New OcrInput()
        input.LoadImage(imagePath) ' Stays local — no network call

        Dim ocr As New IronTesseract()
        Dim result = ocr.Read(input)

        Return result.Text ' Typed property — no JSON navigation
    End Using
End Function
$vbLabelText   $csharpLabel

é a substituição local para. Ele aceita caminhos de arquivos, matrizes de bytes, fluxos e TIFFs de várias páginas por meio de uma API consistente. A injeção de chave de API e a navegação em JSON desaparecem completamente. O guia de entrada de imagens abrange todos os formatos de entrada suportados.

Eliminando a codificação Base64

Quando as integrações do OCR.space usam o parâmetro de formulário em vez do parâmetro de upload de arquivo, o código lê o arquivo para bytes, codifica para Base64, constrói uma string de URI de dados e a incorpora em. O IronOCR aceita bytes brutos diretamente, sem etapa de codificação.

Abordagem OCR.space:

// base64Image parameter: read → encode → embed in form → POST → parse
public async Task<string> ExtractViaBase64(string imagePath)
{
    byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
    string base64Image = Convert.ToBase64String(imageBytes); // Mandatory encoding step

    // Embed as data URI — adds 33% overhead to payload size
    string mimeType = "image/png";
    string dataUri = $"data:{mimeType};base64,{base64Image}";

    var formContent = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("apikey", _apiKey),
        new KeyValuePair<string, string>("base64Image", dataUri),
        new KeyValuePair<string, string>("language", "eng"),
        new KeyValuePair<string, string>("isOverlayRequired", "false")
    });

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent);
    string json = await response.Content.ReadAsStringAsync();

    using var doc = JsonDocument.Parse(json);
    return doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("ParsedText")
        .GetString() ?? string.Empty;
}
// base64Image parameter: read → encode → embed in form → POST → parse
public async Task<string> ExtractViaBase64(string imagePath)
{
    byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
    string base64Image = Convert.ToBase64String(imageBytes); // Mandatory encoding step

    // Embed as data URI — adds 33% overhead to payload size
    string mimeType = "image/png";
    string dataUri = $"data:{mimeType};base64,{base64Image}";

    var formContent = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("apikey", _apiKey),
        new KeyValuePair<string, string>("base64Image", dataUri),
        new KeyValuePair<string, string>("language", "eng"),
        new KeyValuePair<string, string>("isOverlayRequired", "false")
    });

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent);
    string json = await response.Content.ReadAsStringAsync();

    using var doc = JsonDocument.Parse(json);
    return doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("ParsedText")
        .GetString() ?? string.Empty;
}
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks

Public Class ImageProcessor
    Private _apiKey As String
    Private _httpClient As HttpClient

    Public Sub New(apiKey As String, httpClient As HttpClient)
        _apiKey = apiKey
        _httpClient = httpClient
    End Sub

    ' base64Image parameter: read → encode → embed in form → POST → parse
    Public Async Function ExtractViaBase64(imagePath As String) As Task(Of String)
        Dim imageBytes As Byte() = Await File.ReadAllBytesAsync(imagePath)
        Dim base64Image As String = Convert.ToBase64String(imageBytes) ' Mandatory encoding step

        ' Embed as data URI — adds 33% overhead to payload size
        Dim mimeType As String = "image/png"
        Dim dataUri As String = $"data:{mimeType};base64,{base64Image}"

        Dim formContent As New FormUrlEncodedContent(New KeyValuePair(Of String, String)() {
            New KeyValuePair(Of String, String)("apikey", _apiKey),
            New KeyValuePair(Of String, String)("base64Image", dataUri),
            New KeyValuePair(Of String, String)("language", "eng"),
            New KeyValuePair(Of String, String)("isOverlayRequired", "false")
        })

        Dim response As HttpResponseMessage = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent)
        Dim json As String = Await response.Content.ReadAsStringAsync()

        Using doc As JsonDocument = JsonDocument.Parse(json)
            Return doc.RootElement _
                .GetProperty("ParsedResults")(0) _
                .GetProperty("ParsedText") _
                .GetString() OrElse String.Empty
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

// LoadImage(bytes): raw bytes accepted directly — no encoding
public string ExtractFromBytes(byte[] imageBytes)
{
    using var input = new OcrInput();
    input.LoadImage(imageBytes); // Não Base64, no data URI, no overhead

    var result = new IronTesseract().Read(input);
    return result.Text;
}
// LoadImage(bytes): raw bytes accepted directly — no encoding
public string ExtractFromBytes(byte[] imageBytes)
{
    using var input = new OcrInput();
    input.LoadImage(imageBytes); // Não Base64, no data URI, no overhead

    var result = new IronTesseract().Read(input);
    return result.Text;
}
Imports IronOcr

Public Function ExtractFromBytes(imageBytes As Byte()) As String
    Using input As New OcrInput()
        input.LoadImage(imageBytes) ' Não Base64, no data URI, no overhead

        Dim result = New IronTesseract().Read(input)
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

A etapa de codificação Base64 não existe no IronOCR porque não há uma camada de transporte HTTP. Bytes brutos vão diretamente para. A sobrecarga do URI de dados — a codificação Base64 aumenta o tamanho da carga útil em aproximadamente 33% — também desaparece. O guia de entrada de fluxo mostra o mesmo padrão para entradas, o que é útil quando os bytes se originam de um manipulador de upload ou buffer de memória, em vez de um arquivo.

Substituindo a seleção do mecanismo de OCR pelo pré-processamento de imagens

O OCR.space expõe dois motores OCR via o parâmetro de formulário: O Motor 1 é mais rápido, com menor precisão em layouts complexos; O mecanismo 2 é mais lento, mas oferece maior precisão na maioria dos tipos de documento. Os desenvolvedores selecionam o mecanismo a cada chamada, com base nas características do documento. O IronOCR utiliza um único mecanismo Tesseract 5 otimizado, mas expõe filtros de pré-processamento explícitos que abordam a causa principal — a qualidade do documento — em vez de alternar entre modos de mecanismo.

Abordagem OCR.space:

// OCREngine parameter: binary choice, no control over why accuracy differs
public async Task<string> ExtractWithEngineSelection(
    string imagePath,
    bool useHighAccuracyEngine = true)
{
    byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
    string base64 = Convert.ToBase64String(imageBytes);

    var formContent = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("apikey", _apiKey),
        new KeyValuePair<string, string>("base64Image", $"data:image/png;base64,{base64}"),
        new KeyValuePair<string, string>("language", "eng"),
        // Engine 1 = faster, Engine 2 = higher accuracy — binary choice only
        new KeyValuePair<string, string>("OCREngine", useHighAccuracyEngine ? "2" : "1"),
        new KeyValuePair<string, string>("scale", "true"),
        new KeyValuePair<string, string>("detectOrientation", "true")
    });

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent);
    string json = await response.Content.ReadAsStringAsync();

    using var doc = JsonDocument.Parse(json);
    return doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("ParsedText")
        .GetString() ?? string.Empty;
}
// OCREngine parameter: binary choice, no control over why accuracy differs
public async Task<string> ExtractWithEngineSelection(
    string imagePath,
    bool useHighAccuracyEngine = true)
{
    byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
    string base64 = Convert.ToBase64String(imageBytes);

    var formContent = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("apikey", _apiKey),
        new KeyValuePair<string, string>("base64Image", $"data:image/png;base64,{base64}"),
        new KeyValuePair<string, string>("language", "eng"),
        // Engine 1 = faster, Engine 2 = higher accuracy — binary choice only
        new KeyValuePair<string, string>("OCREngine", useHighAccuracyEngine ? "2" : "1"),
        new KeyValuePair<string, string>("scale", "true"),
        new KeyValuePair<string, string>("detectOrientation", "true")
    });

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent);
    string json = await response.Content.ReadAsStringAsync();

    using var doc = JsonDocument.Parse(json);
    return doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("ParsedText")
        .GetString() ?? string.Empty;
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks

Public Class OCRService
    Private _apiKey As String
    Private _httpClient As HttpClient

    Public Sub New(apiKey As String, httpClient As HttpClient)
        _apiKey = apiKey
        _httpClient = httpClient
    End Sub

    ' OCREngine parameter: binary choice, no control over why accuracy differs
    Public Async Function ExtractWithEngineSelection(imagePath As String, Optional useHighAccuracyEngine As Boolean = True) As Task(Of String)
        Dim imageBytes As Byte() = Await File.ReadAllBytesAsync(imagePath)
        Dim base64 As String = Convert.ToBase64String(imageBytes)

        Dim formContent As New FormUrlEncodedContent(New KeyValuePair(Of String, String)() {
            New KeyValuePair(Of String, String)("apikey", _apiKey),
            New KeyValuePair(Of String, String)("base64Image", $"data:image/png;base64,{base64}"),
            New KeyValuePair(Of String, String)("language", "eng"),
            ' Engine 1 = faster, Engine 2 = higher accuracy — binary choice only
            New KeyValuePair(Of String, String)("OCREngine", If(useHighAccuracyEngine, "2", "1")),
            New KeyValuePair(Of String, String)("scale", "true"),
            New KeyValuePair(Of String, String)("detectOrientation", "true")
        })

        Dim response As HttpResponseMessage = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", formContent)
        Dim json As String = Await response.Content.ReadAsStringAsync()

        Using doc As JsonDocument = JsonDocument.Parse(json)
            Return doc.RootElement _
                .GetProperty("ParsedResults")(0) _
                .GetProperty("ParsedText") _
                .GetString() OrElse String.Empty
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

// Preprocessing pipeline: fix the document, not the engine selection
public string ExtractWithPreprocessing(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);

    // Apply filters that match the document's specific quality issues
    input.Deskew();         // Correct rotation — replaces detectOrientation
    input.DeNoise();        // Remove noise from fax/photocopier artifacts
    input.Contrast();       // Enhance contrast on low-quality scans
    input.Scale(200);       // Upscale small or low-DPI images

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    Console.WriteLine($"Confidence: {result.Confidence}%"); // Não equivalent in OCR.space
    return result.Text;
}
// Preprocessing pipeline: fix the document, not the engine selection
public string ExtractWithPreprocessing(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);

    // Apply filters that match the document's specific quality issues
    input.Deskew();         // Correct rotation — replaces detectOrientation
    input.DeNoise();        // Remove noise from fax/photocopier artifacts
    input.Contrast();       // Enhance contrast on low-quality scans
    input.Scale(200);       // Upscale small or low-DPI images

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    Console.WriteLine($"Confidence: {result.Confidence}%"); // Não equivalent in OCR.space
    return result.Text;
}
Imports IronOcr

Public Function ExtractWithPreprocessing(imagePath As String) As String
    Using input As New OcrInput()
        input.LoadImage(imagePath)

        ' Apply filters that match the document's specific quality issues
        input.Deskew()         ' Correct rotation — replaces detectOrientation
        input.DeNoise()        ' Remove noise from fax/photocopier artifacts
        input.Contrast()       ' Enhance contrast on low-quality scans
        input.Scale(200)       ' Upscale small or low-DPI images

        Dim ocr As New IronTesseract()
        Dim result = ocr.Read(input)

        Console.WriteLine($"Confidence: {result.Confidence}%") ' Não equivalent in OCR.space
        Return result.Text
    End Using
End Function
$vbLabelText   $csharpLabel

O parâmetro do OCR.space é um proxy para a qualidade do documento — quando o Motor 1 falha em um documento, os desenvolvedores mudam para o Motor 2 esperando que o algoritmo diferente compense. O pipeline de pré-processamento do IronOCR aborda diretamente o problema de qualidade: corrige digitalizações inclinadas, lida com artefatos de fax e recupera texto de fotocópias de baixo contraste. A propriedade do resultado quantifica a qualidade da extração, o que a troca não pode fornecer. O guia de correção de qualidade da imagem e o assistente de filtros documentam o efeito de cada filtro em diferentes tipos de documentos.

OCR multilíngue sem troca de idioma por chamada

OCR.space aceita um parâmetro por chamada de API. Documentos que contenham idiomas mistos exigem chamadas separadas para cada idioma, com os resultados sendo mesclados manualmente.IronOCR processa vários idiomas simultaneamente em uma única operação de leitura usando o operador em valores.

Abordagem OCR.space:

// OCR.space: one language per call — multi-language requires multiple requests
public async Task<string> ExtractMultiLanguage(string imagePath)
{
    // First pass: English
    string englishText = await ExtractWithLanguage(imagePath, "eng");

    // Second pass: French (consumes another rate-limit slot, another API call)
    string frenchText = await ExtractWithLanguage(imagePath, "fre");

    // Manually merge results — no way to know which text belongs to which language
    return $"{englishText}\n{frenchText}";
}

private async Task<string> ExtractWithLanguage(string imagePath, string langCode)
{
    byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
    string base64 = Convert.ToBase64String(imageBytes);

    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("apikey", _apiKey),
        new KeyValuePair<string, string>("base64Image", $"data:image/png;base64,{base64}"),
        new KeyValuePair<string, string>("language", langCode) // One language per call
    });

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
    string json = await response.Content.ReadAsStringAsync();

    using var doc = JsonDocument.Parse(json);
    return doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("ParsedText")
        .GetString() ?? string.Empty;
}
// OCR.space: one language per call — multi-language requires multiple requests
public async Task<string> ExtractMultiLanguage(string imagePath)
{
    // First pass: English
    string englishText = await ExtractWithLanguage(imagePath, "eng");

    // Second pass: French (consumes another rate-limit slot, another API call)
    string frenchText = await ExtractWithLanguage(imagePath, "fre");

    // Manually merge results — no way to know which text belongs to which language
    return $"{englishText}\n{frenchText}";
}

private async Task<string> ExtractWithLanguage(string imagePath, string langCode)
{
    byte[] imageBytes = await File.ReadAllBytesAsync(imagePath);
    string base64 = Convert.ToBase64String(imageBytes);

    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("apikey", _apiKey),
        new KeyValuePair<string, string>("base64Image", $"data:image/png;base64,{base64}"),
        new KeyValuePair<string, string>("language", langCode) // One language per call
    });

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
    string json = await response.Content.ReadAsStringAsync();

    using var doc = JsonDocument.Parse(json);
    return doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("ParsedText")
        .GetString() ?? string.Empty;
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks

Public Class OCRSpace
    Private _apiKey As String
    Private _httpClient As HttpClient

    Public Async Function ExtractMultiLanguage(imagePath As String) As Task(Of String)
        ' First pass: English
        Dim englishText As String = Await ExtractWithLanguage(imagePath, "eng")

        ' Second pass: French (consumes another rate-limit slot, another API call)
        Dim frenchText As String = Await ExtractWithLanguage(imagePath, "fre")

        ' Manually merge results — no way to know which text belongs to which language
        Return $"{englishText}{vbLf}{frenchText}"
    End Function

    Private Async Function ExtractWithLanguage(imagePath As String, langCode As String) As Task(Of String)
        Dim imageBytes As Byte() = Await File.ReadAllBytesAsync(imagePath)
        Dim base64 As String = Convert.ToBase64String(imageBytes)

        Dim content = New FormUrlEncodedContent(New KeyValuePair(Of String, String)() {
            New KeyValuePair(Of String, String)("apikey", _apiKey),
            New KeyValuePair(Of String, String)("base64Image", $"data:image/png;base64,{base64}"),
            New KeyValuePair(Of String, String)("language", langCode) ' One language per call
        })

        Dim response = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", content)
        Dim json As String = Await response.Content.ReadAsStringAsync()

        Using doc = JsonDocument.Parse(json)
            Return doc.RootElement _
                .GetProperty("ParsedResults")(0) _
                .GetProperty("ParsedText") _
                .GetString() OrElse String.Empty
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

// IronOCR: multiple languages in a single read — one pass, correct output
public string ExtractMultiLanguage(string imagePath)
{
    var ocr = new IronTesseract();

    // Combine languages with + operator — processed simultaneously
    ocr.Language = OcrLanguage.English + OcrLanguage.French + OcrLanguage.German;

    var result = ocr.Read(imagePath);
    return result.Text; // Correctly interleaved multilingual output
}
// IronOCR: multiple languages in a single read — one pass, correct output
public string ExtractMultiLanguage(string imagePath)
{
    var ocr = new IronTesseract();

    // Combine languages with + operator — processed simultaneously
    ocr.Language = OcrLanguage.English + OcrLanguage.French + OcrLanguage.German;

    var result = ocr.Read(imagePath);
    return result.Text; // Correctly interleaved multilingual output
}
Imports IronOcr

Public Function ExtractMultiLanguage(imagePath As String) As String
    Dim ocr As New IronTesseract()

    ' Combine languages with + operator — processed simultaneously
    ocr.Language = OcrLanguage.English + OcrLanguage.French + OcrLanguage.German

    Dim result = ocr.Read(imagePath)
    Return result.Text ' Correctly interleaved multilingual output
End Function
$vbLabelText   $csharpLabel

A restrição de um único idioma por chamada do OCR.space força os desenvolvedores a fazerem N chamadas de API para um documento em N idiomas e a tentarem adivinhar como conciliar os resultados. O IronOCR combina modelos de linguagem em uma única passagem do mecanismo, o que produz uma saída corretamente intercalada sem pós-processamento. Pacotes de idiomas são instalados como pacotes NuGet — e assim por diante — e funcionam offline. O como processar múltiplos idiomas cobre a instalação dos pacotes e a sintaxe do operador para todos os 125+ idiomas suportados.

Extração de dados estruturados com coordenadas de palavras

OCR.space retorna texto simples de. Não há dados ao nível da palavra, nem caixas delimitadoras, nem limites de linha, nem pontuações de confiança por elemento. Aplicações que precisam localizar campos específicos — uma data no canto superior direito de uma fatura, um total na célula inferior direita de uma tabela — não têm uma base estruturada para se basear a partir da resposta do OCR.space. O IronOCR fornece uma hierarquia completa do documento: páginas, parágrafos, linhas, palavras e caracteres, cada um com coordenadas de pixel e pontuações de confiança.

Abordagem OCR.space:

// OCR.space: plain text only — no structure, no coordinates
public async Task<string> ExtractInvoiceFields(string invoicePath)
{
    byte[] invoiceBytes = await File.ReadAllBytesAsync(invoicePath);
    string base64 = Convert.ToBase64String(invoiceBytes);

    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("apikey", _apiKey),
        new KeyValuePair<string, string>("base64Image", $"data:application/pdf;base64,{base64}"),
        new KeyValuePair<string, string>("filetype", "PDF"),
        new KeyValuePair<string, string>("language", "eng"),
        // isOverlayRequired=true returns word boxes, but only as raw JSON coordinates
        new KeyValuePair<string, string>("isOverlayRequired", "true")
    });

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
    string json = await response.Content.ReadAsStringAsync();

    // Navigate deeply-nested JSON to find word boxes — no typed models
    using var doc = JsonDocument.Parse(json);
    var overlay = doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("TextOverlay");

    // Parse word coordinate arrays manually — fragile JSON path traversal
    var wordData = new List<(string word, int x, int y)>();
    foreach (var line in overlay.GetProperty("Lines").EnumerateArray())
    {
        foreach (var word in line.GetProperty("Words").EnumerateArray())
        {
            string wordText = word.GetProperty("WordText").GetString() ?? "";
            int left = word.GetProperty("Left").GetInt32();
            int top = word.GetProperty("Top").GetInt32();
            wordData.Add((wordText, left, top));
        }
    }

    // Reconstruct full text from raw JSON — still no typed result
    return string.Join(" ", wordData.Select(w => w.word));
}
// OCR.space: plain text only — no structure, no coordinates
public async Task<string> ExtractInvoiceFields(string invoicePath)
{
    byte[] invoiceBytes = await File.ReadAllBytesAsync(invoicePath);
    string base64 = Convert.ToBase64String(invoiceBytes);

    var content = new FormUrlEncodedContent(new[]
    {
        new KeyValuePair<string, string>("apikey", _apiKey),
        new KeyValuePair<string, string>("base64Image", $"data:application/pdf;base64,{base64}"),
        new KeyValuePair<string, string>("filetype", "PDF"),
        new KeyValuePair<string, string>("language", "eng"),
        // isOverlayRequired=true returns word boxes, but only as raw JSON coordinates
        new KeyValuePair<string, string>("isOverlayRequired", "true")
    });

    var response = await _httpClient.PostAsync("https://api.ocr.space/parse/image", content);
    string json = await response.Content.ReadAsStringAsync();

    // Navigate deeply-nested JSON to find word boxes — no typed models
    using var doc = JsonDocument.Parse(json);
    var overlay = doc.RootElement
        .GetProperty("ParsedResults")[0]
        .GetProperty("TextOverlay");

    // Parse word coordinate arrays manually — fragile JSON path traversal
    var wordData = new List<(string word, int x, int y)>();
    foreach (var line in overlay.GetProperty("Lines").EnumerateArray())
    {
        foreach (var word in line.GetProperty("Words").EnumerateArray())
        {
            string wordText = word.GetProperty("WordText").GetString() ?? "";
            int left = word.GetProperty("Left").GetInt32();
            int top = word.GetProperty("Top").GetInt32();
            wordData.Add((wordText, left, top));
        }
    }

    // Reconstruct full text from raw JSON — still no typed result
    return string.Join(" ", wordData.Select(w => w.word));
}
Imports System.IO
Imports System.Net.Http
Imports System.Text.Json
Imports System.Threading.Tasks

Public Class InvoiceProcessor
    Private _apiKey As String
    Private _httpClient As HttpClient

    Public Sub New(apiKey As String, httpClient As HttpClient)
        _apiKey = apiKey
        _httpClient = httpClient
    End Sub

    Public Async Function ExtractInvoiceFields(invoicePath As String) As Task(Of String)
        Dim invoiceBytes As Byte() = Await File.ReadAllBytesAsync(invoicePath)
        Dim base64 As String = Convert.ToBase64String(invoiceBytes)

        Dim content As New FormUrlEncodedContent(New KeyValuePair(Of String, String)() {
            New KeyValuePair(Of String, String)("apikey", _apiKey),
            New KeyValuePair(Of String, String)("base64Image", $"data:application/pdf;base64,{base64}"),
            New KeyValuePair(Of String, String)("filetype", "PDF"),
            New KeyValuePair(Of String, String)("language", "eng"),
            New KeyValuePair(Of String, String)("isOverlayRequired", "true")
        })

        Dim response As HttpResponseMessage = Await _httpClient.PostAsync("https://api.ocr.space/parse/image", content)
        Dim json As String = Await response.Content.ReadAsStringAsync()

        Using doc As JsonDocument = JsonDocument.Parse(json)
            Dim overlay = doc.RootElement _
                .GetProperty("ParsedResults")(0) _
                .GetProperty("TextOverlay")

            Dim wordData As New List(Of (word As String, x As Integer, y As Integer))()
            For Each line In overlay.GetProperty("Lines").EnumerateArray()
                For Each word In line.GetProperty("Words").EnumerateArray()
                    Dim wordText As String = word.GetProperty("WordText").GetString() OrElse ""
                    Dim left As Integer = word.GetProperty("Left").GetInt32()
                    Dim top As Integer = word.GetProperty("Top").GetInt32()
                    wordData.Add((wordText, left, top))
                Next
            Next

            Return String.Join(" ", wordData.Select(Function(w) w.word))
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

// IronOCR: full document hierarchy — typed, no JSON, no coordinates parsing
public void ExtractInvoiceFields(string invoicePath)
{
    var ocr = new IronTesseract();
    var result = ocr.Read(invoicePath);

    // Access the full document hierarchy — all strongly typed
    foreach (var page in result.Pages)
    {
        foreach (var paragraph in page.Paragraphs)
        {
            Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}");
        }

        foreach (var word in page.Words)
        {
            // Word-level confidence — identify low-quality extractions
            if (word.Confidence < 70)
                Console.WriteLine($"Low confidence word '{word.Text}' at ({word.X}, {word.Y})");
        }
    }

    // Or use region-based OCR to target specific invoice zones directly
    var totalRegion = new CropRectangle(400, 700, 200, 50); // Bottom-right total field
    using var input = new OcrInput();
    input.LoadImage(invoicePath, totalRegion);
    string totalText = ocr.Read(input).Text;
    Console.WriteLine($"Invoice total: {totalText}");
}
// IronOCR: full document hierarchy — typed, no JSON, no coordinates parsing
public void ExtractInvoiceFields(string invoicePath)
{
    var ocr = new IronTesseract();
    var result = ocr.Read(invoicePath);

    // Access the full document hierarchy — all strongly typed
    foreach (var page in result.Pages)
    {
        foreach (var paragraph in page.Paragraphs)
        {
            Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}");
        }

        foreach (var word in page.Words)
        {
            // Word-level confidence — identify low-quality extractions
            if (word.Confidence < 70)
                Console.WriteLine($"Low confidence word '{word.Text}' at ({word.X}, {word.Y})");
        }
    }

    // Or use region-based OCR to target specific invoice zones directly
    var totalRegion = new CropRectangle(400, 700, 200, 50); // Bottom-right total field
    using var input = new OcrInput();
    input.LoadImage(invoicePath, totalRegion);
    string totalText = ocr.Read(input).Text;
    Console.WriteLine($"Invoice total: {totalText}");
}
Imports IronOcr

Public Sub ExtractInvoiceFields(invoicePath As String)
    Dim ocr As New IronTesseract()
    Dim result = ocr.Read(invoicePath)

    ' Access the full document hierarchy — all strongly typed
    For Each page In result.Pages
        For Each paragraph In page.Paragraphs
            Console.WriteLine($"Paragraph at ({paragraph.X}, {paragraph.Y}): {paragraph.Text}")
        Next

        For Each word In page.Words
            ' Word-level confidence — identify low-quality extractions
            If word.Confidence < 70 Then
                Console.WriteLine($"Low confidence word '{word.Text}' at ({word.X}, {word.Y})")
            End If
        Next
    Next

    ' Or use region-based OCR to target specific invoice zones directly
    Dim totalRegion As New CropRectangle(400, 700, 200, 50) ' Bottom-right total field
    Using input As New OcrInput()
        input.LoadImage(invoicePath, totalRegion)
        Dim totalText As String = ocr.Read(input).Text
        Console.WriteLine($"Invoice total: {totalText}")
    End Using
End Sub
$vbLabelText   $csharpLabel

A flag do OCR.space retorna coordenadas de palavras em JSON, mas a estrutura da resposta requer navegação em arrays JSON aninhados com acesso a propriedades baseadas em string — sem modelo tipado, sem IntelliSense e com a travessia de caminho frágil que quebra se a estrutura da resposta for alterada. IronOCR's , e são objetos tipados .NET. A abordagem tem como alvo regiões específicas do documento diretamente, em vez de extrair o documento inteiro e filtrar por coordenadas posteriormente. O guia de instruções de leitura de resultados e o guia de OCR baseado em região abordam ambos os padrões em detalhes.

Referência de mapeamento da API OCR.space para o IronOCR

Conceito OCR.space Equivalente de IronOCR
Nenhum pacote NuGet dotnet add package IronOcr
construção Não é necessário — não há camada HTTP.
limitador de taxa Não é necessário — não há limites de taxa.
/ OcrInput
parâmetro de URI de dados input.LoadImage(bytes)
parâmetro de upload input.LoadImage(path)
cabeçalho / campo de formulário (uma vez na inicialização)
parâmetro (um por chamada) ocr.Language = OcrLanguage.English + OcrLanguage.French
(rápido) Motor padrão (Tesseract 5 otimizado)
(alta precisão) input.Desc(); input.DeNoise(); input.Contrast();
parâmetro input.Scale(200)
parâmetro input.Deskew()
parâmetro (sempre disponível, tipado)
parâmetro result.SaveAsSearchablePdf("output.pdf")
parâmetro input.LoadPdf(path)
ParsedResults[0].ParsedText result.Text
(texto por página) result.Pages[n].Text
TextOverlay.Lines[n].Words[n].WordText result.Pages[n].Words[n].Text
TextOverlay.Lines[n].Words[n].Left/Top result.Pages[n].Words[n].X / .Y
flag JSON padrão com mensagem
flag por página padrão com mensagem
HTTP 429 Muitas solicitações Não aplicável — sem limites de taxa
POCO personalizado (definido pelo usuário) (fornecido pelo NuGet)
personalizado (definido pelo usuário) Tipos de exceção padrão do .NET

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

Problema 1: Código assíncrono que existia apenas para HTTP

OCR.space: Cada chamada OCR é porque envolve uma viagem de ida e volta HTTP para a nuvem. Os métodos de serviço, as ações do controlador e as tarefas em segundo plano foram tornados assíncronos para evitar o bloqueio da thread durante a espera pela rede.

Solução: O método do IronOCR é síncrono. Remova / dos métodos que eram assíncronos puramente porque o OCR.space exigia. Em contextos ASP.NET Core, onde a execução não bloqueante é importante, envolva a chamada síncrona em ou use os padrões assíncronos documentados no guia de OCR assíncrono. Não adicione reflexivamente a chamadas IronOCR— não é necessário e adiciona sobrecarga desnecessária em contextos não web.

// Before: async because OCR.space required network I/O
public async Task<string> ProcessDocumentAsync(string path)
{
    return await _ocrSpaceClient.ExtractTextAsync(path); // Network wait
}

// After: synchronous — no network, no async needed
public string ProcessDocument(string path)
{
    return _ocr.Read(path).Text; // Local execution
}
// Before: async because OCR.space required network I/O
public async Task<string> ProcessDocumentAsync(string path)
{
    return await _ocrSpaceClient.ExtractTextAsync(path); // Network wait
}

// After: synchronous — no network, no async needed
public string ProcessDocument(string path)
{
    return _ocr.Read(path).Text; // Local execution
}
Imports System.Threading.Tasks

' Before: async because OCR.space required network I/O
Public Async Function ProcessDocumentAsync(path As String) As Task(Of String)
    Return Await _ocrSpaceClient.ExtractTextAsync(path) ' Network wait
End Function

' After: synchronous — no network, no async needed
Public Function ProcessDocument(path As String) As String
    Return _ocr.Read(path).Text ' Local execution
End Function
$vbLabelText   $csharpLabel

Problema 2: Infraestrutura de armazenamento e rotação de chaves de API

OCR.space: A chave de API deve ser injetada em cada solicitação. As equipes geralmente a armazenam em ou variáveis de ambiente, injetam através de ou injeção de construtor e a giram quando exposta. A rotação de chaves exige a atualização de cada ambiente de implantação e a reinicialização do aplicativo.

Solução: A chave de licença do IronOCR é definida uma única vez na inicialização e nunca mais é referenciada durante a execução. Remova o padrão de injeção de chave por requisição. Remova a classe de configuração. O padrão de inicialização principal consiste em uma única linha:

// Startup.cs or Program.cs — once only
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY");
// Startup.cs or Program.cs — once only
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY");
Imports System

' Startup.vb or Program.vb — once only
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
$vbLabelText   $csharpLabel

Não há injeção de credenciais por requisição, nenhum procedimento de rotação de chaves e nenhum risco de registrar acidentalmente a chave nos rastreamentos de requisição.

Problema 3: Lógica de pré-validação do tamanho do arquivo

OCR.space: O plano gratuito rejeita arquivos com mais de 5 MB, exibindo uma mensagem de erro. O código de produção adiciona uma verificação do tamanho do arquivo antes de cada requisição para evitar o desperdício de um slot de limite de taxa em uma chamada que falhará:

// OCR.space: pre-validation to avoid wasting quota on large files
var fileInfo = new FileInfo(filePath);
if (fileInfo.Length > 5 * 1024 * 1024)
    throw new InvalidOperationException("File exceeds 5MB free tier limit.");
// OCR.space: pre-validation to avoid wasting quota on large files
var fileInfo = new FileInfo(filePath);
if (fileInfo.Length > 5 * 1024 * 1024)
    throw new InvalidOperationException("File exceeds 5MB free tier limit.");
Dim fileInfo As New FileInfo(filePath)
If fileInfo.Length > 5 * 1024 * 1024 Then
    Throw New InvalidOperationException("File exceeds 5MB free tier limit.")
End If
$vbLabelText   $csharpLabel

Solução: Elimine completamente essa verificação.IronOCR e não têm limite de tamanho além da memória disponível do sistema. O limite artificial de 5 MB existe apenas porque o plano gratuito do OCR.space o impõe por questões de capacidade do servidor. Um PDF digitalizado de 50 MB carrega da mesma forma que um de 500 KB.

Problema 4: Fragilidade na navegação de respostas JSON

OCR.space: A análise de respostas depende da navegação com acesso a propriedades baseadas em string. Código como lança se a forma da resposta mudar e se estiver vazio. Ambos exigem blocos try-catch ou verificações de valor nulo em todo o código.

Solução:IronOCR retorna um objeto tipado. A propriedade é sempre — nunca nula, nunca ausente. Se o OCR não produzir saída (página em branco, imagem ilegível), é uma string vazia. Não há JSON para navegar e nenhuma fragilidade de caminho de propriedade para se proteger. Para filtragem baseada em confiança, retorna um que você pode comparar diretamente:

// IronOCR: typed result — no JSON path fragility
var result = new IronTesseract().Read("document.jpg");

if (result.Confidence < 50)
    Console.WriteLine("Low confidence — consider preprocessing");
else
    Console.WriteLine(result.Text);
// IronOCR: typed result — no JSON path fragility
var result = new IronTesseract().Read("document.jpg");

if (result.Confidence < 50)
    Console.WriteLine("Low confidence — consider preprocessing");
else
    Console.WriteLine(result.Text);
Imports IronOcr

Dim result = New IronTesseract().Read("document.jpg")

If result.Confidence < 50 Then
    Console.WriteLine("Low confidence — consider preprocessing")
Else
    Console.WriteLine(result.Text)
End If
$vbLabelText   $csharpLabel

O guia sobre como calcular os índices de confiança abrange os limites de confiança por palavra e por documento.

Problema 5: Esgotamento do limite de taxa de IP compartilhado em CI/CD

OCR.space: Os pipelines de CI/CD que executam testes de integração no OCR.space usam o mesmo endereço IP de saída da rede do escritório de desenvolvimento. As contas do plano gratuito compartilham um limite de 500 solicitações por dia por IP. Um pipeline que processa 200 documentos de teste por execução pode esgotar a cota diária antes mesmo do primeiro desenvolvedor executar um teste manual. As equipes contornam isso simulando as respostas do OCR.space nos testes, o que anula o propósito dos testes de integração.

Solução: O IronOCR processa os dados localmente. O conjunto de testes chama diretamente — nenhum simulado necessário, sem cota para esgotar, sem dependência de rede. Os testes de integração são executados em CI/CD com os mesmos resultados reais de OCR que a produção, sem qualquer gerenciamento de limite de taxa ou padrões de isolamento de testes.

Problema 6: Padrão de IDisposable da Gerência de HttpClient

OCR.space: A classe wrapper implementa para liberar o pool de conexões HTTP. Todos os consumidores do serviço OCR devem injetar um singleton, usar blocos, ou registrá-lo com o ciclo de vida de eliminação do contêiner DI. O esquecimento de descartar corretamente causa o desgaste da tomada sob carga.

Solução: não gerencia conexões de rede. Não implementa. Crie uma instância por thread (ou por solicitação em ASP.NET), chame e deixe o GC coletá-la. A classe implementa e deve ser envolvida em blocos quando o pré-processamento é aplicado, mas a classe primária não precisa de gerenciamento de ciclo de vida. Remova a implementação do seu wrapper de serviço OCR e simplifique o registro DI de scoped/transient com eliminação para uma fábrica simples ou singleton.

Lista de verificação para migração do OCR.space

Tarefas pré-migração

Realize uma auditoria no código-fonte para identificar todos os pontos de integração do OCR.space:

# Find all OCR.space HTTP calls
grep -rn "ocr.space" --include="*.cs" .

# Find all base64 encoding related to OCR
grep -rn "base64Image\|Convert.ToBase64String" --include="*.cs" .

# Find rate limiter and retry logic
grep -rn "SemaphoreSlim\|TooManyRequests\|exponential" --include="*.cs" .

# Find JSON parsing for OCR responses
grep -rn "ParsedResults\|IsErroredOnProcessing\|FileParseExitCode" --include="*.cs" .

# Find custom OCR models and exception types
grep -rn "OcrSpaceException\|OcrResult\b" --include="*.cs" .

# Find API key configuration
grep -rn "apikey\|OcrSpaceApiKey\|ocr_space" --include="*.cs" --include="*.json" .
# Find all OCR.space HTTP calls
grep -rn "ocr.space" --include="*.cs" .

# Find all base64 encoding related to OCR
grep -rn "base64Image\|Convert.ToBase64String" --include="*.cs" .

# Find rate limiter and retry logic
grep -rn "SemaphoreSlim\|TooManyRequests\|exponential" --include="*.cs" .

# Find JSON parsing for OCR responses
grep -rn "ParsedResults\|IsErroredOnProcessing\|FileParseExitCode" --include="*.cs" .

# Find custom OCR models and exception types
grep -rn "OcrSpaceException\|OcrResult\b" --include="*.cs" .

# Find API key configuration
grep -rn "apikey\|OcrSpaceApiKey\|ocr_space" --include="*.cs" --include="*.json" .
SHELL

Documente a lista de arquivos que contêm o código OCR.space. Observe quais métodos são exclusivamente devido à dependência HTTP do OCR.space — estes podem ser feitos síncronos após a migração.

Tarefas de atualização de código

  1. Instale o pacote NuGet:
  2. Adicione ao início da aplicação
  3. Exclua a classe e toda a infraestrutura de suporte
  4. Exclua o POCO personalizado (substituído por )
  5. Exclua a classe personalizada (substituída por exceções padrão do .NET)
  6. Exclua o limitador de taxa e a lógica de Task.Delay associada
  7. Remova todas as chamadas usadas para codificação de imagem OCR
  8. Substitua / construção por
  9. Substitua chamadas por
  10. Substitua a análise de de por
  11. Substitua a análise de coordenadas JSON por
  12. Substitua a troca de parâmetros por filtros de pré-processamento apropriados
  13. Substitua strings de parâmetros por valores enumerados
  14. Remover verificações de pré-validação do tamanho do arquivo (o limite de 5 MB não se aplica mais)
  15. Converta métodos OCR em síncronos onde HTTP era a única razão assíncrona
  16. Remova a chave da API OCR.space dos arquivos de configuração e da configuração das variáveis ​​de ambiente.

Testes pós-migração

  • Verificar se a extração de texto produz precisão equivalente ou superior nos mesmos documentos de teste.
  • Confirme se os arquivos grandes (acima de 5 MB) são processados ​​sem erros.
  • Teste documentos multilíngues com e verifique a saída entrelaçada
  • Execute o pipeline de CI/CD com chamadas OCR reais — confirme que não há erros de limite de taxa em nenhum volume de documentos.
  • Verificar se o PDF pesquisável não possui marcas d'água.
  • Verifique se as ações do controlador anteriormente assíncronas ainda respondem corretamente após a conversão para síncrono.
  • Testar se ambientes de implantação isolados da internet ou com restrição de rede processam documentos sem erros.
  • Confirme que os valores são aceitáveis em documentos que anteriormente exigiam
  • Verifique se as coordenadas correspondem às posições esperadas dos campos em documentos estruturados
  • Teste se a inicialização da licença do aplicativo é bem-sucedida antes da primeira chamada de OCR.

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

A taxa de infraestrutura para mais de 80 linhas desaparece. Cada integração com o OCR.space inclui um cliente HTTP, um limitador de taxa, um desserializador JSON, tipos de exceção personalizados e modelos de resultados personalizados. Nenhum desse código faz nada que o aplicativo realmente precise — ele existe para compensar a ausência do SDK do OCR.space. Após a migração, esse código é apagado. A área superficial de OCR no código se reduz a no local de chamada e uma linha de inicialização de licença na inicialização.

A velocidade de processamento de documentos passa a depender do hardware local. O OCR.space introduz latência de rede, profundidade da fila do servidor OCR.space e tempo de ida e volta geográfico em cada operação de processamento. O IronOCR é executado durante o processo. Uma estação de trabalho local processa documentos mais rapidamente do que qualquer API na nuvem, em qualquer nível de taxa de transferência, sem o limite de 60 solicitações por minuto que serializa o processamento em lote. O processamento paralelo com em várias instâncias escala com os núcleos do CPU — veja o exemplo de multithreading.

Documentos confidenciais permanecem permanentemente dentro da sua infraestrutura. Após a migração, registros médicos, documentos financeiros, contratos legais e documentos de identidade nunca saem do servidor de aplicativos. As revisões de conformidade com HIPAA, GDPR, SOC 2 e políticas internas de classificação de dados não precisam mais incluir as práticas de tratamento de dados da OCR.space em seu escopo. A superfície de auditoria se reduz à sua própria infraestrutura. O guia de implantação do Docker e o guia de implantação do Azure abordam a implantação do IronOCR em ambientes conteinerizados e em nuvem que exigem conformidade com a residência de dados.

A saída estruturada habilita aplicativos de inteligência documental. A string do OCR.space é o fim do caminho para a análise de documentos. Os do IronOCR, com coordenadas e pontuações de confiança por palavra, permitem que os aplicativos localizem campos específicos, validem a qualidade da extração, extraiam dados de tabelas e construam pipelines de inteligência documental a jusante. Funcionalidades que exigiam a criação de análises de layout personalizadas com base na saída de texto simples do OCR.space agora podem ser feitas por meio de chamadas diretas à API. O guia de extração de tabelas e o guia de processamento de documentos digitalizados demonstram o que essa base estruturada possibilita.

O custo torna-se fixo e previsível, independentemente do volume. O plano gratuito do OCR.space cobre 25.000 solicitações por mês. Acima disso, os custos de assinatura aumentam proporcionalmente ao uso. A licença Lite perpétua do IronOCR não cobra por documento em qualquer volume. Uma equipe que processa 100.000 documentos por mês paga a mesma taxa de licença que uma equipe que processa 1.000 documentos por mês. A previsão orçamentária para aplicativos de processamento de documentos passa a ser um custo anual fixo, em vez de uma rubrica variável que cresce com o sucesso do negócio. A página do produto IronOCR inclui um período de teste gratuito que permite às equipes validar a precisão em seus tipos de documentos específicos antes da compra.

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

Perguntas frequentes

Por que devo migrar da API do OCR.space para o IronOCR?

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

Quais são as principais alterações de código ao migrar da API OCR.space para o IronOCR?

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

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

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

O IronOCR atinge a mesma precisão de OCR da API OCR.space para documentos comerciais padrão?

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

Como o IronOCR lida com os dados de idioma que a API OCR.space instala separadamente?

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

A migração da API do OCR.space para o IronOCR requer alterações na infraestrutura de implantação?

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

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

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

O IronOCR consegue processar PDFs da mesma forma que o OCR.space?

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

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

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

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

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

O preço do IronOCR é mais previsível do que a API do OCR.space para dimensionamento de cargas de trabalho?

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

O que acontece com meus testes existentes após a migração da API do OCR.space para o IronOCR?

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

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

Equipe de Suporte Iron

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