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

Como escrever códigos de barras Unicode e em idiomas internacionais em C# | IronPDF

Migrando de ZXing.Net para IronBarcode

Este guia abrange uma migração completa do ZXing .NET para o IronBarcode para aplicações .NET que leem e geram códigos de barras. Ele aborda a remoção do pacote principal e pacotes de vinculação do ZXing.Net, a eliminação de soluções alternativas do PdfiumViewer, onde presente, e a substituição de cada instanciação de BarcodeReader com a API estática do IronBarcode. Cada seção inclui exemplos de código antes e depois, extraídos dos padrões mais comuns encontrados em integrações ZXing .NET .

Por que migrar do ZXing .NET?

O ZXing .NET tem servido bem à comunidade .NET por mais de uma década como uma biblioteca de código de barras gratuita e licenciada sob a licença Apache 2.0. Não entanto, diversas restrições arquitetônicas se transformam em custos operacionais à medida que as aplicações crescem em escala ou complexidade.

Propriedade de Segurança de Thread: O BarcodeReader do ZXing.Net é um objeto com estado. A própria documentação da biblioteca afirma que as instâncias não devem ser compartilhadas entre threads. Na prática, isso significa que cada caminho de processamento concorrente — cada ação do controlador que lida com solicitações simultâneas, cada tarefa em um lote paralelo — deve alocar, configurar e descartar seu próprio leitor. À medida que o volume de solicitações aumenta, esse padrão de alocação produz uma pressão mensurável na memória. A alternativa ThreadLocal<BarcodeReader> reduz a frequência de alocação, mas introduz sua própria complexidade de descarte. Em ambos os casos, a correção sob concorrência é um problema de quem chama a função, e não uma garantia fornecida pela biblioteca.

Risco de Especificação de Formato: O ZXing.Net requer que reader.Options.PossibleFormats seja populado antes de cada operação de decodificação. Um código de barras em um formato não presente nessa lista retorna nulo — sem exceção, sem aviso, sem indicação de que um código de barras estava presente, mas não foi reconhecido. Para aplicações que recebem documentos de parceiros externos, esse comportamento de falha silenciosa é um risco de confiabilidade: um pedido enviado erroneamente, um registro de check-in de paciente não registrado ou uma entrada de auditoria que nunca é escrita podem se originar de uma lista de formatos configurada para um requisito anterior e nunca atualizada.

Lacuna no processamento de PDF: o ZXing .NET lê apenas bitmaps. Quando os documentos de origem são PDFs — faturas, manifestos de remessa, certificados de conformidade — os usuários devem integrar uma biblioteca de renderização de PDF separada (PdfiumViewer sendo a mais comum), implementar um loop de enumeração de páginas, configurar DPI, gerenciar arquivos temporários e lidar com a limpeza tanto em casos de sucesso quanto de falha. Trata-se de 30 a 50 linhas de código de infraestrutura por integração, cuja função é exclusivamente converter o que o ZXing .NET não consegue ler (PDFs) no que ele consegue (bitmaps). Essa infraestrutura possui suas próprias dependências, seus próprios requisitos de implantação e seus próprios modos de falha.

Fragmentação da vinculação de plataforma: a capacidade de carregamento de imagens do ZXing.Net está dividida entre pacotes de vinculação específicos da plataforma. A vinculação do Windows usa System.Drawing.Bitmap; a vinculação multiplataforma usa SixLabors.ImageSharp com um parâmetro de tipo genérico diferente e uma diretiva using diferente. Um projeto que comece no Windows e mais tarde seja contêinerizado no Linux deve mudar tanto suas referências NuGet quanto seu código de carregamento de imagens. Dois caminhos de código para a mesma operação aumentam a superfície de ataque e dificultam futuras alterações na camada de varredura.

O problema fundamental

A ilustração mais clara da arquitetura ZXing .NET é a diferença entre uma chamada de thread única e uma chamada concorrente. Em ZXing .NET, o processamento concorrente exige a criação de um objeto leitor completo para cada operação paralela:

// ZXing.Net: full reader instantiation and configuration on every parallel task
Parallel.ForEach(files, file =>
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    };

    using var bitmap = new Bitmap(file);
    var result = reader.Decode(bitmap);
    if (result != null)
        processed[file] = result.Text;
});
// ZXing.Net: full reader instantiation and configuration on every parallel task
Parallel.ForEach(files, file =>
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    };

    using var bitmap = new Bitmap(file);
    var result = reader.Decode(bitmap);
    if (result != null)
        processed[file] = result.Text;
});
Imports ZXing
Imports System.Drawing
Imports System.Threading.Tasks

Parallel.ForEach(files, Sub(file)
    Dim reader As New BarcodeReader()
    reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    }

    Using bitmap As New Bitmap(file)
        Dim result = reader.Decode(bitmap)
        If result IsNot Nothing Then
            processed(file) = result.Text
        End If
    End Using
End Sub)
$vbLabelText   $csharpLabel

IronBarcode remove o objeto por completo. A chamada estática é a mesma, independentemente de ser executada em uma ou cem threads:

// IronBarcode: static call, same code for single-threaded and concurrent use
Parallel.ForEach(files, file =>
{
    var result = BarcodeReader.Read(file).FirstOrDefault();
    if (result != null)
        processed[file] = result.Value;
});
// IronBarcode: static call, same code for single-threaded and concurrent use
Parallel.ForEach(files, file =>
{
    var result = BarcodeReader.Read(file).FirstOrDefault();
    if (result != null)
        processed[file] = result.Value;
});
Imports IronBarCode
Imports System.Threading.Tasks

Parallel.ForEach(files, Sub(file)
    Dim result = BarcodeReader.Read(file).FirstOrDefault()
    If result IsNot Nothing Then
        processed(file) = result.Value
    End If
End Sub)
$vbLabelText   $csharpLabel

IronBarcode vs ZXing .NET: Comparação de Recursos

Recurso ZXing.Net IronBarcode
Licença Apache 2.0 (gratuito) Comercial
Segurança da rosca Não é thread-safe — requer uma nova instância por thread. API estática thread-safe
Detecção de formato Manual — lista PossibleFormats necessária Automático — mais de 50 formatos
Leitura de PDF Não — requer o PdfiumViewer ou similar. Nativo — chamada de método único
Suporte da plataforma Pacotes de vinculação separados por plataforma Pacote único, todas as plataformas
Vários códigos de barras por imagem Sim — DecodeMultiple Sim — comportamento padrão
Geração de código de barras Retorna Bitmap, requer salvamento manual API fluente com saída integrada
Suporte para logotipo de código QR Não Sim
Controle de cores do código QR Não Sim
Recuperação de código de barras danificado flag TryHarder Correção de imagem com tecnologia de aprendizado de máquina
Dependências extras do Docker Pode requerer libgdiplus None
Suporte a SLA comercial Não Sim
Pacotes NuGet necessários 2–3 (núcleo + vinculação + ImageSharp opcional) 1

Início rápido

Passo 1: Remova os pacotes .NET do ZXing

Remova todos os pacotes ZXing .NET e relacionados do projeto:

dotnet remove package ZXing.Net
dotnet remove package ZXing.Net.Bindings.Windows.Compatibility
dotnet remove package ZXing.Net.Bindings.ImageSharp
dotnet remove package PdfiumViewer
dotnet remove package ZXing.Net
dotnet remove package ZXing.Net.Bindings.Windows.Compatibility
dotnet remove package ZXing.Net.Bindings.ImageSharp
dotnet remove package PdfiumViewer
SHELL

Se os binários nativos do PdfiumViewer foram instalados como um pacote separado:

dotnet remove package PdfiumViewer.Native.x64.v8-xfa
dotnet remove package PdfiumViewer.Native.x64.v8-xfa
SHELL

Se o Dockerfile contiver apt-get install -y libgdiplus — adicionado para suportar System.Drawing através da vinculação do Windows no Linux — essa linha pode ser removida após a migração.

Passo 2: Instale o IronBarcode

dotnet add package IronBarcode
dotnet add package IronBarcode
SHELL

Não são necessários pacotes de vinculação adicionais nem dependências específicas da plataforma. O mesmo pacote NuGet funciona no Windows, Linux, macOS e em contêineres Docker. Para obter detalhes sobre a implementação, o guia de configuração do IronBarcode para Docker e Linux aborda o padrão exato do Dockerfile.

Etapa 3: Atualizar Namespaces e Inicializar Licença

Remova todos os namespaces relacionados ao ZXing de todos os arquivos que usam operações de código de barras:

// Remove all of these:
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using ZXing.ImageSharp;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using PdfiumViewer;

// Add this single import:
using IronBarCode;
// Remove all of these:
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using ZXing.ImageSharp;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using PdfiumViewer;

// Add this single import:
using IronBarCode;
Imports IronBarCode
$vbLabelText   $csharpLabel

Adicionar inicialização da licença na inicialização do aplicativo, antes de qualquer operação com código de barras:

// Program.cs or Startup.cs — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// Program.cs or Startup.cs — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
' Program.vb or Startup.vb — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

A chave de licença é uma string simples que pode ser carregada de uma variável de ambiente, appsettings.json, ou um gerenciador de segredos. Não há arquivo para localizar nem caminho para configurar.

Exemplos de migração de código

Leitura de um único código de barras a partir de uma imagem

Este exemplo substitui o padrão de uso mais comum do ZXing .NET : instanciar um leitor, configurar a lista de formatos, carregar um bitmap e decodificar.

Abordagem ZXing .NET :

using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;

public string ReadSingleBarcode(string imagePath)
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    };

    using var bitmap = new Bitmap(imagePath);
    var result = reader.Decode(bitmap);

    return result?.Text ?? string.Empty;
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;

public string ReadSingleBarcode(string imagePath)
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    };

    using var bitmap = new Bitmap(imagePath);
    var result = reader.Decode(bitmap);

    return result?.Text ?? string.Empty;
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Drawing

Public Function ReadSingleBarcode(imagePath As String) As String
    Dim reader = New BarcodeReader()
    reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    }

    Using bitmap As New Bitmap(imagePath)
        Dim result = reader.Decode(bitmap)
        Return If(result?.Text, String.Empty)
    End Using
End Function
$vbLabelText   $csharpLabel

Abordagem do IronBarcode:

using IronBarCode;

public string ReadSingleBarcode(string imagePath)
{
    var result = BarcodeReader.Read(imagePath).FirstOrDefault();
    return result?.Value ?? string.Empty;
}
using IronBarCode;

public string ReadSingleBarcode(string imagePath)
{
    var result = BarcodeReader.Read(imagePath).FirstOrDefault();
    return result?.Value ?? string.Empty;
}
Imports IronBarCode

Public Function ReadSingleBarcode(imagePath As String) As String
    Dim result = BarcodeReader.Read(imagePath).FirstOrDefault()
    Return If(result?.Value, String.Empty)
End Function
$vbLabelText   $csharpLabel

A lista de formatos, a alocação Bitmap, e o bloco using são todos removidos. O IronBarcode aceita um caminho de arquivo diretamente e detecta automaticamente todos os formatos suportados. A propriedade que anteriormente retornava a string decodificada era result.Text no ZXing.Net; agora é result.Value no IronBarcode.

Leitura de todos os códigos de barras de uma imagem

Este exemplo substitui DecodeMultiple, que no ZXing.Net requer uma lista exaustiva de formatos para evitar falhas silenciosas.

Abordagem ZXing .NET :

using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;

public List<string> ReadAllBarcodes(string imagePath)
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.CODE_39,
        BarcodeFormat.EAN_13,
        BarcodeFormat.EAN_8,
        BarcodeFormat.UPC_A,
        BarcodeFormat.DATA_MATRIX,
        BarcodeFormat.PDF_417
    };
    reader.Options.TryHarder = true;

    using var bitmap = new Bitmap(imagePath);
    var results = reader.DecodeMultiple(bitmap);

    return results?.Select(r => r.Text).ToList() ?? new List<string>();
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;

public List<string> ReadAllBarcodes(string imagePath)
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.CODE_39,
        BarcodeFormat.EAN_13,
        BarcodeFormat.EAN_8,
        BarcodeFormat.UPC_A,
        BarcodeFormat.DATA_MATRIX,
        BarcodeFormat.PDF_417
    };
    reader.Options.TryHarder = true;

    using var bitmap = new Bitmap(imagePath);
    var results = reader.DecodeMultiple(bitmap);

    return results?.Select(r => r.Text).ToList() ?? new List<string>();
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Drawing

Public Function ReadAllBarcodes(imagePath As String) As List(Of String)
    Dim reader = New BarcodeReader()
    reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.CODE_39,
        BarcodeFormat.EAN_13,
        BarcodeFormat.EAN_8,
        BarcodeFormat.UPC_A,
        BarcodeFormat.DATA_MATRIX,
        BarcodeFormat.PDF_417
    }
    reader.Options.TryHarder = True

    Using bitmap As New Bitmap(imagePath)
        Dim results = reader.DecodeMultiple(bitmap)
        Return If(results?.Select(Function(r) r.Text).ToList(), New List(Of String)())
    End Using
End Function
$vbLabelText   $csharpLabel

Abordagem do IronBarcode:

using IronBarCode;

public List<string> ReadAllBarcodes(string imagePath)
{
    return BarcodeReader.Read(imagePath)
        .Select(r => r.Value)
        .ToList();
}
using IronBarCode;

public List<string> ReadAllBarcodes(string imagePath)
{
    return BarcodeReader.Read(imagePath)
        .Select(r => r.Value)
        .ToList();
}
Imports IronBarCode

Public Function ReadAllBarcodes(imagePath As String) As List(Of String)
    Return BarcodeReader.Read(imagePath) _
        .Select(Function(r) r.Value) _
        .ToList()
End Function
$vbLabelText   $csharpLabel

BarcodeReader.Read sempre retorna uma coleção e nunca retorna nulo, eliminando a necessidade de uma proteção nula no resultado. Para ajustar o equilíbrio entre precisão e velocidade, veja o guia de opções de velocidade de leitura, que cobre o enum ReadingSpeed sem estreitar o escopo do formato.

Processamento em lote concorrente

Este exemplo demonstra a diferença em relação à segurança de threads de forma mais direta. O ZXing .NET requer um novo leitor para cada operação paralela;IronBarcode usa a mesma chamada estática independentemente do nível de concorrência.

Abordagem ZXing .NET :

using ZXing;
using ZXing.Windows.Compatibility;
using System.Collections.Concurrent;
using System.Drawing;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
    var output = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(filePaths, new ParallelOptions { MaxDegreeOfParallelism = 4 }, file =>
    {
        // ZXing.Net is not thread-safe — a new reader is required per parallel operation
        var reader = new BarcodeReader();
        reader.Options.PossibleFormats = new List<BarcodeFormat>
        {
            BarcodeFormat.QR_CODE,
            BarcodeFormat.CODE_128
        };

        using var bitmap = new Bitmap(file);
        var result = reader.Decode(bitmap);
        if (result != null)
            output[file] = result.Text;
    });

    return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Collections.Concurrent;
using System.Drawing;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
    var output = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(filePaths, new ParallelOptions { MaxDegreeOfParallelism = 4 }, file =>
    {
        // ZXing.Net is not thread-safe — a new reader is required per parallel operation
        var reader = new BarcodeReader();
        reader.Options.PossibleFormats = new List<BarcodeFormat>
        {
            BarcodeFormat.QR_CODE,
            BarcodeFormat.CODE_128
        };

        using var bitmap = new Bitmap(file);
        var result = reader.Decode(bitmap);
        if (result != null)
            output[file] = result.Text;
    });

    return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Collections.Concurrent
Imports System.Drawing

Public Function ProcessBatch(filePaths As IEnumerable(Of String)) As Dictionary(Of String, String)
    Dim output = New ConcurrentDictionary(Of String, String)()

    Parallel.ForEach(filePaths, New ParallelOptions With {.MaxDegreeOfParallelism = 4}, Sub(file)
        ' ZXing.Net is not thread-safe — a new reader is required per parallel operation
        Dim reader = New BarcodeReader()
        reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
            BarcodeFormat.QR_CODE,
            BarcodeFormat.CODE_128
        }

        Using bitmap As New Bitmap(file)
            Dim result = reader.Decode(bitmap)
            If result IsNot Nothing Then
                output(file) = result.Text
            End If
        End Using
    End Sub)

    Return output.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
End Function
$vbLabelText   $csharpLabel

Abordagem do IronBarcode:

using IronBarCode;
using System.Collections.Concurrent;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
    var output = new ConcurrentDictionary<string, string>();
    var options = new BarcodeReaderOptions { MaxParallelThreads = 4 };

    Parallel.ForEach(filePaths, file =>
    {
        var result = BarcodeReader.Read(file, options).FirstOrDefault();
        if (result != null)
            output[file] = result.Value;
    });

    return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
using IronBarCode;
using System.Collections.Concurrent;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
    var output = new ConcurrentDictionary<string, string>();
    var options = new BarcodeReaderOptions { MaxParallelThreads = 4 };

    Parallel.ForEach(filePaths, file =>
    {
        var result = BarcodeReader.Read(file, options).FirstOrDefault();
        if (result != null)
            output[file] = result.Value;
    });

    return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
Imports IronBarCode
Imports System.Collections.Concurrent

Public Function ProcessBatch(filePaths As IEnumerable(Of String)) As Dictionary(Of String, String)
    Dim output = New ConcurrentDictionary(Of String, String)()
    Dim options = New BarcodeReaderOptions With {.MaxParallelThreads = 4}

    Parallel.ForEach(filePaths, Sub(file)
        Dim result = BarcodeReader.Read(file, options).FirstOrDefault()
        If result IsNot Nothing Then
            output(file) = result.Value
        End If
    End Sub)

    Return output.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
End Function
$vbLabelText   $csharpLabel

Não há nenhuma instância de leitor para proteger ou isolar. Para padrões de pipeline assíncronos e configuração de número de threads, consulte o guia de leitura de código de barras assíncrona e multithread .

Extraindo códigos de barras de um PDF

Este exemplo substitui o loop de renderização do PdfiumViewer. Se a integração existente usava Ghostscript ou iText em vez de PdfiumViewer, o bloco antes será diferente nos detalhes, mas estruturalmente idêntico: um loop de enumeração de páginas alimentando bitmaps no ZXing.Net.

Abordagem ZXing .NET :

using ZXing;
using ZXing.Windows.Compatibility;
using PdfiumViewer;
using System.Drawing;
using System.Drawing.Imaging;

public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
    var collected = new List<string>();

    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.PDF_417
    };

    using var document = PdfDocument.Load(pdfPath);
    for (int page = 0; page < document.PageCount; page++)
    {
        string temp = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png");
        try
        {
            using var rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi);
            rendered.Save(temp, ImageFormat.Png);

            using var bmp = new Bitmap(temp);
            var decoded = reader.DecodeMultiple(bmp);
            if (decoded != null)
                collected.AddRange(decoded.Select(d => d.Text));
        }
        finally
        {
            if (File.Exists(temp))
                File.Delete(temp);
        }
    }

    return collected;
}
using ZXing;
using ZXing.Windows.Compatibility;
using PdfiumViewer;
using System.Drawing;
using System.Drawing.Imaging;

public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
    var collected = new List<string>();

    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.PDF_417
    };

    using var document = PdfDocument.Load(pdfPath);
    for (int page = 0; page < document.PageCount; page++)
    {
        string temp = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png");
        try
        {
            using var rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi);
            rendered.Save(temp, ImageFormat.Png);

            using var bmp = new Bitmap(temp);
            var decoded = reader.DecodeMultiple(bmp);
            if (decoded != null)
                collected.AddRange(decoded.Select(d => d.Text));
        }
        finally
        {
            if (File.Exists(temp))
                File.Delete(temp);
        }
    }

    return collected;
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports PdfiumViewer
Imports System.Drawing
Imports System.Drawing.Imaging

Public Function ExtractBarcodesFromPdf(pdfPath As String) As List(Of String)
    Dim collected As New List(Of String)()

    Dim reader As New BarcodeReader()
    reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.PDF_417
    }

    Using document = PdfDocument.Load(pdfPath)
        For page As Integer = 0 To document.PageCount - 1
            Dim temp As String = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png")
            Try
                Using rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi)
                    rendered.Save(temp, ImageFormat.Png)

                    Using bmp As New Bitmap(temp)
                        Dim decoded = reader.DecodeMultiple(bmp)
                        If decoded IsNot Nothing Then
                            collected.AddRange(decoded.Select(Function(d) d.Text))
                        End If
                    End Using
                End Using
            Finally
                If File.Exists(temp) Then
                    File.Delete(temp)
                End If
            End Try
        Next
    End Using

    Return collected
End Function
$vbLabelText   $csharpLabel

Abordagem do IronBarcode:

using IronBarCode;

public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
    return BarcodeReader.Read(pdfPath)
        .Select(r => r.Value)
        .ToList();
}
using IronBarCode;

public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
    return BarcodeReader.Read(pdfPath)
        .Select(r => r.Value)
        .ToList();
}
Imports IronBarCode

Public Function ExtractBarcodesFromPdf(pdfPath As String) As List(Of String)
    Return BarcodeReader.Read(pdfPath) _
        .Select(Function(r) r.Value) _
        .ToList()
End Function
$vbLabelText   $csharpLabel

A dependência do PdfiumViewer, o loop de renderização da página, a configuração de DPI, a criação de arquivos temporários e o bloco de limpeza foram todos removidos. O IronBarcodelê códigos de barras de PDFs nativamente , processando todas as páginas automaticamente.

Geração de um código de barras

O escritor do ZXing.Net retorna um Bitmap que os chamadores devem salvar usando System.Drawing.Imaging. O IronBarcode retorna um GeneratedBarcode com métodos de saída incorporados.

Abordagem ZXing .NET :

using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using System.Drawing;
using System.Drawing.Imaging;

public void WriteCode128(string content, string outputPath)
{
    var writer = new BarcodeWriter
    {
        Format = BarcodeFormat.CODE_128,
        Options = new EncodingOptions
        {
            Width = 400,
            Height = 120,
            Margin = 10
        }
    };

    using var bitmap = writer.Write(content);
    bitmap.Save(outputPath, ImageFormat.Png);
}
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using System.Drawing;
using System.Drawing.Imaging;

public void WriteCode128(string content, string outputPath)
{
    var writer = new BarcodeWriter
    {
        Format = BarcodeFormat.CODE_128,
        Options = new EncodingOptions
        {
            Width = 400,
            Height = 120,
            Margin = 10
        }
    };

    using var bitmap = writer.Write(content);
    bitmap.Save(outputPath, ImageFormat.Png);
}
Imports ZXing
Imports ZXing.Common
Imports ZXing.Windows.Compatibility
Imports System.Drawing
Imports System.Drawing.Imaging

Public Sub WriteCode128(content As String, outputPath As String)
    Dim writer = New BarcodeWriter With {
        .Format = BarcodeFormat.CODE_128,
        .Options = New EncodingOptions With {
            .Width = 400,
            .Height = 120,
            .Margin = 10
        }
    }

    Using bitmap = writer.Write(content)
        bitmap.Save(outputPath, ImageFormat.Png)
    End Using
End Sub
$vbLabelText   $csharpLabel

Abordagem do IronBarcode:

using IronBarCode;

public void WriteCode128(string content, string outputPath)
{
    BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128)
        .ResizeTo(400, 120)
        .SaveAsPng(outputPath);
}
using IronBarCode;

public void WriteCode128(string content, string outputPath)
{
    BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128)
        .ResizeTo(400, 120)
        .SaveAsPng(outputPath);
}
Imports IronBarCode

Public Sub WriteCode128(content As String, outputPath As String)
    BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128) _
        .ResizeTo(400, 120) _
        .SaveAsPng(outputPath)
End Sub
$vbLabelText   $csharpLabel

Se a saída binária for necessária em vez de salvar em um arquivo, ToPngBinaryData() e ToJpegBinaryData() estão disponíveis no objeto retornado GeneratedBarcode sem qualquer encanamento MemoryStream.

Referência de mapeamento da API .NET do ZXing para o IronBarcode

ZXing.Net IronBarcode Notas
new BarcodeReader() Estático — nenhuma instância BarcodeReader.Read(...) é uma chamada estática
reader.Options.PossibleFormats = new List<BarcodeFormat> { ... } Não é necessário A detecção automática abrange mais de 50 formatos.
reader.Options.TryHarder = true Speed = ReadingSpeed.Balanced Ajuste de precisão via BarcodeReaderOptions
reader.Decode(bitmap) BarcodeReader.Read(imagePath).FirstOrDefault() Passar o caminho do arquivo — não é necessário construir Bitmap
reader.DecodeMultiple(bitmap) BarcodeReader.Read(imagePath) Sempre retorna uma coleção; never null
result.Text result.Value Propriedade renomeada
result.BarcodeFormat result.Format Propriedade renomeada
BarcodeFormat.QR_CODE BarcodeEncoding.QRCode Alteração na convenção de nomenclatura de enumerações
BarcodeFormat.CODE_128 BarcodeEncoding.Code128 Alteração na convenção de nomenclatura de enumerações
BarcodeFormat.EAN_13 BarcodeEncoding.EAN13 Alteração na convenção de nomenclatura de enumerações
BarcodeFormat.DATA_MATRIX BarcodeEncoding.DataMatrix Alteração na convenção de nomenclatura de enumerações
BarcodeFormat.PDF_417 BarcodeEncoding.PDF417 Alteração na convenção de nomenclatura de enumerações
new BarcodeWriter { Format = ..., Options = new EncodingOptions { ... } } BarcodeWriter.CreateBarcode(data, encoding) Fábrica estática, sem objeto de opções
writer.Write(data) retorna Bitmap .SaveAsPng(path) / .ToPngBinaryData() Saída incorporada em GeneratedBarcode
EncodingOptions { Width, Height } .ResizeTo(width, height) Método de dimensionamento Fluent
Sem suporte para PDF BarcodeReader.Read("file.pdf") Suporte nativo a PDF, todas as páginas

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

Problema 1: Padrões de instanciação do leitor de código de barras

ZXing.Net: Os chamadores criam um new BarcodeReader(), definem reader.Options.PossibleFormats, carregam um Bitmap, chamam reader.Decode(bitmap) ou reader.DecodeMultiple(bitmap), e leem result.Text.

Solução: Remova a instanciação por completo. Substitua o padrão completo por uma chamada estática:

// Before: reader creation + format config + bitmap + decode + result.Text
// After:
var result = BarcodeReader.Read(imagePath).FirstOrDefault();
var value = result?.Value ?? string.Empty;
// Before: reader creation + format config + bitmap + decode + result.Text
// After:
var result = BarcodeReader.Read(imagePath).FirstOrDefault();
var value = result?.Value ?? string.Empty;
' Before: reader creation + format config + bitmap + decode + result.Text
' After:
Dim result = BarcodeReader.Read(imagePath).FirstOrDefault()
Dim value = If(result?.Value, String.Empty)
$vbLabelText   $csharpLabel

Procure no código por new BarcodeReader() para encontrar cada instância. Cada um é removido, não refatorado.

Problema 2: Remoção do bloco PossibleFormats

ZXing .NET: Cada chamada de decodificação é precedida por um reader.Options.PossibleFormats = new List. { ... atribuição. Essas listas costumam ser longas e específicas para cada projeto.

Solução: Exclua cada bloco de atribuição de PossibleFormats por inteiro. O IronBarcode realiza a detecção automática de formato; Nenhuma lista de formatos é aceita ou exigida. Se o sinalizador TryHarder = true foi definido juntamente com a lista de formatos, substitua por Speed = ReadingSpeed.Balanced em um objeto BarcodeReaderOptions se o ajuste de precisão for necessário.

Problema 3: Limpeza do pacote de vinculação

ZXing.Net: Projetos usando ZXing.Net.Bindings.Windows.Compatibility têm código que referenciam System.Drawing.Bitmap como tipo de entrada. Projetos usando ZXing.Net.Bindings.ImageSharp referenciam SixLabors.ImageSharp.Image<Rgba32>. Ambos os padrões são interrompidos após a remoção dos pacotes de vinculação.

Solução: Remova ambos os pacotes de vinculação e substitua todo o código de carregamento de imagens. O BarcodeReader.Read do IronBarcode aceita uma string de caminho de arquivo, um byte[], um Stream, ou um Uri — não é necessário construção Bitmap ou Image<t>. Remanescentes de importações using System.Drawing; que existiam apenas para carregamento Bitmap também podem ser removidos.

Problema 4: result.Text para result.Value

ZXing.Net: O valor decodificado do código de barras é acessado via result.Text. O formato do código de barras é acessado via result.BarcodeFormat.

Solução: Substitua result.Text por result.Value e result.BarcodeFormat por result.Format em todo o código. Ambas as mudanças são renomeações simples de propriedade, sem diferença de comportamento.

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

Tarefas pré-migração

Antes de fazer alterações, faça uma auditoria no código-fonte para encontrar todas as referências ao .NET do ZX:

grep -r "using ZXing" --include="*.cs" .
grep -r "new BarcodeReader" --include="*.cs" .
grep -r "PossibleFormats" --include="*.cs" .
grep -r "BarcodeFormat\." --include="*.cs" .
grep -r "reader\.Decode\|reader\.DecodeMultiple" --include="*.cs" .
grep -r "result\.Text\|result\.BarcodeFormat" --include="*.cs" .
grep -r "new BarcodeWriter\|writer\.Write\|EncodingOptions" --include="*.cs" .
grep -r "PdfiumViewer\|PdfDocument\.Load" --include="*.cs" .
grep -r "using System\.Drawing" --include="*.cs" .
grep -r "using ZXing" --include="*.cs" .
grep -r "new BarcodeReader" --include="*.cs" .
grep -r "PossibleFormats" --include="*.cs" .
grep -r "BarcodeFormat\." --include="*.cs" .
grep -r "reader\.Decode\|reader\.DecodeMultiple" --include="*.cs" .
grep -r "result\.Text\|result\.BarcodeFormat" --include="*.cs" .
grep -r "new BarcodeWriter\|writer\.Write\|EncodingOptions" --include="*.cs" .
grep -r "PdfiumViewer\|PdfDocument\.Load" --include="*.cs" .
grep -r "using System\.Drawing" --include="*.cs" .
SHELL

Documente quais arquivos referenciam pacotes de vinculação do ZXing (Windows vs ImageSharp) e observe onde System.Drawing.Bitmap é usado exclusivamente para entrada do ZXing. Revise o Dockerfile (se presente) para a instalação libgdiplus.

Tarefas de atualização de código

  1. Remova os pacotes NuGet ZXing.Net, ZXing.Net.Bindings.Windows.Compatibility, ZXing.Net.Bindings.ImageSharp e PdfiumViewer
  2. Instale o pacote NuGet IronBarcode
  3. Adicione IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"; ao início da aplicação
  4. Substitua todas as importações de using ZXing* e using SixLabors.ImageSharp* por using IronBarCode;
  5. Remova cada instanciação de new BarcodeReader()
  6. Exclua cada bloco reader.Options.PossibleFormats = ...
  7. Substitua reader.Decode(bitmap) por BarcodeReader.Read(imagePath).FirstOrDefault()
  8. Substitua reader.DecodeMultiple(bitmap) por BarcodeReader.Read(imagePath)
  9. Substitua result.Text por result.Value
  10. Substitua result.BarcodeFormat por result.Format
  11. Atualize as referências enum BarcodeFormat.X para equivalentes BarcodeEncoding.X
  12. Substitua new BarcodeWriter { Format = ..., Options = new EncodingOptions { ... } }with BarcodeWriter.CreateBarcode(data, encoding).ResizeTo(w, h)
  13. Substitua writer.Write(data) + bitmap.Save(...) por .SaveAsPng(path) ou .ToPngBinaryData()
  14. Remova todas as importações using System.Drawing; que existiam apenas para carregamento de bitmap do ZXing.Net
  15. Remova o loop de renderização de página do PdfiumViewer de todos os locais onde ele foi implementado como uma solução alternativa para PDFs.
  16. Remova libgdiplus do Dockerfile se foi adicionado para suportar System.Drawing no Linux

Testes pós-migração

  • Verifique se todos os formatos de código de barras que o aplicativo foi previamente configurado para detectar foram encontrados com sucesso.
  • Teste com imagens contendo formatos de código de barras que foram previamente excluídos da lista PossibleFormats para confirmar se a detecção automática os reconhece
  • Execute os caminhos de processamento simultâneo sob carga e confirme que não há condições de corrida ou resultados nulos.
  • Se o aplicativo processou PDFs via PdfiumViewer, forneça as mesmas entradas de PDF e confirme se os valores dos códigos de barras correspondem.
  • Confirme se os códigos de barras gerados (Código 128, Código QR, etc.) apresentam o formato e as dimensões corretas.
  • Em implantações no Linux ou Docker, confirme que a leitura de imagens e PDF funciona sem libgdiplus Execute o Suite completo de testes e compare os resultados com a linha de base pré-migração.

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

Eliminação do ônus da segurança de threads: a API estática do IronBarcode remove completamente o padrão de instância por thread. Não há leitor para instanciar, nenhuma lista de formatos para configurar por thread, e nenhuma piscina ThreadLocal para gerenciar. A mesma chamada é correta tanto em ambientes de thread única quanto em ambientes altamente concorrentes, e a correção da concorrência é fornecida pela biblioteca, em vez de ser delegada a cada chamador.

Detecção Automática de Formato: Remover a lista PossibleFormats elimina a categoria de falhas de silêncio que ocorrem quando os documentos contêm formatos de código de barras que não foram antecipados durante o desenvolvimento. Aplicações que processam documentos de parceiros externos ou que operam em padrões de código de barras em constante evolução não exigem mais a manutenção de listas de formatos para permanecerem confiáveis.

Processamento nativo de PDF: O loop de renderização do PdfiumViewer — incluindo a enumeração de páginas, a configuração de DPI, o ciclo de vida do arquivo temporário e o código de limpeza — foi completamente removido. Aplicações que antes exigiam duas bibliotecas (ZXing .NET e um renderizador de PDF) para processar um código de barras em PDF, agora utilizam apenas uma. A redução das dependências implantadas simplifica tanto a construção quanto a implantação.

Pacote único multiplataforma: Elimina-se a distinção entre pacotes de vinculação para implantações em Windows e Linux. A mesma chamada BarcodeReader.Read(path) compila e se comporta identicamente em todas as plataformas de destino, removendo a necessidade de condicionais de plataforma no código de carregamento de imagens e simplificando os fluxos de trabalho de desenvolvimento cross-platform e de conteinerização.

Redução do código de infraestrutura: O resultado mais significativo da migração é a remoção da infraestrutura subjacente — os blocos de carregamento de Bitmap, as listas de formatos, os loops de renderização do PdfiumViewer, os pools ThreadLocal — que existiam nas integrações ZXing .NET não para realizar o trabalho de código de barras, mas para atender aos requisitos arquitetônicos da biblioteca. O que resta após a migração é a própria lógica do código de barras. Para obter mais contexto sobre taxas de detecção e cenários de digitalização, a comparação entre os scanners ZXing .NET e IronBarcode oferece uma análise mais abrangente.

ObserveGhostscript, PDFium, ZXing.NET e iText são marcas registradas de seus respectivos proprietários. Este site não é afiliado, endossado ou patrocinado pela Artifex Software, Chromium Project, Google, ZXing.NET ou iText Group. Todos os nomes de produtos, logotipos e marcas são propriedade de seus respectivos proprietários. As comparações são apenas para fins informativos e refletem informações disponíveis publicamente no momento da redação.

Perguntas frequentes

Por que devo migrar do ZXing.Net para o IronBarcode?

Entre os motivos comuns estão a simplificação do licenciamento (removendo a complexidade do SDK e da chave de tempo de execução), a eliminação dos limites de taxa de transferência, a obtenção de suporte nativo para PDF, a melhoria da implantação em Docker/CI/CD e a redução do código repetitivo da API em produção.

Como faço para substituir as chamadas da API do ZXing.Net pelo IronBarcode?

Substitua o código padrão de criação de instâncias e licenciamento por `IronBarCode.License.LicenseKey = "key"`. Substitua as chamadas de leitura por `BarcodeReader.Read(path)` e as chamadas de gravação por `BarcodeWriter.CreateBarcode(data, encoding)`. Os métodos estáticos não exigem gerenciamento de instâncias.

Quanta alteração de código ocorre ao migrar do ZXing.Net para o IronBarcode?

A maioria das migrações resulta em menos linhas de código. O código repetitivo de licenciamento, os construtores de instância e a configuração explícita de formato são removidos. As operações principais de leitura/gravação são mapeadas para equivalentes mais curtos em IronBarcode, com objetos de resultado mais limpos.

Preciso manter o ZXing.Net e o IronBarcode instalados durante a migração?

Não. A maioria das migrações são substituições diretas, e não operações paralelas. Migre uma classe de serviço por vez, substitua a referência do NuGet e atualize os padrões de instanciação e chamada de API antes de passar para a próxima classe.

Qual é o nome do pacote NuGet para IronBarcode?

O pacote é 'IronBarCode' (com B e C maiúsculos). Instale-o com 'Install-Package IronBarCode' ou 'dotnet add package IronBarCode'. A diretiva using no código é 'using IronBarCode;'.

Como o IronBarcode simplifica a implantação do Docker em comparação com o ZXing.Net?

IronBarcode é um pacote NuGet sem arquivos SDK externos ou configuração de licença montada. No Docker, defina a variável de ambiente IRONBARCODE_LICENSE_KEY e o pacote cuidará da validação da licença na inicialização.

O IronBarcode detecta automaticamente todos os formatos de código de barras após a migração do ZXing.Net?

Sim. O IronBarcode detecta automaticamente a simbologia em todos os formatos suportados. A enumeração explícita de BarcodeTypes não é necessária. Se o formato já for conhecido e o desempenho for importante, o BarcodeReaderOptions permite restringir o espaço de busca como uma otimização.

O IronBarcode consegue ler códigos de barras de PDFs sem uma biblioteca separada?

Sim. O método `BarcodeReader.Read("document.pdf")` processa arquivos PDF nativamente. Os resultados incluem o número da página, o formato, o valor e a confiança de cada código de barras encontrado. Não é necessária nenhuma etapa externa de renderização de PDF.

Como o IronBarcode lida com o processamento paralelo de códigos de barras?

Os métodos estáticos do IronBarcode são sem estado e thread-safe. Use Parallel.ForEach diretamente em listas de arquivos sem gerenciamento de instâncias por thread. BarcodeReaderOptions.MaxParallelThreads controla o orçamento interno de threads.

Quais propriedades de resultado são alteradas ao migrar do ZXing.Net para o IronBarcode?

Renomeações comuns: BarcodeValue torna-se Value, BarcodeType torna-se Format. Os resultados do IronBarcode também incluem Confidence e PageNumber. Uma função de busca e substituição em toda a solução lida com as renomeações no código de processamento de resultados existente.

Como configuro o licenciamento do IronBarcode em um pipeline de CI/CD?

Armazene IRONBARCODE_LICENSE_KEY como um segredo de pipeline e atribua IronBarCode.License.LicenseKey no código de inicialização do aplicativo. Um único segredo abrange todos os ambientes, incluindo desenvolvimento, teste, homologação e produção.

O IronBarcode suporta a geração de códigos QR com estilos personalizados?

Sim. O método QRCodeWriter.CreateQrCode() suporta cores personalizadas através do método ChangeBarCodeColor(), incorporação de logotipo através do método AddBrandLogo(), níveis configuráveis de correção de erros e múltiplos formatos de saída, incluindo PNG, JPG, PDF e fluxo de dados.

Curtis Chau
Redator Técnico

Curtis Chau é bacharel em Ciência da Computação (Universidade Carleton) e se especializa em desenvolvimento front-end, com experiência em Node.js, TypeScript, JavaScript e React. Apaixonado por criar interfaces de usuário intuitivas e esteticamente agradáveis, Curtis gosta de trabalhar com frameworks modernos e criar manuais ...

Leia mais

Equipe de Suporte Iron

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