Saltar al pie de página
VIDEOS

Cómo Leer Códigos de Barras Desde PDFs en C#

Migrating from BarcodeScanning.Native.Maui to IronBarcode

Esta guía proporciona una ruta de migración completa desde BarcodeScanning.Native.Maui a IronBarcode, que abarca la sustitución del patrón de eventos de la cámara, los cambios de espacio de nombres, ejemplos de migración de código y el manejo de escenarios que BarcodeScanning.Native.Maui no puede abordar: Windows MAUI, entrada de archivos y PDF, procesamiento del lado del servidor y generación de códigos de barras.

¿Por qué migrar desde BarcodeScanning.MAUI?

Los equipos que migran desde BarcodeScanning.Native.Maui informan de los siguientes desencadenantes:

Se requiere Windows MAUI como plataforma de destino: BarcodeScanning.Native.Maui encapsula las API nativas de iOS y Android. No tiene implementación para Windows ni está previsto que la tenga. Si tu aplicación MAUI está dirigida a Windows, además de iOS y Android, necesitas una biblioteca que funcione en las tres plataformas sin necesidad de ramificaciones específicas para cada una.

Entrada de archivos o PDF añadida a los requisitos: BarcodeScanning.Native.Maui solo acepta fotogramas de cámara en directo. Cuando los usuarios necesitan subir una imagen desde su galería, o cuando un punto final del servidor necesita extraer códigos de barras de archivos PDF, la biblioteca no ofrece ninguna ruta de código. Cada escenario de código de barras de archivos o PDF requiere una herramienta diferente.

Los datos UPC-A de iOS eran erróneos en producción: el marco Vision de Apple devuelve 13 dígitos para los códigos de barras UPC-A (codificación EAN-13). BarcodeScanning.Native.Maui lo transmite sin corregir. Si los códigos UPC-A se almacenaban con un cero inicial, los registros de inventario, las consultas en los puntos de venta o las integraciones de la cadena de suministro podrían haberse visto afectados silenciosamente. IronBarcode devuelve el valor UPC-A correcto de 12 dígitos sin necesidad de normalización manual.

El escaneo del PDF417 no era fiable: el propio documento de incidencias de la biblioteca en GitHub describe el PDF417 como "muy problemático: la mayoría de los escaneos no se realizan". Esto supone un bloqueo directo para etiquetas de envío, permisos de conducir y tarjetas de embarque.

Generación necesaria: BarcodeScanning.Native.Maui no puede generar códigos de barras. IronBarcode genera códigos Code128, QR, DataMatrix y otros formatos como archivos de imagen o matrices de bytes.

Se ha introducido el procesamiento del lado del servidor: BarcodeScanning.Native.Maui es un control de interfaz de usuario de la cámara; no puede ejecutarse en un proceso de servidor. Cuando se requiere la lectura de códigos de barras en el servidor junto con el escaneo móvil, IronBarcode cubre ambos lados con el mismo paquete y la misma API.

El problema fundamental

BarcodeScanning.Native.Maui vincula la lectura de códigos de barras completamente al modelo de eventos de la cámara en vivo. En el momento en que cualquier requisito queda fuera de ese modelo, la biblioteca no ofrece nada:

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode != null)
        ResultLabel.Text = barcode.DisplayValue;
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode != null)
        ResultLabel.Text = barcode.DisplayValue;
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
    Dim barcode = e.BarcodeResults.FirstOrDefault()
    If barcode IsNot Nothing Then
        ResultLabel.Text = barcode.DisplayValue
    End If
End Sub
$vbLabelText   $csharpLabel

IronBarcode acepta cualquier tipo de entrada de datos (captura de cámara, archivo, PDF, matriz de bytes) y funciona en todas las plataformas:

using IronBarCode;

private async void ScanBarcodeButton_Clicked(object sender, EventArgs e)
{
    var photo = await MediaPicker.CapturePhotoAsync();
    if (photo == null) return;

    using var stream = await photo.OpenReadAsync();
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
using IronBarCode;

private async void ScanBarcodeButton_Clicked(object sender, EventArgs e)
{
    var photo = await MediaPicker.CapturePhotoAsync();
    if (photo == null) return;

    using var stream = await photo.OpenReadAsync();
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    ResultLabel.Text = results.FirstOrDefault()?.Value ?? "No barcode found";
}
Imports IronBarCode

Private Async Sub ScanBarcodeButton_Clicked(sender As Object, e As EventArgs)
    Dim photo = Await MediaPicker.CapturePhotoAsync()
    If photo Is Nothing Then Return

    Using stream = Await photo.OpenReadAsync()
        Using ms As New MemoryStream()
            Await stream.CopyToAsync(ms)

            Dim results = BarcodeReader.Read(ms.ToArray())
            ResultLabel.Text = If(results.FirstOrDefault()?.Value, "No barcode found")
        End Using
    End Using
End Sub
$vbLabelText   $csharpLabel

IronBarcode vs BarcodeScanning.MAUI: Comparación de funciones

Característica BarcodeScanning.MAUI IronBarcode
Lectura de fotogramas de la cámara en directo Sí — Control de CameraView No (utiliza MediaPicker para capturar y luego leer)
visor de la cámara en la aplicación Sí, en tiempo real y continuo. No, utiliza la interfaz de usuario de la cámara del sistema a través de MediaPicker.
Leer desde archivo de imagen No Sí — BarcodeReader.Read(path)
Leer desde una matriz de bytes No Sí — BarcodeReader.Read(bytes)
Leer desde la transmisión No Sí — BarcodeReader.Read(stream)
Leer desde PDF No Sí — BarcodeReader.Read(pdf)
Generación de BarCodes No Sí — BarcodeWriter + QRCodeWriter
Compatibilidad con Windows MAUI No
Compatibilidad con iOS MAUI
Compatibilidad con Android MAUI
Compatibilidad con macOS MAUI No documentado
Servidor / ASP.NET No
Docker / Azure / AWS Lambda No
Precisión del código UPC-A de iOS Devuelve 13 dígitos (error), requiere normalización manual. Devuelve el código UPC-A correcto de 12 dígitos.
Fiabilidad del PDF417 "La mayoría de los escaneos nunca se realizan" (problemas de GitHub ) Se admite
Detección de múltiples códigos de barras Sí (múltiples por cuadro a través de e.BarcodeResults) Sí (ExpectMultipleBarcodes opción)
Control de velocidad de lectura None ReadingSpeed.Faster / Balanced / Detailed / ExtremeDetail
Licencia MIT (código abierto, gratuito) Comercial: Lite $749, Plus $1,499, Professional $2,999, Ilimitado $5,999
Compatibilidad con .NET Framework No (solo MAUI) Sí — .NET Framework 4.6.2+

Inicio rápido: Migración de BarcodeScanning.MAUI a IronBarcode

Paso 1: Sustituir el paquete NuGet

Eliminar BarcodeScanning.Native.Maui:

dotnet remove package BarcodeScanning.Native.Maui
dotnet remove package BarcodeScanning.Native.Maui
SHELL

Instalar IronBarcode:

dotnet add package IronBarcode
dotnet add package IronBarcode
SHELL

Paso 2: Actualizar los espacios de nombres

Elimine el espacio de nombres BarcodeScanning de todos los archivos:

// Remove
using BarcodeScanning;
// Remove
using BarcodeScanning;
Imports BarcodeScanning
$vbLabelText   $csharpLabel

Agregue el espacio de nombres IronBarcode :

// Add
using IronBarCode;
// Add
using IronBarCode;
Imports IronBarCode
$vbLabelText   $csharpLabel

En archivos XAML, elimine la declaración del espacio de nombres XML scanner::


xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui"

xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui"
XML

Paso 3: Inicializar licencia

Agregue la inicialización de la licencia al inicio de la aplicación — en MauiProgram.cs o App.xaml.cs:

IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode

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

Ejemplos de migración de código

Escaneo de cámara: CameraView a MediaPicker

El control CameraView proporcionaba un visor en tiempo real con detección continua de cuadros. El reemplazo de IronBarcode utiliza MediaPicker de MAUI para abrir la cámara del sistema, capturar una foto y procesar la imagen resultante.

Escaneo de códigos de barras. Enfoque MAUI — XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui">
    <StackLayout>
        <scanner:CameraView x:Name="CameraView"
                            OnDetectionFinished="OnBarcodeDetected"
                            CameraEnabled="True"
                            BarcodeFormats="All"
                            VerticalOptions="FillAndExpand" />
        <Label x:Name="ResultLabel" Text="Waiting for scan..." />
    </StackLayout>
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:scanner="clr-namespace:BarcodeScanning;assembly=BarcodeScanning.Native.Maui">
    <StackLayout>
        <scanner:CameraView x:Name="CameraView"
                            OnDetectionFinished="OnBarcodeDetected"
                            CameraEnabled="True"
                            BarcodeFormats="All"
                            VerticalOptions="FillAndExpand" />
        <Label x:Name="ResultLabel" Text="Waiting for scan..." />
    </StackLayout>
</ContentPage>
XML

Enfoque de BarcodeScanning.MAUI — código subyacente:

using BarcodeScanning;

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode != null)
        MainThread.BeginInvokeOnMainThread(() =>
            ResultLabel.Text = barcode.DisplayValue);
}
using BarcodeScanning;

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode != null)
        MainThread.BeginInvokeOnMainThread(() =>
            ResultLabel.Text = barcode.DisplayValue);
}
Imports BarcodeScanning

Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
    Dim barcode = e.BarcodeResults.FirstOrDefault()
    If barcode IsNot Nothing Then
        MainThread.BeginInvokeOnMainThread(Sub()
                                               ResultLabel.Text = barcode.DisplayValue
                                           End Sub)
    End If
End Sub
$vbLabelText   $csharpLabel

Enfoque IronBarcode — XAML:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
    <StackLayout>
        <Button Text="Scan Barcode" Clicked="ScanButton_Clicked" />
        <Label x:Name="ResultLabel" Text="Tap to scan..." />
    </StackLayout>
</ContentPage>
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui">
    <StackLayout>
        <Button Text="Scan Barcode" Clicked="ScanButton_Clicked" />
        <Label x:Name="ResultLabel" Text="Tap to scan..." />
    </StackLayout>
</ContentPage>
XML

Enfoque de IronBarcode : código subyacente:

using IronBarCode;

private async void ScanButton_Clicked(object sender, EventArgs e)
{
    var photo = await MediaPicker.CapturePhotoAsync();
    if (photo == null) return;

    using var stream = await photo.OpenReadAsync();
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    var first = results.FirstOrDefault();
    ResultLabel.Text = first?.Value ?? "No barcode found";
}
using IronBarCode;

private async void ScanButton_Clicked(object sender, EventArgs e)
{
    var photo = await MediaPicker.CapturePhotoAsync();
    if (photo == null) return;

    using var stream = await photo.OpenReadAsync();
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    var first = results.FirstOrDefault();
    ResultLabel.Text = first?.Value ?? "No barcode found";
}
Imports IronBarCode
Imports System.IO
Imports System.Linq

Private Async Sub ScanButton_Clicked(sender As Object, e As EventArgs)
    Dim photo = Await MediaPicker.CapturePhotoAsync()
    If photo Is Nothing Then Return

    Using stream = Await photo.OpenReadAsync()
        Using ms As New MemoryStream()
            Await stream.CopyToAsync(ms)

            Dim results = BarcodeReader.Read(ms.ToArray())
            Dim first = results.FirstOrDefault()
            ResultLabel.Text = If(first?.Value, "No barcode found")
        End Using
    End Using
End Sub
$vbLabelText   $csharpLabel

Este código se ejecuta en iOS, Android y Windows MAUI sin necesidad de bifurcaciones específicas de la plataforma. La experiencia del usuario cambia de un visor integrado en la aplicación a la pantalla de la cámara nativa de la plataforma, lo cual resulta apropiado para la mayoría de las aplicaciones empresariales. La guía de lectura de IronBarcode MAUI cubre opciones de configuración adicionales.

Manejo de múltiples códigos de barras por escaneo

Escaneo de códigos de barras. Enfoque MAUI:

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    foreach (var barcode in e.BarcodeResults)
    {
        MainThread.BeginInvokeOnMainThread(() =>
            Console.WriteLine($"Found: {barcode.DisplayValue}"));
    }
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    foreach (var barcode in e.BarcodeResults)
    {
        MainThread.BeginInvokeOnMainThread(() =>
            Console.WriteLine($"Found: {barcode.DisplayValue}"));
    }
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
    For Each barcode In e.BarcodeResults
        MainThread.BeginInvokeOnMainThread(Sub()
                                               Console.WriteLine($"Found: {barcode.DisplayValue}")
                                           End Sub)
    Next
End Sub
$vbLabelText   $csharpLabel

Enfoque de IronBarcode :

using IronBarCode;

private async void ScanButton_Clicked(object sender, EventArgs e)
{
    var photo = await MediaPicker.CapturePhotoAsync();
    if (photo == null) return;

    using var stream = await photo.OpenReadAsync();
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);

    var options = new BarcodeReaderOptions
    {
        Speed = ReadingSpeed.Balanced,
        ExpectMultipleBarcodes = true
    };

    var results = BarcodeReader.Read(ms.ToArray(), options);
    foreach (var result in results)
        Console.WriteLine($"{result.Format}: {result.Value}");
}
using IronBarCode;

private async void ScanButton_Clicked(object sender, EventArgs e)
{
    var photo = await MediaPicker.CapturePhotoAsync();
    if (photo == null) return;

    using var stream = await photo.OpenReadAsync();
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);

    var options = new BarcodeReaderOptions
    {
        Speed = ReadingSpeed.Balanced,
        ExpectMultipleBarcodes = true
    };

    var results = BarcodeReader.Read(ms.ToArray(), options);
    foreach (var result in results)
        Console.WriteLine($"{result.Format}: {result.Value}");
}
Imports IronBarCode
Imports System.IO

Private Async Sub ScanButton_Clicked(sender As Object, e As EventArgs)
    Dim photo = Await MediaPicker.CapturePhotoAsync()
    If photo Is Nothing Then Return

    Using stream = Await photo.OpenReadAsync()
        Using ms As New MemoryStream()
            Await stream.CopyToAsync(ms)

            Dim options As New BarcodeReaderOptions With {
                .Speed = ReadingSpeed.Balanced,
                .ExpectMultipleBarcodes = True
            }

            Dim results = BarcodeReader.Read(ms.ToArray(), options)
            For Each result In results
                Console.WriteLine($"{result.Format}: {result.Value}")
            Next
        End Using
    End Using
End Sub
$vbLabelText   $csharpLabel

ExpectMultipleBarcodes = true indica al lector que continúe escaneando después de encontrar el primer código de barras. Sin esta opción, la llamada devuelve el resultado en la primera coincidencia, lo que resulta más rápido en escenarios con un solo código de barras.

Solución para iOS UPC-A: Eliminar la solución alternativa de normalización

Si su código fuente utiliza la solución alternativa del cero inicial en el código UPC-A, elimínela por completo. IronBarcode devuelve el valor correcto de 12 dígitos sin ninguna intervención manual.

Enfoque de BarcodeScanning.MAUI: solución alternativa implementada:

private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode == null) return;

    var value = barcode.DisplayValue;

    // Workaround: Apple Vision returns 13 digits for UPC-A
    if (barcode.BarcodeFormat == BarcodeFormats.Upca && value.Length == 13)
        value = value.Substring(1);

    ProcessBarcode(value, barcode.BarcodeFormat.ToString());
}
private void OnBarcodeDetected(object sender, OnDetectionFinishedEventArg e)
{
    var barcode = e.BarcodeResults.FirstOrDefault();
    if (barcode == null) return;

    var value = barcode.DisplayValue;

    // Workaround: Apple Vision returns 13 digits for UPC-A
    if (barcode.BarcodeFormat == BarcodeFormats.Upca && value.Length == 13)
        value = value.Substring(1);

    ProcessBarcode(value, barcode.BarcodeFormat.ToString());
}
Private Sub OnBarcodeDetected(sender As Object, e As OnDetectionFinishedEventArg)
    Dim barcode = e.BarcodeResults.FirstOrDefault()
    If barcode Is Nothing Then Return

    Dim value = barcode.DisplayValue

    ' Workaround: Apple Vision returns 13 digits for UPC-A
    If barcode.BarcodeFormat = BarcodeFormats.Upca AndAlso value.Length = 13 Then
        value = value.Substring(1)
    End If

    ProcessBarcode(value, barcode.BarcodeFormat.ToString())
End Sub
$vbLabelText   $csharpLabel

Enfoque IronBarcode : no se necesita ninguna solución alternativa:

using IronBarCode;

private async void ScanButton_Clicked(object sender, EventArgs e)
{
    var photo = await MediaPicker.CapturePhotoAsync();
    if (photo == null) return;

    using var stream = await photo.OpenReadAsync();
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    var first = results.FirstOrDefault();
    if (first == null) return;

    // result.Value is the correct 12-digit UPC-A — no normalization needed
    ProcessBarcode(first.Value, first.Format.ToString());
}
using IronBarCode;

private async void ScanButton_Clicked(object sender, EventArgs e)
{
    var photo = await MediaPicker.CapturePhotoAsync();
    if (photo == null) return;

    using var stream = await photo.OpenReadAsync();
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    var first = results.FirstOrDefault();
    if (first == null) return;

    // result.Value is the correct 12-digit UPC-A — no normalization needed
    ProcessBarcode(first.Value, first.Format.ToString());
}
Imports IronBarCode
Imports System.IO
Imports System.Linq
Imports System.Threading.Tasks

Private Async Sub ScanButton_Clicked(sender As Object, e As EventArgs)
    Dim photo = Await MediaPicker.CapturePhotoAsync()
    If photo Is Nothing Then Return

    Using stream = Await photo.OpenReadAsync()
        Using ms As New MemoryStream()
            Await stream.CopyToAsync(ms)

            Dim results = BarcodeReader.Read(ms.ToArray())
            Dim first = results.FirstOrDefault()
            If first Is Nothing Then Return

            ' result.Value is the correct 12-digit UPC-A — no normalization needed
            ProcessBarcode(first.Value, first.Format.ToString())
        End Using
    End Using
End Sub
$vbLabelText   $csharpLabel

Elimine cualquier coincidencia de BarcodeFormats.Upca emparejado con Substring(1) — ese código está inactivo después de la migración.

Agregar compatibilidad con archivos y PDF

BarcodeScanning.Native.Maui no tiene un equivalente para la entrada de archivos o PDF. Si se trata de un nuevo requisito que se cumple en el momento de la migración:

Escaneo de códigos de barras. Enfoque MAUI:

// No equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
// No equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
' No equivalent exists — BarcodeScanning.Native.Maui cannot read from files or PDFs
$vbLabelText   $csharpLabel

Enfoque de IronBarcode :

using IronBarCode;

// Read from a file the user picked with FilePicker
private async void ReadFileButton_Clicked(object sender, EventArgs e)
{
    var file = await FilePicker.PickAsync(new PickOptions
    {
        PickerTitle = "Select image or PDF"
    });
    if (file == null) return;

    var results = BarcodeReader.Read(file.FullPath);
    foreach (var result in results)
        ResultLabel.Text += $"\n{result.Format}: {result.Value}";
}

// Read barcodes from a PDF directly — no intermediate image step
private void ReadPdfBarcodes()
{
    var results = BarcodeReader.Read("shipment-manifest.pdf");
    foreach (var result in results)
        Console.WriteLine($"{result.Format}: {result.Value}");
}
using IronBarCode;

// Read from a file the user picked with FilePicker
private async void ReadFileButton_Clicked(object sender, EventArgs e)
{
    var file = await FilePicker.PickAsync(new PickOptions
    {
        PickerTitle = "Select image or PDF"
    });
    if (file == null) return;

    var results = BarcodeReader.Read(file.FullPath);
    foreach (var result in results)
        ResultLabel.Text += $"\n{result.Format}: {result.Value}";
}

// Read barcodes from a PDF directly — no intermediate image step
private void ReadPdfBarcodes()
{
    var results = BarcodeReader.Read("shipment-manifest.pdf");
    foreach (var result in results)
        Console.WriteLine($"{result.Format}: {result.Value}");
}
Imports IronBarCode

' Read from a file the user picked with FilePicker
Private Async Sub ReadFileButton_Clicked(sender As Object, e As EventArgs)
    Dim file = Await FilePicker.PickAsync(New PickOptions With {
        .PickerTitle = "Select image or PDF"
    })
    If file Is Nothing Then Return

    Dim results = BarcodeReader.Read(file.FullPath)
    For Each result In results
        ResultLabel.Text &= vbCrLf & $"{result.Format}: {result.Value}"
    Next
End Sub

' Read barcodes from a PDF directly — no intermediate image step
Private Sub ReadPdfBarcodes()
    Dim results = BarcodeReader.Read("shipment-manifest.pdf")
    For Each result In results
        Console.WriteLine($"{result.Format}: {result.Value}")
    Next
End Sub
$vbLabelText   $csharpLabel

La documentación de IronBarcode sobre la lectura de archivos PDF abarca la compatibilidad con archivos PDF de varias páginas y la selección de rangos de páginas.

Procesamiento de códigos de barras del lado del servidor

Si su aplicación tiene una API ASP.NET de backend que también necesita procesamiento de códigos de barras, la misma llamada BarcodeReader.Read() se ejecuta allí sin modificaciones. BarcodeScanning.Native.Maui no tiene un equivalente del lado del servidor.

Escaneo de códigos de barras. Enfoque MAUI:

// No equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
// and cannot run in a server process
// No equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
// and cannot run in a server process
' No equivalent exists — BarcodeScanning.Native.Maui is a camera UI control
' and cannot run in a server process
$vbLabelText   $csharpLabel

Enfoque de IronBarcode :

using IronBarCode;

// ASP.NET endpoint — reads barcodes from an uploaded file
[HttpPost("scan")]
public async Task<IActionResult> ScanBarcode(IFormFile file)
{
    using var ms = new MemoryStream();
    await file.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    var values = results.Select(r => new { r.Value, Format = r.Format.ToString() });
    return Ok(values);
}
using IronBarCode;

// ASP.NET endpoint — reads barcodes from an uploaded file
[HttpPost("scan")]
public async Task<IActionResult> ScanBarcode(IFormFile file)
{
    using var ms = new MemoryStream();
    await file.CopyToAsync(ms);

    var results = BarcodeReader.Read(ms.ToArray());
    var values = results.Select(r => new { r.Value, Format = r.Format.ToString() });
    return Ok(values);
}
Imports IronBarCode
Imports Microsoft.AspNetCore.Mvc
Imports System.IO
Imports System.Threading.Tasks

' ASP.NET endpoint — reads barcodes from an uploaded file
<HttpPost("scan")>
Public Async Function ScanBarcode(file As IFormFile) As Task(Of IActionResult)
    Using ms As New MemoryStream()
        Await file.CopyToAsync(ms)

        Dim results = BarcodeReader.Read(ms.ToArray())
        Dim values = results.Select(Function(r) New With {Key .Value = r.Value, Key .Format = r.Format.ToString()})
        Return Ok(values)
    End Using
End Function
$vbLabelText   $csharpLabel

El mismo paquete, la misma API, el mismo comportamiento, tanto en dispositivos móviles como en servidores.

Generación de códigos de barras

BarcodeScanning.Native.Maui no tiene API de generación. IronBarcode genera múltiples formatos.

Escaneo de códigos de barras. Enfoque MAUI:

// No equivalent exists — BarcodeScanning.Native.Maui cannot generate barcodes
// No equivalent exists — BarcodeScanning.Native.Maui cannot generate barcodes
' No equivalent exists — BarcodeScanning.Native.Maui cannot generate barcodes
$vbLabelText   $csharpLabel

Enfoque de IronBarcode :

using IronBarCode;

// QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500)
    .SaveAsPng("qr.png");

// Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
    .ResizeTo(400, 100)
    .SaveAsPng("label.png");

// Get bytes for returning from an API or storing in a database
byte[] barcodeBytes = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
    .ToPngBinaryData();
using IronBarCode;

// QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500)
    .SaveAsPng("qr.png");

// Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
    .ResizeTo(400, 100)
    .SaveAsPng("label.png");

// Get bytes for returning from an API or storing in a database
byte[] barcodeBytes = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128)
    .ToPngBinaryData();
Imports IronBarCode

' QR code
QRCodeWriter.CreateQrCode("https://example.com/product/12345", 500) _
    .SaveAsPng("qr.png")

' Code128 barcode sized to specific dimensions
BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128) _
    .ResizeTo(400, 100) _
    .SaveAsPng("label.png")

' Get bytes for returning from an API or storing in a database
Dim barcodeBytes As Byte() = BarcodeWriter.CreateBarcode("ITEM-98765", BarcodeEncoding.Code128) _
    .ToPngBinaryData()
$vbLabelText   $csharpLabel

La documentación de generación de IronBarcode abarca todos los formatos compatibles y las opciones de estilo.

Referencia de mapeo de la API de BarcodeScanning.MAUI a IronBarcode

BarcodeScanning.Native.Maui IronBarcode
CameraView control de XAML Eliminar — use Button + MediaPicker.CapturePhotoAsync()
Evento de OnDetectionFinished Valor de retorno de BarcodeReader.Read(imageBytes)
OnDetectionFinishedEventArg e Resultado IEnumerable de BarcodeReader.Read()
e.BarcodeResults Valor de retorno de BarcodeReader.Read()
e.BarcodeResults.FirstOrDefault() results.FirstOrDefault()
barcode.DisplayValue result.Value
barcode.BarcodeFormat result.Format
BarcodeFormats="All" Detección automática: no requiere configuración.
CameraEnabled="True" await MediaPicker.CapturePhotoAsync()
Solo iOS y Android iOS, Android, Windows, macOS MAUI
No se permite la entrada de archivos. BarcodeReader.Read(filePath)
No se permite la entrada de archivos PDF. BarcodeReader.Read("document.pdf")
Ninguna generación BarcodeWriter.CreateBarcode() / QRCodeWriter.CreateQrCode()
El código UPC-A de iOS devuelve 13 dígitos. Devuelve los 12 dígitos correctos; no se necesita normalización.
PDF417 poco fiable Se admite

Problemas comunes de migración y soluciones

Problema 1: Se pierde la experiencia del visor en directo

BarcodeScanning.MAUI: El control CameraView integraba una vista previa de cámara en tiempo real directamente en la página MAUI. Los usuarios podían ver la imagen de la cámara y apuntar a un código de barras; la detección se producía automáticamente sin necesidad de pulsar ningún botón.

Solución: MediaPicker.CapturePhotoAsync() muestra en su lugar la pantalla de la cámara de la plataforma. Para la mayoría de los flujos de trabajo empresariales, esto es aceptable. Para aplicaciones de consumo que requieren una vista previa en vivo continua, los cuadros de la cámara pueden pasarse directamente a BarcodeReader.Read():

using IronBarCode;

// Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
// (frame capture depends on your MAUI camera frame source)
private void ProcessCameraFrame(byte[] frameBytes)
{
    var results = BarcodeReader.Read(frameBytes);
    if (results.Any())
    {
        var first = results.First();
        MainThread.BeginInvokeOnMainThread(() =>
            ResultLabel.Text = first.Value);
    }
}
using IronBarCode;

// Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
// (frame capture depends on your MAUI camera frame source)
private void ProcessCameraFrame(byte[] frameBytes)
{
    var results = BarcodeReader.Read(frameBytes);
    if (results.Any())
    {
        var first = results.First();
        MainThread.BeginInvokeOnMainThread(() =>
            ResultLabel.Text = first.Value);
    }
}
Imports IronBarCode

' Continuous scanning: pass camera frame bytes to BarcodeReader.Read()
' (frame capture depends on your MAUI camera frame source)
Private Sub ProcessCameraFrame(frameBytes As Byte())
    Dim results = BarcodeReader.Read(frameBytes)
    If results.Any() Then
        Dim first = results.First()
        MainThread.BeginInvokeOnMainThread(Sub()
                                               ResultLabel.Text = first.Value
                                           End Sub)
    End If
End Sub
$vbLabelText   $csharpLabel

Esto requiere conectar una fuente de fotogramas de la cámara por separado de IronBarcode. Antes de optar por esta opción, evalúe si realmente se necesita una vista previa en tiempo real o si la interfaz de usuario de la cámara del sistema es suficiente.

Problema 2: Cambios en el nombre de la propiedad y la enumeración de e.BarcodeResults

BarcodeScanning.MAUI: barcode.DisplayValue devuelve la cadena decodificada; barcode.BarcodeFormat devuelve un valor de enumeración de la biblioteca BarcodeScanning.

Solución: Reemplace DisplayValue por result.Value y barcode.BarcodeFormat por result.Format. El patrón de iteración es el mismo:

// Before
foreach (var barcode in e.BarcodeResults)
    Console.WriteLine(barcode.DisplayValue);

// After
var results = BarcodeReader.Read(imageBytes);
foreach (var result in results)
    Console.WriteLine(result.Value);
// Before
foreach (var barcode in e.BarcodeResults)
    Console.WriteLine(barcode.DisplayValue);

// After
var results = BarcodeReader.Read(imageBytes);
foreach (var result in results)
    Console.WriteLine(result.Value);
' Before
For Each barcode In e.BarcodeResults
    Console.WriteLine(barcode.DisplayValue)
Next

' After
Dim results = BarcodeReader.Read(imageBytes)
For Each result In results
    Console.WriteLine(result.Value)
Next
$vbLabelText   $csharpLabel

Problema 3: Gestión de subprocesos para actualizaciones de la interfaz de usuario

BarcodeScanning.MAUI: OnDetectionFinished se dispara en un hilo de fondo, por lo que todas las actualizaciones de UI requieren MainThread.BeginInvokeOnMainThread().

Solución: Con el patrón MediaPicker + async, la continuación después de await regresa en el contexto de llamada — típicamente el hilo principal. Los envoltorios MainThread.BeginInvokeOnMainThread() alrededor de la visualización del resultado pueden eliminarse generalmente, simplificando el código del manejador.

Problema 4: Permisos de la cámara de MAUI

BarcodeScanning.MAUI: El paquete añade permisos de cámara a AndroidManifest.xml y Info.plist automáticamente como parte de su configuración.

Solución: Con IronBarcode utilizando MediaPicker, los permisos estándar de cámara MAUI deben estar presentes manualmente. Estos son los mismos permisos que necesita cualquier aplicación MAUI para MediaPicker.CapturePhotoAsync() y típicamente ya están en su lugar. Verifique que android.permission.CAMERA esté declarado en AndroidManifest.xml y NSCameraUsageDescription esté configurado en Info.plist antes de probar en el dispositivo.

Lista de verificación de migración de MAUI para escaneo de códigos de barras

Tareas previas a la migración

Ejecute estas búsquedas para encontrar todos los usos de BarcodeScanning.Native.Maui antes de realizar cualquier cambio:

grep -rn "using BarcodeScanning" --include="*.cs" .
grep -rn "using BarcodeScanning" --include="*.xaml" .
grep -rn "CameraView" --include="*.cs" .
grep -rn "CameraView" --include="*.xaml" .
grep -rn "OnDetectionFinished" --include="*.cs" .
grep -rn "OnDetectionFinishedEventArg" --include="*.cs" .
grep -rn "e\.BarcodeResults" --include="*.cs" .
grep -rn "DisplayValue" --include="*.cs" .
grep -rn "BarcodeFormats\.Upca" --include="*.cs" .
grep -rn "scanner:" --include="*.xaml" .
grep -rn "using BarcodeScanning" --include="*.cs" .
grep -rn "using BarcodeScanning" --include="*.xaml" .
grep -rn "CameraView" --include="*.cs" .
grep -rn "CameraView" --include="*.xaml" .
grep -rn "OnDetectionFinished" --include="*.cs" .
grep -rn "OnDetectionFinishedEventArg" --include="*.cs" .
grep -rn "e\.BarcodeResults" --include="*.cs" .
grep -rn "DisplayValue" --include="*.cs" .
grep -rn "BarcodeFormats\.Upca" --include="*.cs" .
grep -rn "scanner:" --include="*.xaml" .
SHELL

Documenta cada golpe. Tenga en cuenta qué archivos contienen el uso de XAML CameraView (requieren cambios en XAML) frente a los que solo contienen cambios de código-behind. Identifique cualquier solución alternativa de normalización UPC-A que deba eliminarse después de la migración.

Tareas de actualización de código

  1. Eliminar el paquete NuGet BarcodeScanning.Native.Maui
  2. Instalar el paquete NuGet IronBarcode
  3. Agregar IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"; en MauiProgram.cs o App.xaml.cs
  4. Reemplace using BarcodeScanning; por using IronBarCode; en todos los archivos .cs
  5. Elimine las declaraciones de espacio de nombres xmlns:scanner="..." de todos los archivos XAML
  6. Reemplace los controles scanner:CameraView en XAML con un Button que dispare MediaPicker.CapturePhotoAsync()
  7. Elimine el cableado de eventos OnDetectionFinished="..." de XAML
  8. Reemplace los manejadores de eventos OnDetectionFinished con manejadores de clic de botón async usando BarcodeReader.Read()
  9. Reemplace barcode.DisplayValue por result.Value en todo el documento
  10. Reemplace barcode.BarcodeFormat por result.Format en todo el documento
  11. Elimine todos los atajos de normalización BarcodeFormats.Upca + Substring(1)
  12. Agregue ExpectMultipleBarcodes = true a BarcodeReaderOptions donde la detección de múltiples códigos de barras previamente dependía de e.BarcodeResults devolviendo múltiples ítems
  13. Quite los envoltorios MainThread.BeginInvokeOnMainThread() del código de visualización de resultados donde el patrón asincrónico los hace innecesarios
  14. Verifique que los permisos de cámara AndroidManifest.xml y Info.plist estén presentes

Pruebas posteriores a la migración

  • Verificar que el escaneo de códigos de barras de iOS funcione y que los valores UPC-A se devuelvan como cadenas de 12 dígitos sin ceros iniciales.
  • Verificar que el escaneo de códigos de barras de Android produzca valores correctos para todos los formatos utilizados en la aplicación.
  • Verifica que el escaneo de códigos de barras de Windows MAUI funcione si Windows es un destino de compilación.
  • Pruebe el escaneo PDF417 comparándolo con etiquetas de envío reales, licencias de conducir o tarjetas de embarque, si se utilizan.
  • Pruebe escenarios de múltiples códigos de barras con ExpectMultipleBarcodes = true y confirme que todos los códigos de barras en una imagen sean devueltos
  • Verifique que el escaneo del selector de archivos (BarcodeReader.Read(filePath)) funcione en todos los objetivos MAUI
  • Verifique la lectura del código de barras PDF si esta fue una nueva funcionalidad agregada junto con la migración.
  • Confirme que BarcodeReader.Read() del lado del servidor produce resultados correctos si se agregó un componente backend
  • Ejecute las pruebas automatizadas existentes y compare los resultados de los códigos de barras con las líneas base previas a la migración.

Principales ventajas de migrar a IronBarcode

Compatibilidad total con MAUI para Windows: IronBarcode funciona en los cuatro sistemas operativos MAUI (iOS, Android, Windows y macOS) utilizando el mismo código y el mismo paquete. No se necesita una implementación de código de barras específica para la plataforma en Windows, y no se requieren bloques #if WINDOWS en el código de la aplicación.

Cualquier Fuente de Entrada: BarcodeReader.Read() acepta rutas de archivos, arreglos de bytes, flujos y documentos PDF. Cualquier escenario relacionado con códigos de barras (captura de cámara, carga de archivos, imagen de galería, procesamiento de PDF en el servidor) utiliza el mismo método estático con el mismo tipo de resultado.

Valores UPC-A correctos: IronBarcode devuelve el valor UPC-A correcto de 12 dígitos en iOS sin necesidad de ningún código de normalización en la aplicación. Los datos históricos UPC-A almacenados con un cero inicial debido al comportamiento de BarcodeScanning.Native.Maui no afectan la precisión de los valores leídos después de la migración.

PDF417 fiable: PDF417 es totalmente compatible y se lee de forma fiable. Las etiquetas de envío, los permisos de conducir y las tarjetas de embarque se escanean sin la limitación de que "la mayoría de los escaneos nunca ocurren", documentada en los problemas de GitHub de BarcodeScanning.Native.Maui.

Generación de Códigos de Barras: BarcodeWriter.CreateBarcode() y QRCodeWriter.CreateQrCode() generan Code128, QR, DataMatrix y otros formatos como archivos PNG o arreglos de bytes. La generación y la lectura están disponibles desde el mismo paquete sin dependencias adicionales.

Despliegue en el Servidor: La misma llamada BarcodeReader.Read() se ejecuta en ASP.NET, Funciones Azure, contenedores Docker, y AWS Lambda. La lógica de códigos de barras para dispositivos móviles y servidores puede compartir la misma API, la misma compatibilidad de formatos y el mismo tipo de resultado sin necesidad de mantener dos implementaciones de códigos de barras separadas.

Preguntas Frecuentes

¿Por qué debería migrar de BarcodeScanning.MAUI 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 BarcodeScanning.MAUI 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 código cambia al migrar de BarcodeScanning.MAUI 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 mantener BarcodeScanning.MAUI e IronBarcode instalados 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 BarcodeScanning.MAUI?

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 BarcodeScanning.MAUI?

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 resultados cambian al migrar de BarcodeScanning.MAUI 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