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)
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)
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
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
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
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
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"
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
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
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
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
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
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
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
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
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
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
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)
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.
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" .
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
- Remova os pacotes NuGet
ZXing.Net,ZXing.Net.Bindings.Windows.Compatibility,ZXing.Net.Bindings.ImageSharpePdfiumViewer - Instale o pacote NuGet
IronBarcode - Adicione
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";ao início da aplicação - Substitua todas as importações de
using ZXing*eusing SixLabors.ImageSharp*porusing IronBarCode; - Remova cada instanciação de
new BarcodeReader() - Exclua cada bloco
reader.Options.PossibleFormats = ... - Substitua
reader.Decode(bitmap)porBarcodeReader.Read(imagePath).FirstOrDefault() - Substitua
reader.DecodeMultiple(bitmap)porBarcodeReader.Read(imagePath) - Substitua
result.Textporresult.Value - Substitua
result.BarcodeFormatporresult.Format - Atualize as referências enum
BarcodeFormat.Xpara equivalentesBarcodeEncoding.X - Substitua
new BarcodeWriter { Format = ..., Options = new EncodingOptions { ... } }withBarcodeWriter.CreateBarcode(data, encoding).ResizeTo(w, h) - Substitua
writer.Write(data)+bitmap.Save(...)por.SaveAsPng(path)ou.ToPngBinaryData() - Remova todas as importações
using System.Drawing;que existiam apenas para carregamento de bitmap do ZXing.Net - 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.
- Remova
libgdiplusdo Dockerfile se foi adicionado para suportarSystem.Drawingno 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
PossibleFormatspara 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
libgdiplusExecute 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.
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.

