Saltar al pie de página
VIDEOS

Cómo escribir códigos de barras Unicode e internacionales en C# | IronPDF

Migrando de ZXing.Net a IronBarcode

Esta guía abarca una migración completa de ZXing .NET a IronBarcode para aplicaciones .NET que leen y generan códigos de barras. Aborda la eliminación del paquete central de ZXing.Net y los paquetes de enlace, la eliminación de las soluciones alternativas de PdfiumViewer donde estén presentes, y la sustitución de cada instancia con estado BarcodeReader por la API estática de IronBarcode. Cada sección incluye código de antes y después, extraído de los patrones que se encuentran con mayor frecuencia en las integraciones de ZXing .NET .

¿Por qué migrar desde ZXing .NET?

ZXing .NET ha prestado un excelente servicio a la comunidad .NET durante más de una década como una biblioteca de códigos de barras gratuita basada en Apache 2.0. Sin embargo, varias limitaciones arquitectónicas se convierten en costes operativos a medida que las aplicaciones aumentan en escala o complejidad.

Propiedad de Seguridad del Hilo: el BarcodeReader de ZXing.Net es un objeto con estado. La propia documentación de la biblioteca indica que las instancias no deben compartirse entre hilos. En la práctica, esto significa que cada ruta de procesamiento concurrente —cada acción del controlador que maneja solicitudes simultáneas, cada tarea en un lote paralelo— debe asignar, configurar y descartar su propio lector. A medida que aumenta el volumen de solicitudes, este patrón de asignación produce una presión de memoria cuantificable. La alternativa ThreadLocal<BarcodeReader> reduce la frecuencia de asignación pero introduce su propia complejidad de eliminación. En ambos casos, la corrección bajo concurrencia es problema de quien realiza la llamada, no una garantía proporcionada por la biblioteca.

Riesgo de Especificación de Formato: ZXing.Net requiere que reader.Options.PossibleFormats esté poblado antes de cada operación de descodificación. Un código de barras en un formato que no esté presente en esa lista devuelve nulo — sin excepción, sin advertencia, sin indicación de que había un código de barras presente pero sin reconocer. Para aplicaciones que reciben documentos de socios externos, este comportamiento de omisión silenciosa es un riesgo de fiabilidad: un pedido mal despachado, un registro de check-in de pacientes perdido o una entrada de auditoría que nunca se escribe, todos pueden originarse a partir de una lista de formatos que se configuró para un requisito anterior y nunca se actualizó.

Limitación en el procesamiento de PDF: ZXing .NET solo lee mapas de bits. Cuando los documentos de origen son archivos PDF (facturas, manifiestos de envío, certificados de conformidad), quienes realizan las llamadas deben integrar una biblioteca de renderizado de PDF independiente (PdfiumViewer es la más común), implementar un bucle de enumeración de páginas, configurar el DPI, gestionar los archivos temporales y encargarse de la limpieza tanto en los casos de éxito como de error. Se trata de entre 30 y 50 líneas de código de infraestructura por integración, cuya única función es convertir lo que ZXing .NET no puede leer (archivos PDF) en lo que sí puede (mapas de bits). Esa infraestructura tiene sus propias dependencias, sus propios requisitos de implementación y sus propios modos de fallo.

Fragmentación de la vinculación entre plataformas: la capacidad de carga de imágenes de ZXing.Net está dividida entre paquetes de vinculación específicos de cada plataforma. El enlace de Windows utiliza System.Drawing.Bitmap; el enlace multiplataforma utiliza SixLabors.ImageSharp con un parámetro de tipo genérico diferente y una directiva using diferente. Un proyecto que comienza en Windows y luego se contenedora en Linux debe cambiar tanto sus referencias NuGet como su código de carga de imágenes. Existen dos rutas de código para la misma operación que aumentan la superficie de error y dificultan los cambios futuros en la capa de escaneo.

El problema fundamental

La ilustración más clara de la arquitectura ZXing .NET es la diferencia entre una llamada de un solo hilo y una concurrente. En ZXing .NET, el procesamiento concurrente requiere la creación de un objeto lector completo por cada operación 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 elimina el objeto por completo. La llamada estática es la misma tanto si se ejecuta en un hilo como en cien:

// 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: Comparación de características

Característica ZXing.Net IronBarcode
Licencia Apache 2.0 (gratuito) Comercial
Seguridad de hilos No es seguro para subprocesos: se requiere una nueva instancia por cada subproceso. API estática segura para subprocesos
Detección de formato Manual — se requiere lista PossibleFormats Automático: más de 50 formatos
Lectura de PDF No — requiere PdfiumViewer o similar Nativo: llamada a un solo método
Soporte de Plataforma Paquetes de enlace separados por plataforma Paquete único, todas las plataformas
Múltiples códigos de barras por imagen Sí — DecodeMultiple Sí — comportamiento predeterminado
Generación de códigos de barras Devuelve Bitmap, se requiere guardado manual API fluida con salida integrada
Soporte para logotipos de códigos QR No
Control de color del código QR No
Recuperación de códigos de barras dañados Bandera TryHarder Corrección de imágenes mediante aprendizaje automático
Dependencias adicionales de Docker Puede requerir libgdiplus None
Soporte para acuerdos de nivel de servicio (SLA) comerciales No
Paquetes NuGet necesarios 2–3 (núcleo + enlace + ImageSharp opcional) 1

Inicio rápido

Paso 1: Eliminar los paquetes .NET de ZXing

Elimine todos los paquetes ZXing .NET y relacionados del proyecto:

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

Si los binarios nativos de PdfiumViewer se instalaran como un paquete separado:

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

Si el Dockerfile contiene apt-get install -y libgdiplus — añadido para soportar System.Drawing a través del enlace de Windows en Linux — esa línea se puede eliminar después de la migración.

Paso 2: Instalar IronBarcode

dotnet add package IronBarcode
dotnet add package IronBarcode
SHELL

No se requieren paquetes de enlace adicionales ni dependencias específicas de la plataforma. El mismo paquete NuGet funciona en Windows, Linux, macOS y en contenedores Docker. Para obtener detalles sobre la implementación, la guía de configuración de IronBarcode para Docker y Linux cubre el patrón exacto del Dockerfile.

Paso 3: Actualizar espacios de nombres e inicializar la licencia.

Elimine todos los espacios de nombres relacionados con ZXing de cada archivo que utilice operaciones 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

Agregue la inicialización de la licencia al iniciar la aplicación, antes de cualquier operación con códigos 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

La clave de licencia es una cadena simple que se puede cargar desde una variable de entorno, appsettings.json, o un gestor de secretos. No hay ningún archivo que localizar ni ninguna ruta que configurar.

Ejemplos de migración de código

Lectura de un único código de barras a partir de una imagen.

Este ejemplo reemplaza el patrón de uso más común de ZXing .NET : instanciar un lector, configurar la lista de formatos, cargar un mapa de bits y decodificar.

Enfoque 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

Enfoque de 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

La lista de formatos, la asignación Bitmap, y el bloque using se eliminan. IronBarcode acepta directamente la ruta del archivo y detecta automáticamente todos los formatos compatibles. La propiedad que anteriormente devolvía la cadena decodificada era result.Text en ZXing.Net; ahora es result.Value en IronBarcode.

Lectura de todos los códigos de barras de una imagen.

Este ejemplo reemplaza DecodeMultiple, que en ZXing.Net requiere una lista exhaustiva de formatos para evitar omisiones silenciosas.

Enfoque 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

Enfoque de 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 siempre devuelve una colección y nunca devuelve null, eliminando la necesidad de un guardia nulo en el resultado. Para ajustar el equilibrio precisión/velocidad, consulte la guía de opciones de velocidad de lectura, que cubre el enum ReadingSpeed sin reducir el alcance del formato.

Procesamiento por lotes concurrente

Este ejemplo muestra la diferencia en la seguridad de los subprocesos de la forma más directa. ZXing .NET requiere un nuevo lector por cada operación paralela; IronBarcode utiliza la misma llamada estática independientemente del nivel de concurrencia.

Enfoque 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

Enfoque de 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

No hay ninguna instancia de lector que proteger o aislar. Para obtener información sobre patrones de canalización asíncrona y configuración del número de subprocesos, consulte la guía de lectura de códigos de barras asíncrona y multiproceso .

Cómo extraer códigos de barras de un PDF

Este ejemplo reemplaza el bucle de renderizado de PdfiumViewer. Si la integración existente utilizó Ghostscript o iText en lugar de PdfiumViewer, el bloque anterior se verá diferente en detalle pero estructuralmente idéntico: un bucle de enumeración de página que alimenta mapas de bits a ZXing.Net.

Enfoque 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

Enfoque de 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

Se eliminan la dependencia de PdfiumViewer, el bucle de renderizado de página, la configuración de DPI, la creación de archivos temporales y el bloque de limpieza. IronBarcode lee los códigos de barras de los archivos PDF de forma nativa , procesando todas las páginas automáticamente.

Generación de un código de barras

El escritor de ZXing.Net devuelve un Bitmap que los llamantes deben guardar usando System.Drawing.Imaging. IronBarcode devuelve un GeneratedBarcode con métodos de salida integrados.

Enfoque 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

Enfoque de 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

Si se necesita salida binaria en lugar de guardar en un archivo, ToPngBinaryData() y ToJpegBinaryData() están disponibles en el objeto GeneratedBarcode devuelto sin necesidad de MemoryStream.

Referencia de mapeo de la API .NET de ZXing a IronBarcode

ZXing.Net IronBarcode Notas
new BarcodeReader() Estático: ninguna instancia BarcodeReader.Read(...) es una llamada estática
lector.Opciones.FormatosPosibles = nueva lista<BarcodeFormat> { ... } No es necesario La detección automática cubre los más de 50 formatos.
reader.Options.TryHarder = true Speed = ReadingSpeed.Balanced Ajuste de precisión a través de BarcodeReaderOptions
reader.Decode(bitmap) BarcodeReader.Read(imagePath).FirstOrDefault() Pase la ruta del archivo — no se necesita construcción Bitmap
reader.DecodeMultiple(bitmap) BarcodeReader.Read(imagePath) Siempre devuelve una colección; never null
result.Text result.Value Propiedad renombrada
result.BarcodeFormat result.Format Propiedad renombrada
BarcodeFormat.QR_CODE BarcodeEncoding.QRCode Cambio en la convención de nomenclatura de enumeraciones
BarcodeFormat.CODE_128 BarcodeEncoding.Code128 Cambio en la convención de nomenclatura de enumeraciones
BarcodeFormat.EAN_13 BarcodeEncoding.EAN13 Cambio en la convención de nomenclatura de enumeraciones
BarcodeFormat.DATA_MATRIX BarcodeEncoding.DataMatrix Cambio en la convención de nomenclatura de enumeraciones
BarcodeFormat.PDF_417 BarcodeEncoding.PDF417 Cambio en la convención de nomenclatura de enumeraciones
new BarcodeWriter { Formato = ..., Opciones = new EncodingOptions { ... } } BarcodeWriter.CreateBarcode(data, encoding) Fábrica estática, sin objeto de opciones
writer.Write(data) devuelve Bitmap .SaveAsPng(path) / .ToPngBinaryData() Salida integrada en GeneratedBarcode
EncodingOptions { Width, Height } .ResizeTo(width, height) Método de dimensionamiento fluido
Sin soporte para PDF BarcodeReader.Read("file.pdf") Compatibilidad nativa con PDF, todas las páginas

Problemas comunes de migración y soluciones

Problema 1: Patrones de instanciación de lectores de códigos de barras

ZXing.Net: Los llamantes crean un new BarcodeReader(), establecen reader.Options.PossibleFormats, cargan un Bitmap, llaman a reader.Decode(bitmap) o reader.DecodeMultiple(bitmap), y leen result.Text.

Solución: Eliminar la instanciación por completo. Reemplace el patrón completo con una llamada 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

Busque en la base de código new BarcodeReader() para encontrar todas las instancias. Cada uno se elimina, no se refactoriza.

Problema 2: Eliminación del bloque PossibleFormats

ZXing .NET: Cada llamada de decodificación está precedida por un lector.Opciones.FormatosPosibles = nueva lista<BarcodeFormat> { ... }asignación. Estas listas suelen ser largas y específicas para cada proyecto.

Solución: Elimine cada bloque de asignación PossibleFormats en su totalidad. IronBarcode realiza la detección automática de formato; No se acepta ni se requiere ninguna lista de formatos. Si la bandera TryHarder = true fue establecida junto con la lista de formatos, reemplácela con Speed = ReadingSpeed.Balanced en un objeto BarcodeReaderOptions si se necesita ajuste de precisión.

Problema 3: Limpieza del paquete de enlace

ZXing.Net: Los proyectos que utilizan ZXing.Net.Bindings.Windows.Compatibility tienen código que referencia System.Drawing.Bitmap como el tipo de entrada. Los proyectos que utilizan ZXing.Net.Bindings.ImageSharp referencian SixLabors.ImageSharp.Image<Rgba32>. Ambos patrones se rompen después de que se eliminan los paquetes de enlace.

Solución: Elimine ambos paquetes de enlace y reemplace todo el código de carga de imágenes. El BarcodeReader.Read de IronBarcode acepta una cadena de ruta de archivo, un byte[], un Stream, o un Uri — no se necesita construcción Bitmap o Image<t>. Las importaciones using System.Drawing; restantes que existían únicamente para la carga de Bitmap también se pueden eliminar.

Problema 4: result.Text a result.Value

ZXing.Net: El valor del código de barras decodificado se accede a través de result.Text. El formato del código de barras se accede a través de result.BarcodeFormat.

Solución: Reemplace result.Text con result.Value y result.BarcodeFormat con result.Format en toda la base de código. Ambos cambios son simples cambios de nombre de propiedad sin diferencia de comportamiento.

Lista de verificación de migración de ZXing .NET

Tareas previas a la migración

Antes de realizar cambios, revise el código fuente para encontrar todas las referencias a ZXing .NET :

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 qué archivos hacen referencia a los paquetes de enlace ZXing (Windows vs ImageSharp) y anote dónde se usa System.Drawing.Bitmap únicamente para la entrada de ZXing. Revise el Dockerfile (si está presente) para la instalación de libgdiplus.

Tareas de actualización de código

  1. Elimine los paquetes de NuGet ZXing.Net, ZXing.Net.Bindings.Windows.Compatibility, ZXing.Net.Bindings.ImageSharp, y PdfiumViewer
  2. Instale el paquete NuGet IronBarcode
  3. Agregue IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"; al inicio de la aplicación
  4. Reemplace todas las importaciones using ZXing* y using SixLabors.ImageSharp* con using IronBarCode;
  5. Elimine cada instancia new BarcodeReader()
  6. Elimine cada bloque reader.Options.PossibleFormats = ...
  7. Reemplace reader.Decode(bitmap) con BarcodeReader.Read(imagePath).FirstOrDefault()
  8. Reemplace reader.DecodeMultiple(bitmap) con BarcodeReader.Read(imagePath)
  9. Reemplace result.Text con result.Value
  10. Reemplace result.BarcodeFormat con result.Format
  11. Actualice las referencias enum BarcodeFormat.X a equivalentes BarcodeEncoding.X
  12. Reemplazar new BarcodeWriter { Formato = ..., Opciones = new EncodingOptions { ... } }with BarcodeWriter.CreateBarcode(data, encoding).ResizeTo(w, h)
  13. Reemplace writer.Write(data) + bitmap.Save(...) con .SaveAsPng(path) o .ToPngBinaryData()
  14. Elimine todas las importaciones using System.Drawing; que existían únicamente para la carga de mapas de bits de ZXing.Net
  15. Elimine el bucle de renderizado de página de PdfiumViewer dondequiera que se haya implementado como solución alternativa para PDF.
  16. Elimine libgdiplus del Dockerfile si se añadió para soportar System.Drawing en Linux

Pruebas posteriores a la migración

  • Verificar que se detecten correctamente todos los formatos de código de barras que la aplicación estaba configurada previamente para detectar.
  • Pruebe con imágenes que contienen formatos de código de barras que anteriormente estaban excluidos de la lista PossibleFormats, para confirmar que la autodetección los recoge
  • Ejecute las rutas de procesamiento concurrente bajo carga y confirme que no haya condiciones de carrera ni resultados nulos.
  • Si la aplicación procesó archivos PDF a través de PdfiumViewer, proporcione los mismos datos de entrada de PDF y confirme que los valores del código de barras coinciden.
  • Confirme que los códigos de barras generados (Code 128, código QR, etc.) produzcan el formato y las dimensiones de salida correctos.
  • En implementaciones de Linux o Docker, confirme que la lectura de imágenes y PDF funciona sin libgdiplus
  • Ejecute el Suite completo de pruebas y compare el resultado con la línea base previa a la migración.

Principales ventajas de migrar a IronBarcode

Eliminación de la carga de seguridad de subprocesos: la API estática de IronBarcode elimina por completo el patrón de instancia por subproceso. No hay lector para instanciar, no hay lista de formatos para configurar por hilo, y no hay piscina de ThreadLocal para gestionar. La misma llamada es correcta tanto en entornos de un solo hilo como en entornos altamente concurrentes, y la corrección de la concurrencia la proporciona la biblioteca en lugar de delegarse a cada llamador.

Detección Automática de Formato: Eliminar la lista PossibleFormats elimina la categoría de fallos por omisión silenciosa que ocurren cuando los documentos contienen formatos de código de barras que no fueron anticipados durante el desarrollo. Las aplicaciones que procesan documentos de socios externos o que operan con estándares de códigos de barras en constante evolución ya no requieren el mantenimiento de listas de formatos para seguir siendo fiables.

Procesamiento nativo de PDF: El bucle de renderizado de PdfiumViewer —su enumeración de páginas, configuración de DPI, ciclo de vida de archivos temporales y código de limpieza— se elimina por completo. Las aplicaciones que antes requerían dos bibliotecas (ZXing .NET y un renderizador de PDF) para procesar un código de barras PDF ahora utilizan solo una. La reducción de las dependencias desplegadas simplifica tanto la compilación como la implementación.

Paquete único multiplataforma: Se elimina la distinción entre paquetes para implementaciones en Windows y Linux. La misma llamada BarcodeReader.Read(path) se compila y se comporta de manera idéntica en todas las plataformas objetivo, eliminando la necesidad de condicionales de plataforma en el código de carga de imágenes y simplificando los flujos de trabajo de desarrollo y contenedorización multiplataforma.

Reducción del código de infraestructura: El resultado más significativo de la migración es la eliminación de la infraestructura circundante (los bloques de carga de Bitmap, las listas de formato, los bucles de renderizado de PdfiumViewer, los grupos de ThreadLocal) que existían en las integraciones de ZXing .NET no para realizar tareas con códigos de barras, sino para satisfacer los requisitos arquitectónicos de la biblioteca. Lo que queda después de la migración es la lógica del código de barras en sí. Para obtener información adicional sobre las tasas de detección y los escenarios de escaneo, la comparación entre los escáneres ZXing .NET e IronBarcode ofrece un análisis más amplio.

Por favor notaGhostscript, PDFium, ZXing.NET e iText son marcas registradas de sus respectivos propietarios. Este sitio no está afiliado, respaldado ni patrocinado por Artifex Software, Chromium Project, Google, ZXing.NET o iText Group. Todos los nombres de productos, logotipos y marcas son propiedad de sus respectivos dueños. Las comparaciones son solo para fines informativos y reflejan información públicamente disponible en el momento de la redacción.

Preguntas Frecuentes

¿Por qué debería migrar de ZXing.Net a IronBarcode?

Entre las razones más comunes se incluyen la simplificación de licencias (eliminando la complejidad de SDK + clave de tiempo de ejecución), la eliminación de límites de rendimiento, la obtención de compatibilidad nativa con PDF, la mejora de la implementación de Docker/CI/CD y la reducción de la repetición de API en el código de producción.

¿Cómo puedo sustituir las llamadas a la API de ZXing.Net por IronBarcode?

Sustituya la creación de instancias y la repetición de licencias por IronBarCode.License.LicenseKey = "key". Sustituya las llamadas al lector por BarcodeReader.Read(path) y las llamadas al escritor por BarcodeWriter.CreateBarcode(data, encoding). Los métodos estáticos no requieren gestión de instancias.

¿Cuánto cambia el código al migrar de ZXing.Net a IronBarcode?

La mayoría de las migraciones se traducen en menos líneas de código. Se eliminan la repetición de licencias, los constructores de instancias y la configuración explícita de formatos. Las operaciones básicas de lectura/escritura se traducen a equivalentes IronBarcode más cortos con objetos de resultado más limpios.

¿Necesito tener instalados tanto ZXing.Net como IronBarcode durante la migración?

No. La mayoría de las migraciones son sustituciones directas en lugar de operaciones paralelas. Migre una clase de servicio cada vez, sustituya la referencia NuGet y actualice los patrones de instanciación y llamada a la API antes de pasar a la siguiente clase.

¿Cuál es el nombre del paquete NuGet para IronBarcode?

El paquete es 'IronBarCode' (con B y C mayúsculas). Instálalo con 'Install-Package IronBarCode' o 'dotnet add package IronBarCode'. La directiva using en el código es 'using IronBarCode;'.

¿Cómo simplifica IronBarcode el despliegue de Docker en comparación con ZXing.Net?

IronBarcode es un paquete NuGet sin archivos SDK externos ni configuración de licencia montada. En Docker, establezca la variable de entorno IRONBARCODE_LICENSE_KEY y el paquete se encargará de la validación de la licencia al inicio.

¿IronBarcode detecta automáticamente todos los formatos de código de barras después de migrar desde ZXing.Net?

Sí, IronBarcode detecta automáticamente la simbología de todos los formatos compatibles. No es necesaria la enumeración explícita de BarcodeTypes. Si ya se conoce el formato y el rendimiento es importante, BarcodeReaderOptions permite restringir el espacio de búsqueda como optimización.

¿Puede IronBarcode leer códigos de barras de PDF sin una biblioteca independiente?

Sí. BarcodeReader.Read("document.pdf") procesa archivos PDF de forma nativa. Los resultados incluyen PageNumber, Format, Value y Confidence para cada código de barras encontrado. No es necesario ningún paso externo de procesamiento de PDF.

¿Cómo gestiona IronBarcode el procesamiento paralelo de códigos de barras?

Los métodos estáticos de IronBarcode no tienen estado y son seguros para los hilos. Utilice Parallel.ForEach directamente sobre listas de archivos sin gestión de instancias por subproceso. BarcodeReaderOptions.MaxParallelThreads controla el presupuesto interno de hilos.

¿Qué propiedades de los resultados cambian al migrar de ZXing.Net a IronBarcode?

Cambios de nombre comunes: BarcodeValue se convierte en Value, BarcodeType se convierte en Format. Los resultados de IronBarcode también añaden Confidence y PageNumber. Una búsqueda y sustitución en toda la solución gestiona los cambios de nombre en el código de procesamiento de resultados existente.

¿Cómo configuro las licencias de IronBarcode en un proceso CI/CD?

Almacene IRONBARCODE_LICENSE_KEY como un secreto de canalización y asigne IronBarCode.License.LicenseKey en el código de inicio de la aplicación. Un secreto cubre todos los entornos, incluidos los de desarrollo, prueba, montaje y producción.

¿Admite IronBarcode la generación de códigos QR con estilos personalizados?

Sí. QRCodeWriter.CreateQrCode() admite colores personalizados mediante ChangeBarCodeColor(), incrustación de logotipos mediante AddBrandLogo(), niveles de corrección de errores configurables y múltiples formatos de salida, incluidos PNG, JPG, PDF y stream.

Curtis Chau
Escritor Técnico

Curtis Chau tiene una licenciatura en Ciencias de la Computación (Carleton University) y se especializa en el desarrollo front-end con experiencia en Node.js, TypeScript, JavaScript y React. Apasionado por crear interfaces de usuario intuitivas y estéticamente agradables, disfruta trabajando con frameworks modernos y creando manuales bien ...

Leer más

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame