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

Como extrair texto árabe de imagens usando ferramentas de OCR

Este guia orienta os desenvolvedores .NET em uma migração completa do OCR GdPicture .NET para o IronOCR . Este documento aborda a troca de pacotes, as alterações de namespace e os padrões práticos de código antes e depois para cada fluxo de trabalho OCR principal, com foco especial na eliminação do ciclo de vida do ID de imagem inteiro que define o modelo de gerenciamento de recursos do GdPicture. Não é necessário ler o artigo comparativo previamente.

Por que migrar do GdPicture .NET?

GdPicture .NET é uma plataforma de digitalização de documentos criada para equipes que precisam de integração com scanners, suporte a DICOM, edição de PDF, anotações e OCR, tudo em um único fornecedor. Quando o OCR é o único requisito, o preço da plataforma e a arquitetura da API criam atritos que se acumulam ao longo do tempo.

Custo do Plugin para um Fluxo de Trabalho OCR Básico. Extrair texto de PDFs digitalizados e gerar resultados pesquisáveis ​​requer três componentes de licença separados: o SDK principal por aproximadamente US$ 4.000, o Plugin OCR por aproximadamente US$ 2.000 e o Plugin PDF por aproximadamente US$ 2.000. Isso resulta em um custo inicial de US$ 8.000, Plus 20% de manutenção anual. Equipes que precisam apenas de OCR absorvem toda a estrutura de preços de uma plataforma de digitalização de documentos.IronOCR cobre o mesmo fluxo de trabalho — OCR de imagem, OCR de PDF, pré-processamento, saída de PDF pesquisável — de um único pacote por $999 até $2,999 perpétuos, sem decisões de licenciamento por recurso. Consulte a página de licenciamento do IronOCR para obter uma descrição completa dos níveis de licenciamento.

O Ciclo de Vida do ID de Imagem Inteiro. Toda imagem carregada através do GdPicture retorna um int. Você passa esse inteiro para operações de OCR, então chama ReleaseGdPictureImage com ele quando terminar. Esse padrão precede IDisposable. Funciona quando seguido corretamente; Vazamento de memória ocorre quando ocorre uma falha. Em serviços de produção que processam centenas de documentos diariamente, uma chamada de liberação perdida em um ramo com erro gera um aumento de memória que é realmente difícil de diagnosticar. O OcrInput do IronOCR implementa IDisposable — uma declaração using elimina todo o encargo de limpeza.

Namespace Específico de Versão. O GdPicture incorpora o número da versão principal em seu namespace: using GdPicture14. Atualizar para a próxima versão principal requer a atualização dessa diretiva using em cada arquivo fonte que referencia as classes GdPicture. Uma aplicação complexa com OCR distribuída por dezenas de serviços transforma essa tarefa de localizar e substituir em algo que leva várias horas e não traz nenhuma melhoria funcional. O namespace do IronOCR foi IronOcr em todas as versões principais.

Requisito de Pasta de Recursos Externos. O OCR do GdPicture requer uma propriedade ResourceFolder apontando para um diretório de arquivos de linguagem .traineddata em tempo de execução. Esse caminho funciona em uma máquina de desenvolvimento, mas quebra em servidores Linux, contêineres Docker, e implantações Azure App Service onde a estrutura de diretórios não existe. O IronOCR incorpora o suporte ao idioma inglês dentro do pacote NuGet; Idiomas adicionais são instalados como pacotes NuGet que acompanham o resultado da compilação.

Inicialização de Três Componentes. Um fluxo de trabalho de OCR de PDF no GdPicture requer instanciar GdPictureImaging, GdPictureOCR e GdPicturePDF — três componentes separados com requisitos individuais de descarte — além da inscrição do gerenciador de licenças e a atribuição da pasta de recursos. O IronOCR requer uma linha na inicialização e uma classe no momento da chamada.

Sem segurança de threads nativa. As instâncias de OCR do GdPicture não são thread-safe. O processamento paralelo de documentos exige um gerenciamento cuidadoso das instâncias e sincronização para evitar estados corrompidos. O IronOCR é projetado para uso simultâneo: crie um IronTesseract por thread ou compartilhe uma única instância sob carga — qualquer padrão funciona sem código de sincronização adicional.

O problema fundamental

O GdPicture aloca memória para cada imagem como um identificador inteiro gerenciado em tempo de execução. Cada chamada RenderPageToGdPictureImage em um loop de processamento TIFF cria uma nova alocação que deve ser liberada manualmente:

// GdPicture: every frame = new integer ID = manual release required
using var pdf = new GdPicturePDF();
pdf.LoadFromFile("multi-page.tiff", false);

var frameIds = new List<int>();
try
{
    for (int i = 1; i <= pdf.GetPageCount(); i++)
    {
        pdf.SelectPage(i);
        int frameId = pdf.RenderPageToGdPictureImage(200, false); // new allocation
        if (frameId != 0) frameIds.Add(frameId);
        // ... OCR call here ...
    }
}
finally
{
    foreach (var id in frameIds) _imaging.ReleaseGdPictureImage(id); // manual per-frame release
}
// GdPicture: every frame = new integer ID = manual release required
using var pdf = new GdPicturePDF();
pdf.LoadFromFile("multi-page.tiff", false);

var frameIds = new List<int>();
try
{
    for (int i = 1; i <= pdf.GetPageCount(); i++)
    {
        pdf.SelectPage(i);
        int frameId = pdf.RenderPageToGdPictureImage(200, false); // new allocation
        if (frameId != 0) frameIds.Add(frameId);
        // ... OCR call here ...
    }
}
finally
{
    foreach (var id in frameIds) _imaging.ReleaseGdPictureImage(id); // manual per-frame release
}
Imports System.Collections.Generic

' GdPicture: every frame = new integer ID = manual release required
Using pdf As New GdPicturePDF()
    pdf.LoadFromFile("multi-page.tiff", False)

    Dim frameIds As New List(Of Integer)()
    Try
        For i As Integer = 1 To pdf.GetPageCount()
            pdf.SelectPage(i)
            Dim frameId As Integer = pdf.RenderPageToGdPictureImage(200, False) ' new allocation
            If frameId <> 0 Then frameIds.Add(frameId)
            ' ... OCR call here ...
        Next
    Finally
        For Each id In frameIds
            _imaging.ReleaseGdPictureImage(id) ' manual per-frame release
        Next
    End Try
End Using
$vbLabelText   $csharpLabel

O IronOCR elimina completamente o ciclo de vida. OcrInput lida com enumeração de quadros e limpeza:

// IronOCR: the using statement handles everything
using var input = new OcrInput();
input.LoadImageFrames("multi-page.tiff");
var result = new IronTesseract().Read(input);
// IronOCR: the using statement handles everything
using var input = new OcrInput();
input.LoadImageFrames("multi-page.tiff");
var result = new IronTesseract().Read(input);
Imports IronOcr

Dim input As New OcrInput()
Using input
    input.LoadImageFrames("multi-page.tiff")
    Dim result = New IronTesseract().Read(input)
End Using
$vbLabelText   $csharpLabel

IronOCR vs GdPicture .NET: Comparação de Recursos

A tabela abaixo mostra a cobertura entre as duas bibliotecas para fluxos de trabalho focados em OCR.

Recurso GdPicture.NET IronOCR
Instalação Vários pacotes NuGet dotnet add package IronOcr
Ativação de licença LicenseManager.RegisterKEY() IronOcr.License.LicenseKey = "..."
Namespace em atualização principal Requer localizar-e-substituir (GdPicture14 → próximo) Inalterado (IronOcr)
Inicialização de componentes GdPictureImaging + GdPictureOCR + GdPicturePDF new IronTesseract()
Modelo de memória de recursos Rastreamento e liberação manual de IDs inteiros declaração IDisposable / using
risco de vazamento de memória Alto (faltando ReleaseGdPictureImage) Nenhum (enforçado pelo compilador via using)
Pasta de recursos externos Necessário (_ocr.ResourceFolder = path) Não é necessário — incluído no pacote.
OCR de imagem Sim Sim
OCR de PDF Sim (requer o plugin PDF) Integrado, sem necessidade de licença adicional.
TIFF de várias páginas Loop de quadros manual + limpeza de ID por quadro input.LoadImageFrames()
Entrada de fluxo Via sobrecarga de fluxo GdPictureImaging input.LoadImage(stream)
Saída em PDF pesquisável pdf.OcrPage() + pdf.SaveToFile() result.SaveAsSearchablePdf()
Pré-processamento de correção de distorção É necessário o plugin de digitalização de documentos. input.Deskew() — embutido
Remoção de ruído É necessário o plugin de digitalização de documentos. input.DeNoise() — embutido
Línguas Arquivos de dados treinados baseados em Tesseract na pasta Mais de 125 pacotes NuGet
OCR multilíngue Sim OcrLanguage.French + OcrLanguage.German
Segurança da rosca Gerenciamento manual de instâncias Projetado para ser seguro contra roscas.
OCR assíncrono Não embutido ReadAsync()
Leitura de código de barras Plugin de código de barras separado ocr.Configuration.ReadBarCodes = true
Saída estruturada Acesso baseado em índice a blocos/linhas/palavras Digitado .Pages, .Words, .Characters
Pontuação de confiança GetOCRResultConfidence(resultId) result.Confidence
Multiplataforma Windows, Linux, macOS Windows, Linux, macOS, Docker, AWS, Azure
Custo de entrada (OCR a partir de PDFs) Aproximadamente US$ 8.000 (Núcleo + OCR + plugins de PDF) $999–$2,999
Modelo de preços Licença perpétua baseada em plugins + manutenção de 20% ao ano. Plano perpétuo, com atualizações anuais opcionais.
Apoio comercial Sim Sim

Guia rápido: Migração do GdPicture .NET para o IronOCR

Passo 1: Substitua o pacote NuGet

Remova os pacotes GdPicture:

dotnet remove package GdPicture.NET
dotnet remove package GdPicture.NET.OCR
dotnet remove package GdPicture.NET.PDF
dotnet remove package GdPicture.NET
dotnet remove package GdPicture.NET.OCR
dotnet remove package GdPicture.NET.PDF
SHELL

Instale o IronOCR a partir da página de pacotes NuGet :

dotnet add package IronOcr

Para idiomas além do inglês, instale o pacote de idiomas correspondente:

dotnet add package IronOcr.Languages.French, IronOcr.Languages.German

Etapa 2: Atualizar Namespaces

Substitua o namespace GdPicture pelo namespace IronOCR:

// Before (GdPicture)
using GdPicture14;

// After (IronOCR)
using IronOcr;
// Before (GdPicture)
using GdPicture14;

// After (IronOCR)
using IronOcr;
Imports IronOcr
$vbLabelText   $csharpLabel

Etapa 3: Inicializar a licença

Coloque esta linha em Program.cs ou Startup.cs, antes de qualquer chamada de OCR:

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

Remova completamente o bloco de registro de licença do GdPicture:

// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
// Remove this
LicenseManager lm = new LicenseManager();
lm.RegisterKEY("GDPICTURE-LICENSE-KEY");
$vbLabelText   $csharpLabel

Uma chave de avaliação gratuita está disponível na página do produto IronOCR para que você possa avaliá-lo antes de comprar.

Exemplos de migração de código

Processamento de quadros TIFF de várias páginas

O processamento de arquivos TIFF com várias páginas no GdPicture exige a seleção de cada quadro por meio da API PDF/imagens, a renderização para um novo ID de imagem, a execução do OCR e a liberação do ID. Um único quadro que não é liberado no bloco finally vaza 10–50 MB dependendo do DPI.

Abordagem GdPicture .NET :

using GdPicture14;

public class GdPictureTiffProcessor
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public string ExtractTextFromTiff(string tiffPath)
    {
        var text = new StringBuilder();

        // Load TIFF through the imaging component
        int tiffId = _imaging.CreateGdPictureImageFromFile(tiffPath);

        if (tiffId == 0)
            throw new Exception($"TIFF load failed: {_imaging.GetStat()}");

        // Outer try: release the original TIFF handle
        try
        {
            int frameCount = _imaging.GetPageCount(tiffId);

            for (int i = 1; i <= frameCount; i++)
            {
                // Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i);

                // Clone frame to a new image ID for OCR
                int frameId = _imaging.CloneImage(tiffId);

                if (frameId == 0) continue;

                // Inner try: release each cloned frame ID
                try
                {
                    _ocr.SetImage(frameId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (!string.IsNullOrEmpty(resultId))
                    {
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}");
                    }
                }
                finally
                {
                    // Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId);
                }
            }
        }
        finally
        {
            // Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId);
        }

        return text.ToString();
    }
}
using GdPicture14;

public class GdPictureTiffProcessor
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public string ExtractTextFromTiff(string tiffPath)
    {
        var text = new StringBuilder();

        // Load TIFF through the imaging component
        int tiffId = _imaging.CreateGdPictureImageFromFile(tiffPath);

        if (tiffId == 0)
            throw new Exception($"TIFF load failed: {_imaging.GetStat()}");

        // Outer try: release the original TIFF handle
        try
        {
            int frameCount = _imaging.GetPageCount(tiffId);

            for (int i = 1; i <= frameCount; i++)
            {
                // Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i);

                // Clone frame to a new image ID for OCR
                int frameId = _imaging.CloneImage(tiffId);

                if (frameId == 0) continue;

                // Inner try: release each cloned frame ID
                try
                {
                    _ocr.SetImage(frameId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (!string.IsNullOrEmpty(resultId))
                    {
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}");
                    }
                }
                finally
                {
                    // Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId);
                }
            }
        }
        finally
        {
            // Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId);
        }

        return text.ToString();
    }
}
Imports GdPicture14
Imports System.Text

Public Class GdPictureTiffProcessor
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR

    Public Function ExtractTextFromTiff(tiffPath As String) As String
        Dim text As New StringBuilder()

        ' Load TIFF through the imaging component
        Dim tiffId As Integer = _imaging.CreateGdPictureImageFromFile(tiffPath)

        If tiffId = 0 Then
            Throw New Exception($"TIFF load failed: {_imaging.GetStat()}")
        End If

        ' Outer try: release the original TIFF handle
        Try
            Dim frameCount As Integer = _imaging.GetPageCount(tiffId)

            For i As Integer = 1 To frameCount
                ' Switch to frame — modifies the existing ID in place
                _imaging.SelectPage(tiffId, i)

                ' Clone frame to a new image ID for OCR
                Dim frameId As Integer = _imaging.CloneImage(tiffId)

                If frameId = 0 Then Continue For

                ' Inner try: release each cloned frame ID
                Try
                    _ocr.SetImage(frameId)
                    _ocr.Language = "eng"

                    Dim resultId As String = _ocr.RunOCR()

                    If Not String.IsNullOrEmpty(resultId) Then
                        text.AppendLine($"[Frame {i}] {_ocr.GetOCRResultText(resultId)}")
                    End If
                Finally
                    ' Release cloned frame — critical for each iteration
                    _imaging.ReleaseGdPictureImage(frameId)
                End Try
            Next
        Finally
            ' Release original TIFF handle
            _imaging.ReleaseGdPictureImage(tiffId)
        End Try

        Return text.ToString()
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

using IronOcr;

public class IronOcrTiffProcessor
{
    public string ExtractTextFromTiff(string tiffPath)
    {
        using var input = new OcrInput();
        input.LoadImageFrames(tiffPath);  // all frames loaded, all cleanup automatic

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

        // Per-frame text is available on result.Pages
        foreach (var page in result.Pages)
            Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}");

        return result.Text;
    }
}
using IronOcr;

public class IronOcrTiffProcessor
{
    public string ExtractTextFromTiff(string tiffPath)
    {
        using var input = new OcrInput();
        input.LoadImageFrames(tiffPath);  // all frames loaded, all cleanup automatic

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

        // Per-frame text is available on result.Pages
        foreach (var page in result.Pages)
            Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}");

        return result.Text;
    }
}
Imports IronOcr

Public Class IronOcrTiffProcessor
    Public Function ExtractTextFromTiff(tiffPath As String) As String
        Using input As New OcrInput()
            input.LoadImageFrames(tiffPath) ' all frames loaded, all cleanup automatic

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

            ' Per-frame text is available on result.Pages
            For Each page In result.Pages
                Console.WriteLine($"[Frame {page.PageNumber}] {page.Text}")
            Next

            Return result.Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

LoadImageFrames carrega cada quadro de um TIFF de várias páginas no pipeline OcrInput. O bloco using lida com toda a memória associada a cada quadro no final do escopo. Nenhum List<int> para manter, nenhum bloco try/finally necessário. O guia de entrada TIFF e GIF aborda em detalhes a seleção de quadros e o processamento de múltiplos formatos.

Inicialização de plugins para substituição de entrada baseada em fluxo

Os aplicativos de servidor frequentemente recebem documentos como fluxos em vez de caminhos de arquivo — de uploads HTTP, filas de mensagens ou blobs de banco de dados. O GdPicture requer o carregamento do fluxo através de GdPictureImaging, que por si só requer a sequência de inicialização do componente e a configuração da pasta de recursos que precedem cada operação.

Abordagem GdPicture .NET :

using GdPicture14;

public class GdPictureStreamOcr : IDisposable
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public GdPictureStreamOcr()
    {
        // Plugin initialization required before stream loading is possible
        var lm = new LicenseManager();
        lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

        _imaging = new GdPictureImaging();
        _ocr = new GdPictureOCR();
        _ocr.ResourceFolder = @"C:\GdPicture\Resources\OCR"; // path must exist at runtime
    }

    public string ExtractTextFromStream(Stream documentStream)
    {
        // Load stream into imaging component to get an image ID
        int imageId = _imaging.CreateGdPictureImageFromStream(documentStream);

        if (imageId == 0)
            throw new Exception($"Stream load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            return _ocr.GetOCRResultText(resultId);
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }
    }

    public void Dispose()
    {
        _ocr?.Dispose();
        _imaging?.Dispose();
    }
}
using GdPicture14;

public class GdPictureStreamOcr : IDisposable
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public GdPictureStreamOcr()
    {
        // Plugin initialization required before stream loading is possible
        var lm = new LicenseManager();
        lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

        _imaging = new GdPictureImaging();
        _ocr = new GdPictureOCR();
        _ocr.ResourceFolder = @"C:\GdPicture\Resources\OCR"; // path must exist at runtime
    }

    public string ExtractTextFromStream(Stream documentStream)
    {
        // Load stream into imaging component to get an image ID
        int imageId = _imaging.CreateGdPictureImageFromStream(documentStream);

        if (imageId == 0)
            throw new Exception($"Stream load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            return _ocr.GetOCRResultText(resultId);
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }
    }

    public void Dispose()
    {
        _ocr?.Dispose();
        _imaging?.Dispose();
    }
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

Abordagem IronOCR:

using IronOcr;

public class IronOcrStreamOcr
{
    public string ExtractTextFromStream(Stream documentStream)
    {
        using var input = new OcrInput();
        input.LoadImage(documentStream);  // stream accepted directly — no imaging component

        return new IronTesseract().Read(input).Text;
    }
}
using IronOcr;

public class IronOcrStreamOcr
{
    public string ExtractTextFromStream(Stream documentStream)
    {
        using var input = new OcrInput();
        input.LoadImage(documentStream);  // stream accepted directly — no imaging component

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

Public Class IronOcrStreamOcr
    Public Function ExtractTextFromStream(documentStream As Stream) As String
        Using input As New OcrInput()
            input.LoadImage(documentStream) ' stream accepted directly — no imaging component

            Return New IronTesseract().Read(input).Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

A abordagem GdPicture requer a construção de três objetos e a configuração de um caminho no sistema de arquivos antes que o primeiro fluxo possa ser consumido. O IronOCR aceita o fluxo diretamente em OcrInput sem configuração prévia. O guia de entrada de fluxo cobre array de bytes, MemoryStream, e padrões FileStream para arquiteturas de pipeline onde gravações de arquivos temporários são indesejáveis.

OCR assíncrono substituindo a sondagem de código de status

O OCR do GdPicture é síncrono. Aplicativos que processam documentos em endpoints ASP.NET Core ou serviços em segundo plano devem envolver RunOCR em Task.Run para evitar bloquear threads de solicitação — e então gerenciar o ciclo de vida do ID da imagem através da fronteira do thread. O IronOCR oferece suporte a async de primeira classe através de ReadAsync.

Abordagem GdPicture .NET :

using GdPicture14;
using System.Threading.Tasks;

public class GdPictureAsyncWrapper
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;
    private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // Must acquire lock: GdPictureOCR is not thread-safe
        await _lock.WaitAsync();

        try
        {
            return await Task.Run(() =>
            {
                int imageId = _imaging.CreateGdPictureImageFromFile(imagePath);

                if (imageId == 0)
                    throw new Exception($"Load failed: {_imaging.GetStat()}");

                try
                {
                    _ocr.SetImage(imageId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (string.IsNullOrEmpty(resultId))
                        throw new Exception($"OCR failed: {_ocr.GetStat()}");

                    return _ocr.GetOCRResultText(resultId);
                }
                finally
                {
                    _imaging.ReleaseGdPictureImage(imageId);
                }
            });
        }
        finally
        {
            _lock.Release();
        }
    }
}
using GdPicture14;
using System.Threading.Tasks;

public class GdPictureAsyncWrapper
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;
    private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // Must acquire lock: GdPictureOCR is not thread-safe
        await _lock.WaitAsync();

        try
        {
            return await Task.Run(() =>
            {
                int imageId = _imaging.CreateGdPictureImageFromFile(imagePath);

                if (imageId == 0)
                    throw new Exception($"Load failed: {_imaging.GetStat()}");

                try
                {
                    _ocr.SetImage(imageId);
                    _ocr.Language = "eng";

                    string resultId = _ocr.RunOCR();

                    if (string.IsNullOrEmpty(resultId))
                        throw new Exception($"OCR failed: {_ocr.GetStat()}");

                    return _ocr.GetOCRResultText(resultId);
                }
                finally
                {
                    _imaging.ReleaseGdPictureImage(imageId);
                }
            });
        }
        finally
        {
            _lock.Release();
        }
    }
}
Imports GdPicture14
Imports System.Threading.Tasks

Public Class GdPictureAsyncWrapper
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR
    Private ReadOnly _lock As New SemaphoreSlim(1, 1)

    Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
        ' Must acquire lock: GdPictureOCR is not thread-safe
        Await _lock.WaitAsync()

        Try
            Return Await Task.Run(Function()
                                      Dim imageId As Integer = _imaging.CreateGdPictureImageFromFile(imagePath)

                                      If imageId = 0 Then
                                          Throw New Exception($"Load failed: {_imaging.GetStat()}")
                                      End If

                                      Try
                                          _ocr.SetImage(imageId)
                                          _ocr.Language = "eng"

                                          Dim resultId As String = _ocr.RunOCR()

                                          If String.IsNullOrEmpty(resultId) Then
                                              Throw New Exception($"OCR failed: {_ocr.GetStat()}")
                                          End If

                                          Return _ocr.GetOCRResultText(resultId)
                                      Finally
                                          _imaging.ReleaseGdPictureImage(imageId)
                                      End Try
                                  End Function)
        Finally
            _lock.Release()
        End Try
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

using IronOcr;

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

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // ReadAsync is natively async — no Task.Run wrapper, no lock required
        var result = await _ocr.ReadAsync(imagePath);
        return result.Text;
    }

    public async Task<string> ExtractFromStreamAsync(Stream stream)
    {
        using var input = new OcrInput();
        input.LoadImage(stream);

        var result = await _ocr.ReadAsync(input);
        return result.Text;
    }
}
using IronOcr;

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

    public async Task<string> ExtractTextAsync(string imagePath)
    {
        // ReadAsync is natively async — no Task.Run wrapper, no lock required
        var result = await _ocr.ReadAsync(imagePath);
        return result.Text;
    }

    public async Task<string> ExtractFromStreamAsync(Stream stream)
    {
        using var input = new OcrInput();
        input.LoadImage(stream);

        var result = await _ocr.ReadAsync(input);
        return result.Text;
    }
}
Imports IronOcr
Imports System.IO
Imports System.Threading.Tasks

Public Class IronOcrAsyncService
    Private ReadOnly _ocr As New IronTesseract()

    Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
        ' ReadAsync is natively async — no Task.Run wrapper, no lock required
        Dim result = Await _ocr.ReadAsync(imagePath)
        Return result.Text
    End Function

    Public Async Function ExtractFromStreamAsync(stream As Stream) As Task(Of String)
        Using input As New OcrInput()
            input.LoadImage(stream)

            Dim result = Await _ocr.ReadAsync(input)
            Return result.Text
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

A abordagem do GdPicture requer um SemaphoreSlim para serializar o acesso à instância compartilhada GdPictureOCR, além de um Task.Run para mover o trabalho de bloqueio síncrono do thread de chamada, além do ciclo de vida completo do ID da imagem dentro desse lambda. O ReadAsync do IronOCR é genuinamente não-bloqueante e seguro para threads. O guia de OCR assíncrono aborda a integração com middleware do ASP.NET Core e serviços hospedados em segundo plano.

Processamento paralelo em lotes com segurança de rosca

Processar uma pasta de documentos digitalizados o mais rápido possível requer execução em paralelo. O GdPicture requer uma instância GdPictureOCR por thread — compartilhar uma única instância causa falhas não determinísticas. Cada instância por thread também requer seu próprio componente GdPictureImaging e configuração da pasta de recursos, tornando as abordagens de pool de threads impraticáveis sem um padrão de fábrica.

Abordagem GdPicture .NET :

using GdPicture14;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class GdPictureParallelBatch
{
    private readonly string _resourceFolder = @"C:\GdPicture\Resources\OCR";

    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // Each thread must have its own component instances
        Parallel.ForEach(imagePaths, imagePath =>
        {
            // Create per-thread instances — shared instances cause failures
            using var threadImaging = new GdPictureImaging();
            using var threadOcr = new GdPictureOCR();
            threadOcr.ResourceFolder = _resourceFolder;

            // Re-register license per thread (may be required depending on SDK version)
            var lm = new LicenseManager();
            lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

            int imageId = threadImaging.CreateGdPictureImageFromFile(imagePath);

            if (imageId == 0)
            {
                results[imagePath] = $"ERROR: {threadImaging.GetStat()}";
                return;
            }

            try
            {
                threadOcr.SetImage(imageId);
                threadOcr.Language = "eng";

                string resultId = threadOcr.RunOCR();
                results[imagePath] = string.IsNullOrEmpty(resultId)
                    ? $"ERROR: {threadOcr.GetStat()}"
                    : threadOcr.GetOCRResultText(resultId);
            }
            finally
            {
                threadImaging.ReleaseGdPictureImage(imageId);
            }
        });

        return results;
    }
}
using GdPicture14;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class GdPictureParallelBatch
{
    private readonly string _resourceFolder = @"C:\GdPicture\Resources\OCR";

    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // Each thread must have its own component instances
        Parallel.ForEach(imagePaths, imagePath =>
        {
            // Create per-thread instances — shared instances cause failures
            using var threadImaging = new GdPictureImaging();
            using var threadOcr = new GdPictureOCR();
            threadOcr.ResourceFolder = _resourceFolder;

            // Re-register license per thread (may be required depending on SDK version)
            var lm = new LicenseManager();
            lm.RegisterKEY("GDPICTURE-LICENSE-KEY");

            int imageId = threadImaging.CreateGdPictureImageFromFile(imagePath);

            if (imageId == 0)
            {
                results[imagePath] = $"ERROR: {threadImaging.GetStat()}";
                return;
            }

            try
            {
                threadOcr.SetImage(imageId);
                threadOcr.Language = "eng";

                string resultId = threadOcr.RunOCR();
                results[imagePath] = string.IsNullOrEmpty(resultId)
                    ? $"ERROR: {threadOcr.GetStat()}"
                    : threadOcr.GetOCRResultText(resultId);
            }
            finally
            {
                threadImaging.ReleaseGdPictureImage(imageId);
            }
        });

        return results;
    }
}
Imports GdPicture14
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Public Class GdPictureParallelBatch
    Private ReadOnly _resourceFolder As String = "C:\GdPicture\Resources\OCR"

    Public Function ProcessBatch(imagePaths As String()) As ConcurrentDictionary(Of String, String)
        Dim results As New ConcurrentDictionary(Of String, String)()

        ' Each thread must have its own component instances
        Parallel.ForEach(imagePaths, Sub(imagePath)
            ' Create per-thread instances — shared instances cause failures
            Using threadImaging As New GdPictureImaging()
                Using threadOcr As New GdPictureOCR()
                    threadOcr.ResourceFolder = _resourceFolder

                    ' Re-register license per thread (may be required depending on SDK version)
                    Dim lm As New LicenseManager()
                    lm.RegisterKEY("GDPICTURE-LICENSE-KEY")

                    Dim imageId As Integer = threadImaging.CreateGdPictureImageFromFile(imagePath)

                    If imageId = 0 Then
                        results(imagePath) = $"ERROR: {threadImaging.GetStat()}"
                        Return
                    End If

                    Try
                        threadOcr.SetImage(imageId)
                        threadOcr.Language = "eng"

                        Dim resultId As String = threadOcr.RunOCR()
                        results(imagePath) = If(String.IsNullOrEmpty(resultId), $"ERROR: {threadOcr.GetStat()}", threadOcr.GetOCRResultText(resultId))
                    Finally
                        threadImaging.ReleaseGdPictureImage(imageId)
                    End Try
                End Using
            End Using
        End Sub)

        Return results
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class IronOcrParallelBatch
{
    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // IronTesseract is thread-safe — one instance handles all threads
        var ocr = new IronTesseract();

        Parallel.ForEach(imagePaths, imagePath =>
        {
            try
            {
                results[imagePath] = ocr.Read(imagePath).Text;
            }
            catch (Exception ex)
            {
                results[imagePath] = $"ERROR: {ex.Message}";
            }
        });

        return results;
    }
}
using IronOcr;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public class IronOcrParallelBatch
{
    public ConcurrentDictionary<string, string> ProcessBatch(string[] imagePaths)
    {
        var results = new ConcurrentDictionary<string, string>();

        // IronTesseract is thread-safe — one instance handles all threads
        var ocr = new IronTesseract();

        Parallel.ForEach(imagePaths, imagePath =>
        {
            try
            {
                results[imagePath] = ocr.Read(imagePath).Text;
            }
            catch (Exception ex)
            {
                results[imagePath] = $"ERROR: {ex.Message}";
            }
        });

        return results;
    }
}
Imports IronOcr
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Public Class IronOcrParallelBatch
    Public Function ProcessBatch(imagePaths As String()) As ConcurrentDictionary(Of String, String)
        Dim results As New ConcurrentDictionary(Of String, String)()

        ' IronTesseract is thread-safe — one instance handles all threads
        Dim ocr As New IronTesseract()

        Parallel.ForEach(imagePaths, Sub(imagePath)
            Try
                results(imagePath) = ocr.Read(imagePath).Text
            Catch ex As Exception
                results(imagePath) = $"ERROR: {ex.Message}"
            End Try
        End Sub)

        Return results
    End Function
End Class
$vbLabelText   $csharpLabel

A implementação paralela do GdPicture cria três objetos por thread e requer o registro de uma licença por thread. O IronOCR lida com leituras simultâneas de uma única instância IronTesseract sem sobrecarga de sincronização. O exemplo de multithreading demonstra benchmarks de rendimento e padrões Parallel.ForEach para cargas de trabalho de processamento de documentos de alto volume.

Entrada de matriz de bytes e extração de parágrafos estruturados

Aplicações que recuperam documentos de bancos de dados ou armazenamento de objetos geralmente trabalham com matrizes de bytes em vez de caminhos de arquivo. O GdPicture requer a conversão do array de bytes para um fluxo e o carregamento através de GdPictureImaging. Extrair dados estruturados em nível de parágrafo do resultado requer navegar pela hierarquia do índice de bloco/linha.

Abordagem GdPicture .NET :

using GdPicture14;

public class GdPictureByteArrayOcr
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        var paragraphs = new List<string>();

        // Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        using var ms = new MemoryStream(imageBytes);
        int imageId = _imaging.CreateGdPictureImageFromStream(ms);

        if (imageId == 0)
            throw new Exception($"Byte array load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            // Paragraph-level data requires iterating block structure
            int blockCount = _ocr.GetOCRResultBlockCount(resultId);

            for (int b = 0; b < blockCount; b++)
            {
                var blockText = new StringBuilder();
                int lineCount = _ocr.GetOCRResultBlockLineCount(resultId, b);

                for (int l = 0; l < lineCount; l++)
                {
                    int wordCount = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l);

                    for (int w = 0; w < wordCount; w++)
                    {
                        blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w));
                        blockText.Append(" ");
                    }
                }

                string text = blockText.ToString().Trim();
                if (!string.IsNullOrEmpty(text))
                    paragraphs.Add(text);
            }
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }

        return paragraphs;
    }
}
using GdPicture14;

public class GdPictureByteArrayOcr
{
    private readonly GdPictureImaging _imaging;
    private readonly GdPictureOCR _ocr;

    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        var paragraphs = new List<string>();

        // Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        using var ms = new MemoryStream(imageBytes);
        int imageId = _imaging.CreateGdPictureImageFromStream(ms);

        if (imageId == 0)
            throw new Exception($"Byte array load failed: {_imaging.GetStat()}");

        try
        {
            _ocr.SetImage(imageId);
            _ocr.Language = "eng";

            string resultId = _ocr.RunOCR();

            if (string.IsNullOrEmpty(resultId))
                throw new Exception($"OCR failed: {_ocr.GetStat()}");

            // Paragraph-level data requires iterating block structure
            int blockCount = _ocr.GetOCRResultBlockCount(resultId);

            for (int b = 0; b < blockCount; b++)
            {
                var blockText = new StringBuilder();
                int lineCount = _ocr.GetOCRResultBlockLineCount(resultId, b);

                for (int l = 0; l < lineCount; l++)
                {
                    int wordCount = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l);

                    for (int w = 0; w < wordCount; w++)
                    {
                        blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w));
                        blockText.Append(" ");
                    }
                }

                string text = blockText.ToString().Trim();
                if (!string.IsNullOrEmpty(text))
                    paragraphs.Add(text);
            }
        }
        finally
        {
            _imaging.ReleaseGdPictureImage(imageId);
        }

        return paragraphs;
    }
}
Imports GdPicture14
Imports System.IO
Imports System.Text

Public Class GdPictureByteArrayOcr
    Private ReadOnly _imaging As GdPictureImaging
    Private ReadOnly _ocr As GdPictureOCR

    Public Function ExtractParagraphsFromBytes(imageBytes As Byte()) As List(Of String)
        Dim paragraphs As New List(Of String)()

        ' Byte array must go through MemoryStream to reach CreateGdPictureImageFromStream
        Using ms As New MemoryStream(imageBytes)
            Dim imageId As Integer = _imaging.CreateGdPictureImageFromStream(ms)

            If imageId = 0 Then
                Throw New Exception($"Byte array load failed: {_imaging.GetStat()}")
            End If

            Try
                _ocr.SetImage(imageId)
                _ocr.Language = "eng"

                Dim resultId As String = _ocr.RunOCR()

                If String.IsNullOrEmpty(resultId) Then
                    Throw New Exception($"OCR failed: {_ocr.GetStat()}")
                End If

                ' Paragraph-level data requires iterating block structure
                Dim blockCount As Integer = _ocr.GetOCRResultBlockCount(resultId)

                For b As Integer = 0 To blockCount - 1
                    Dim blockText As New StringBuilder()
                    Dim lineCount As Integer = _ocr.GetOCRResultBlockLineCount(resultId, b)

                    For l As Integer = 0 To lineCount - 1
                        Dim wordCount As Integer = _ocr.GetOCRResultBlockLineWordCount(resultId, b, l)

                        For w As Integer = 0 To wordCount - 1
                            blockText.Append(_ocr.GetOCRResultBlockLineWordText(resultId, b, l, w))
                            blockText.Append(" "c)
                        Next
                    Next

                    Dim text As String = blockText.ToString().Trim()
                    If Not String.IsNullOrEmpty(text) Then
                        paragraphs.Add(text)
                    End If
                Next
            Finally
                _imaging.ReleaseGdPictureImage(imageId)
            End Try
        End Using

        Return paragraphs
    End Function
End Class
$vbLabelText   $csharpLabel

Abordagem IronOCR:

using IronOcr;

public class IronOcrByteArrayOcr
{
    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        using var input = new OcrInput();
        input.LoadImage(imageBytes);  // byte array accepted directly

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

        // Paragraphs are a first-class typed collection
        return result.Paragraphs
            .Select(p => p.Text)
            .Where(t => !string.IsNullOrWhiteSpace(t))
            .ToList();
    }
}
using IronOcr;

public class IronOcrByteArrayOcr
{
    public List<string> ExtractParagraphsFromBytes(byte[] imageBytes)
    {
        using var input = new OcrInput();
        input.LoadImage(imageBytes);  // byte array accepted directly

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

        // Paragraphs are a first-class typed collection
        return result.Paragraphs
            .Select(p => p.Text)
            .Where(t => !string.IsNullOrWhiteSpace(t))
            .ToList();
    }
}
Imports IronOcr

Public Class IronOcrByteArrayOcr
    Public Function ExtractParagraphsFromBytes(imageBytes As Byte()) As List(Of String)
        Using input As New OcrInput()
            input.LoadImage(imageBytes) ' byte array accepted directly

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

            ' Paragraphs are a first-class typed collection
            Return result.Paragraphs _
                .Select(Function(p) p.Text) _
                .Where(Function(t) Not String.IsNullOrWhiteSpace(t)) _
                .ToList()
        End Using
    End Function
End Class
$vbLabelText   $csharpLabel

O IronOCR aceita byte[] diretamente em LoadImage sem o intermediário MemoryStream. O resultado expõe .Paragraphs como uma coleção LINQ-consultável digitada — não é necessário loop triplo de bloco/linha/palavra. O guia de resultados de leitura aborda o acesso a coordenadas, a filtragem de confiança e os padrões de saída estruturados para fluxos de trabalho de processamento de faturas e formulários. Para digitalizar áreas específicas de documentos, consulte OCR baseado em região .

Referência de mapeamento da API .NET do GdPicture para o IronOCR

GdPicture.NET Equivalente de IronOCR
using GdPicture14; using IronOcr;
LicenseManager.RegisterKEY("key") IronOcr.License.LicenseKey = "key"
new GdPictureImaging() Não requerido — interno ao OcrInput
new GdPictureOCR() new IronTesseract()
new GdPicturePDF() Não requerido — o OcrInput.LoadPdf() lida com isso
_ocr.ResourceFolder = path Não é necessário — recursos incluídos no NuGet.
imaging.CreateGdPictureImageFromFile(path) input.LoadImage(path)
imaging.CreateGdPictureImageFromStream(stream) input.LoadImage(stream)
imaging.CreateGdPictureImageFromBytes(bytes) input.LoadImage(bytes)
imaging.CloneImage(tiffId) por quadro input.LoadImageFrames(tiffPath)
imaging.ReleaseGdPictureImage(imageId) using var input = new OcrInput() — automático
ocr.SetImage(imageId) Não requerido — o OcrInput mantém a imagem
ocr.Language = "eng" ocr.Language = OcrLanguage.English
ocr.RunOCR() → string resultId ocr.Read(input) → digitado OcrResult
ocr.GetOCRResultText(resultId) result.Text
ocr.GetOCRResultConfidence(resultId) result.Confidence
ocr.GetOCRResultBlockCount(resultId) result.Pages[i].Paragraphs.Count
ocr.GetOCRResultBlockLineWordText(resultId, b, l, w) result.Words[i].Text
imaging.GetStat() / ocr.GetStat() Exceções padrão do .NET
Verificação GdPictureStatus.OK após cada chamada Não é necessário — as exceções se propagam.
pdf.OcrPage("eng", resourcePath, "", 200) result.SaveAsSearchablePdf(outputPath)
pdf.RenderPageToGdPictureImage(200, false) Não é necessário — o IronOCR renderiza internamente.
pdf.SelectPage(i) Não é necessário — todas as páginas são processadas por padrão.
pdf.GetPageCount() result.Pages.Count
Task.Run(() => ocr.RunOCR()) + SemaphoreSlim await ocr.ReadAsync(input)

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

Problema 1: Variáveis ​​de ID de imagem permanecem no código após a refatoração.

GdPicture.NET: O código existente declara int imageId no topo dos métodos, rastreia-o através de try/finally, e o passa para várias chamadas GdPicture. Após substituir as chamadas GdPicture, essas variáveis e suas chamadas ReleaseGdPictureImage tornam-se código morto órfão.

Solução: Exclua todo o padrão de identificação da imagem. Substitua a declaração, o try, o finally, e a chamada de liberação por um bloco using var input = new OcrInput(). Procure por ReleaseGdPictureImage para encontrar cada chamada de limpeza que deve ser removida:

grep -rn "ReleaseGdPictureImage\|imageId\|resultId" --include="*.cs" .
grep -rn "ReleaseGdPictureImage\|imageId\|resultId" --include="*.cs" .
SHELL
// Remove all of this
int imageId = _imaging.CreateGdPictureImageFromFile(path);
try
{
    _ocr.SetImage(imageId);
    string resultId = _ocr.RunOCR();
    return _ocr.GetOCRResultText(resultId);
}
finally
{
    _imaging.ReleaseGdPictureImage(imageId);
}

// Replace with
using var input = new OcrInput();
input.LoadImage(path);
return new IronTesseract().Read(input).Text;
// Remove all of this
int imageId = _imaging.CreateGdPictureImageFromFile(path);
try
{
    _ocr.SetImage(imageId);
    string resultId = _ocr.RunOCR();
    return _ocr.GetOCRResultText(resultId);
}
finally
{
    _imaging.ReleaseGdPictureImage(imageId);
}

// Replace with
using var input = new OcrInput();
input.LoadImage(path);
return new IronTesseract().Read(input).Text;
' Remove all of this
Dim imageId As Integer = _imaging.CreateGdPictureImageFromFile(path)
Try
    _ocr.SetImage(imageId)
    Dim resultId As String = _ocr.RunOCR()
    Return _ocr.GetOCRResultText(resultId)
Finally
    _imaging.ReleaseGdPictureImage(imageId)
End Try

' Replace with
Using input As New OcrInput()
    input.LoadImage(path)
    Return New IronTesseract().Read(input).Text
End Using
$vbLabelText   $csharpLabel

Problema 2: Caminho da pasta de recursos não encontrado no ambiente de implantação

GdPicture.NET: O caminho configurado em _ocr.ResourceFolder resolve-se na máquina de desenvolvimento, mas falha em produção. Sintomas comuns são falhas silenciosas de OCR retornando resultados vazios, ou erros genéricos GdPictureStatus que não nomeiam o arquivo ausente.

Solução: Remova totalmente a atribuição do ResourceFolder. O suporte para inglês está integrado no pacote NuGet do IronOCR. Idiomas adicionais são instalados como pacotes NuGet . Não existe nenhum caminho de sistema de arquivos para configurar ou implantar:

# Remove the filesystem folder from deployment artifacts
# Add language NuGet packages to the project instead
:InstallCmd dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
# Remove the filesystem folder from deployment artifacts
# Add language NuGet packages to the project instead
:InstallCmd dotnet add package IronOcr.Languages.French, IronOcr.Languages.German
SHELL

Problema 3: O tratamento de erros do GdPictureStatus foi substituído por exceções.

GdPicture.NET: Toda operação retorna ou define um valor enum GdPictureStatus que deve ser verificado imediatamente. O código está denso com proteções if (status != GdPictureStatus.OK). Alguns códigos de status são genéricos (e.g., Error, InvalidParameter) e requerem consultar a documentação para determinar a causa raiz.

Solução: O IronOCR gera exceções tipadas do .NET . Substitua as verificações de status por blocos try/catch. Erros de entrada são cobertos pelos padrões IOException e FileNotFoundException; IronOcr.Exceptions.OcrException cobre erros específicos de OCR. Consulte o guia de configuração do IronTesseract para obter padrões recomendados de tratamento de erros:

try
{
    var result = new IronTesseract().Read(imagePath);
    return result.Text;
}
catch (FileNotFoundException ex)
{
    _logger.LogError("Input file missing: {Path}", ex.FileName);
    throw;
}
catch (IronOcr.Exceptions.OcrException ex)
{
    _logger.LogError("OCR processing failed: {Message}", ex.Message);
    throw;
}
try
{
    var result = new IronTesseract().Read(imagePath);
    return result.Text;
}
catch (FileNotFoundException ex)
{
    _logger.LogError("Input file missing: {Path}", ex.FileName);
    throw;
}
catch (IronOcr.Exceptions.OcrException ex)
{
    _logger.LogError("OCR processing failed: {Message}", ex.Message);
    throw;
}
Imports IronOcr
Imports System.IO

Try
    Dim result = New IronTesseract().Read(imagePath)
    Return result.Text
Catch ex As FileNotFoundException
    _logger.LogError("Input file missing: {Path}", ex.FileName)
    Throw
Catch ex As IronOcr.Exceptions.OcrException
    _logger.LogError("OCR processing failed: {Message}", ex.Message)
    Throw
End Try
$vbLabelText   $csharpLabel

Problema 4: Namespace GdPicture14 em Múltiplos Arquivos

GdPicture.NET: O número da versão no namespace significa que existe uma diretiva using GdPicture14; em toda a extensão do projeto em dezenas de arquivos. Após a migração, todos estes devem ser substituídos por using IronOcr;.

Solução: Utilize uma busca e substituição global em todos os arquivos .cs, então verifique se não restam referências ao GdPicture:

# Find all files with GdPicture namespace
grep -rln "using GdPicture" --include="*.cs" .

# After replacing, verify nothing remains
grep -rn "GdPicture14\|GdPictureOCR\|GdPictureImaging\|GdPicturePDF" --include="*.cs" .
# Find all files with GdPicture namespace
grep -rln "using GdPicture" --include="*.cs" .

# After replacing, verify nothing remains
grep -rn "GdPicture14\|GdPictureOCR\|GdPictureImaging\|GdPicturePDF" --include="*.cs" .
SHELL

Edição 5: Lógica de Contagem de Quadros TIFF

GdPicture.NET: O código que itera quadros TIFF muitas vezes mistura chamadas entre GdPictureImaging.GetPageCount(imageId) e GdPicturePDF.GetPageCount() dependendo de como o arquivo foi carregado. O índice do quadro é baseado em 1.

Solução: input.LoadImageFrames(path) lida com todos os quadros automaticamente. Se o seu código atual apenas processa quadros específicos, use input.LoadImageFrames(path, frameNumbers) com um array de índice baseado em zero. Acesse os resultados por quadro através de result.Pages, que também é indexado por zero. O guia de entrada TIFF documenta explicitamente o comportamento do índice.

Problema 6: O pré-processamento requer o plugin de digitalização de documentos.

GdPicture.NET: Operações de desalinhamento e remoção de manchas pertencem ao plugin GdPictureDocumentImaging, que requer compra de licença separada. Equipes que optaram por não usar o plugin frequentemente enfrentam problemas de precisão de OCR em documentos digitalizados com páginas distorcidas ou com ruído.

Solução: Os métodos de pré-processamento do IronOCR fazem parte do pacote básico. Adicione Deskew() e DeNoise() diretamente em OcrInput. O guia de correção de qualidade de imagem cobre todos os filtros disponíveis, incluindo Contrast(), Sharpen(), Binarize(), e DeepCleanBackgroundNoise() para digitalizações severamente degradadas:

using var input = new OcrInput();
input.LoadImage("scanned-document.tiff");
input.Deskew();        // no separate plugin license
input.DeNoise();
input.Contrast();

var result = new IronTesseract().Read(input);
using var input = new OcrInput();
input.LoadImage("scanned-document.tiff");
input.Deskew();        // no separate plugin license
input.DeNoise();
input.Contrast();

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

Using input As New OcrInput()
    input.LoadImage("scanned-document.tiff")
    input.Deskew() ' no separate plugin license
    input.DeNoise()
    input.Contrast()

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

Lista de verificação para migração do GdPicture for .NET

Pré-migração

Antes de fazer alterações, audite o código-fonte para localizar todas as dependências do GdPicture:

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

# Find all image ID creation points
grep -rn "CreateGdPictureImageFromFile\|CreateGdPictureImageFromStream\|RenderPageToGdPictureImage\|CloneImage" --include="*.cs" .

# Find all release calls — these map to using block boundaries
grep -rn "ReleaseGdPictureImage" --include="*.cs" .

# Find all resource folder assignments
grep -rn "ResourceFolder" --include="*.cs" .

# Find all OCR result ID accesses
grep -rn "RunOCR\|GetOCRResult\|resultId" --include="*.cs" .

# Find all GdPictureStatus checks
grep -rn "GdPictureStatus\|GetStat()" --include="*.cs" .

# Count GdPicture-dependent files
grep -rln "GdPicture14" --include="*.cs" . | wc -l
# Find all GdPicture namespace imports
grep -rn "using GdPicture" --include="*.cs" .

# Find all image ID creation points
grep -rn "CreateGdPictureImageFromFile\|CreateGdPictureImageFromStream\|RenderPageToGdPictureImage\|CloneImage" --include="*.cs" .

# Find all release calls — these map to using block boundaries
grep -rn "ReleaseGdPictureImage" --include="*.cs" .

# Find all resource folder assignments
grep -rn "ResourceFolder" --include="*.cs" .

# Find all OCR result ID accesses
grep -rn "RunOCR\|GetOCRResult\|resultId" --include="*.cs" .

# Find all GdPictureStatus checks
grep -rn "GdPictureStatus\|GetStat()" --include="*.cs" .

# Count GdPicture-dependent files
grep -rln "GdPicture14" --include="*.cs" . | wc -l
SHELL

Documente o seguinte antes de modificar o código:

  • Quais arquivos contêm referências GdPictureImaging, GdPictureOCR, e GdPicturePDF
  • Quantos pares distintos de criação/liberação de IDs de imagem existem?
  • Se o plugin de processamento de imagens de documentos (desvio de distorção, remoção de ruído) está em uso.
  • Quais arquivos de linguagem traineddata estão na pasta de recursos
  • Quais scripts de implantação ou arquivos Docker fazem referência ao caminho da pasta de recursos?

Migração de código

  1. Remova todos os pacotes NuGet do GdPicture do arquivo de projeto.
  2. Instale IronOcr via NuGet
  3. Instale pacotes IronOcr.Languages.* para cada idioma previamente na pasta de recursos
  4. Adicione IronOcr.License.LicenseKey = "..." a Program.cs ou Startup.cs
  5. Remova a chamada LicenseManager.RegisterKEY() e o objeto do gerenciador de licenças
  6. Remova todas as declarações de campo GdPictureImaging e a inicialização do construtor
  7. Remova todas as declarações de campo GdPictureOCR e a atribuição ResourceFolder
  8. Remova todas as declarações de campo GdPicturePDF usadas para fluxos de trabalho de OCR
  9. Substitua cada bloco int imageId = _imaging.CreateGdPictureImage*(...) por using var input = new OcrInput(); input.Load*(...)
  10. Substitua cada _ocr.SetImage(imageId); _ocr.Language = &quot;...&quot;; string resultId = _ocr.RunOCR(); with var result = new IronTesseract().Read(input);
  11. Substitua _ocr.GetOCRResultText(resultId) por result.Text
  12. Remova todas as chamadas _imaging.ReleaseGdPictureImage(imageId)
  13. Substitua verificações GdPictureStatus por blocos try/catch
  14. Substitua loops de quadros TIFF por input.LoadImageFrames(path)
  15. Substitua pdf.OcrPage(...) + pdf.SaveToFile(...) por result.SaveAsSearchablePdf(outputPath)
  16. Remova o caminho da pasta de recursos dos scripts de implantação e das imagens do Docker.
  17. Atualize using GdPicture14; para using IronOcr; em todos os arquivos afetados

Pós-migração

Após concluir todas as alterações de código, verifique o seguinte antes de implantar em produção:

  • OCR de imagem única retorna o texto esperado sem NullReferenceException de componentes removidos
  • O processamento de TIFF de várias páginas cobre todos os quadros e produz texto por página através de result.Pages
  • O OCR de PDF processa todas as páginas sem aumentar o consumo de memória em lotes de mais de 50 documentos.
  • A entrada de fluxo aceita MemoryStream e FileStream sem gravações de arquivos intermediários
  • O OCR assíncrono integra-se com os manipuladores de requisição do ASP.NET Core sem bloquear o pool de threads.
  • O processamento em lote paralelo com Parallel.ForEach produz resultados precisos em todos os threads
  • Todos os pacotes de idiomas (francês, alemão, etc.) são ativados corretamente por meio de pacotes NuGet.
  • Os filtros de pré-processamento (correção de distorção, redução de ruído) melhoram a precisão em documentos digitalizados.
  • O PDF pesquisável pode ser lido por visualizadores de PDF e aplicativos de busca de texto.
  • Nenhuma referência ao namespace GdPicture resta em qualquer arquivo .cs após a migração
  • O perfil de memória mostra uso estável sob carga sustentada (sem vazamento de alocações de imagem).
  • A implantação é bem-sucedida em destinos Linux e Docker sem erros de caminho do sistema de arquivos.

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

Segurança de memória imposta pelo compilador. O ciclo de vida do ID da imagem que o GdPicture exige que os desenvolvedores mantenham manualmente desaparece completamente. OcrInput implementa IDisposable, e blocos using reforçam a limpeza no final de cada escopo — incluindo caminhos de exceção. Nenhum List<int> para manter, nenhum bloco finally para lembrar, nenhum incidente de memória de produção por chamadas de liberação perdidas.

Pacote Único para Cada Cenário de OCR. OCR de imagem, OCR de PDF, processamento de TIFF de várias páginas, geração de PDF pesquisável, filtros de pré-processamento, leitura de códigos de barras e mais de 125 pacotes de idiomas estão todos disponíveis no pacote NuGet IronOcr e seus complementos de idioma. Não existe nenhuma funcionalidade que exija a compra de uma segunda ou terceira licença antes que um fluxo de trabalho comum se torne possível. Consulte a visão geral dos recursos do IronOCR para obter a lista completa de funcionalidades.

Async Nativo e Segurança de Thread. ReadAsync é um verdadeiro método async, não um invólucro Task.Run. IronTesseract é seguro para usar em threads sem sincronização. Serviços de processamento de documentos que anteriormente requeriam inicialização de componentes por thread e serialização de semáforo reduzem para uma única instância compartilhada com Parallel.ForEach. O guia de OCR assíncrono abrange padrões tanto do ASP.NET Core quanto de serviços hospedados.

Configuração de implantação zero. O IronOCR não requer caminhos de sistema de arquivos, arquivos de idioma externos, instalação de binários nativos nem scripts de implantação. A etapa de restauração do NuGet fornece tudo o que o aplicativo precisa. As imagens Docker, as implantações do Azure App Service e os servidores Linux funcionam de forma idêntica à máquina de desenvolvimento. O guia de implantação do Docker e o guia de implantação do Azure demonstram configurações prontas para produção.

Namespace Estável de Versão. using IronOcr não mudou através de lançamentos principais de versão. Os números de versão do NuGet gerenciam o versionamento por meio do modelo padrão de gerenciamento de pacotes. As futuras atualizações importantes não exigirão uma busca e substituição em todo o código-fonte da importação do namespace.

Licenciamento Perpétuo Previsível.IronOCR é vendido por $999 (Lite), $1,499 (Plus), $2,999 (Professional) e $5,999 (Unlimited) — compras perpétuas únicas que incluem um ano de atualizações, com renovação opcional anualmente. Todas as funcionalidades estão disponíveis em todos os planos. Não há plugins por funcionalidade, custos por página ou obrigação de manutenção após o primeiro ano. As equipes que anteriormente absorviam mais de US$ 8.000 em licenças do plugin GdPicture para um fluxo de trabalho exclusivamente de OCR recuperam essa diferença já no primeiro ciclo de licenciamento. Informações completas sobre preços estão disponíveis na página de licenciamento do IronOCR .

ObserveGdPicture.NET e Tesseract são marcas registradas de seus respectivos proprietários. Este site não está afiliado, endossado ou patrocinado pelo Google, Nutrient, ou ORPALIS. 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 do OCR GdPicture.NET para o IronOCR?

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

Quais são as principais alterações de código ao migrar do OCR GdPicture.NET para o IronOCR?

Substitua as sequências de inicialização do GdPicture.NET 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 que o GdPicture.NET para documentos comerciais padrão?

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

Como o IronOCR lida com os dados de idioma que o GdPicture.NET OCR instala separadamente?

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

A migração do OCR GdPicture.NET para o IronOCR requer alterações na infraestrutura de implantação?

O IronOCR requer menos alterações de infraestrutura do que o GdPicture.NET OCR. 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 GdPicture.NET?

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

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

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

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

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

O preço do IronOCR é mais previsível do que o do GdPicture.NET OCR para cargas de trabalho escaláveis?

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

O que acontece com meus testes existentes após a migração do OCR GdPicture.NET 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