Escáner de código de barras USB en C#: Cree una aplicación de escaneo completa
Los lectores de códigos de barras USB se conectan a aplicaciones C# como dispositivos de entrada de teclado estándar y envían datos escaneados como caracteres escritos seguidos de una pulsación de tecla Intro. Este comportamiento de cuña de teclado HID hace que la integración sea sencilla: su aplicación recibe entrada de texto sin necesidad de ningún controlador o SDK especial. IronBarcode procesa esa entrada sin procesar para validar formatos, extraer datos estructurados y generar códigos de barras de respuesta, convirtiendo un simple evento de escaneo en una tubería de datos completa para la gestión de inventario, puntos de venta minoristas y sistemas de seguimiento logístico.
Las operaciones de venta minorista, almacenamiento y fabricación dependen de un escaneo rápido y preciso de códigos de barras. Cuando un desarrollador conecta un escáner USB a una aplicación de Windows Forms o WPF, el escáner se comporta de manera idéntica a un teclado: los datos llegan a un cuadro de texto y al presionar Enter se indica que se ha recibido un código de barras completo. El desafío no es capturar los datos; Lo está procesando correctamente. La validación de código de barras de IronBarcode verifica la integridad del formato, extrae campos como números de lote o identificadores de aplicaciones GS1 y puede generar inmediatamente un nuevo código de barras en respuesta.
Esta guía explica paso a paso la creación de una aplicación de escáner de códigos de barras USB en C# lista para producción. Instalará la biblioteca, capturará la entrada del escáner, validará los formatos de los códigos de barras, generará etiquetas de respuesta y ensamblará un procesador de colas de alto volumen. Cada sección incluye código completo y ejecutable orientado a .NET 10 con estilo de declaración de nivel superior cuando corresponda.
¿Cómo funcionan los escáneres de códigos de barras USB con C#?
¿Por qué el modo de cuña de teclado HID simplifica la integración?
La mayoría de los escáneres de códigos de barras USB se envían configurados en modo de cuña de teclado HID de manera predeterminada. Cuando lo conectas a una máquina Windows, el sistema operativo lo registra como un dispositivo de almacenamiento USB (para configuración) y como un teclado (para entrada de datos). Cuando se escanea un código de barras, el dispositivo traduce el valor del código de barras decodificado en pulsaciones de teclas y las envía a la ventana de la aplicación que tenga el foco, agregando un retorno de carro al final.
Desde la perspectiva de un desarrollador de C#, esto significa que no se necesitan SDK de proveedores, bibliotecas COM ni API USB especiales. Un TextBox estándar con un controlador KeyDown es todo lo que se necesita para capturar la entrada. El principal desafío de integración es distinguir la entrada del escáner de la escritura genuina en el teclado. Los escáneres generalmente entregan todos los caracteres en un lapso muy corto (a menudo menos de 50 milisegundos), mientras que la escritura humana distribuye las pulsaciones de teclas a lo largo de cientos de milisegundos. Medir el tiempo de la ráfaga es una forma confiable de filtrar pulsaciones de teclas accidentales.
Los escáneres de nivel profesional también admiten modos seriales (RS-232 o puerto COM virtual) y USB HID directo, que le brindan más control sobre los caracteres de prefijo/sufijo y los activadores de escaneo. El patrón de interfaz a continuación maneja ambos casos:
public interface IScannerInput
{
event EventHandler<string> BarcodeScanned;
void StartListening();
void StopListening();
}
public class KeyboardWedgeScanner : IScannerInput
{
public event EventHandler<string> BarcodeScanned;
private readonly TextBox _inputBox;
private readonly System.Windows.Forms.Timer _burstTimer;
private readonly System.Text.StringBuilder _buffer = new();
public KeyboardWedgeScanner(TextBox inputBox)
{
_inputBox = inputBox;
_burstTimer = new System.Windows.Forms.Timer { Interval = 80 };
_burstTimer.Tick += OnBurstTimeout;
_inputBox.KeyPress += OnKeyPress;
}
private void OnKeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
_burstTimer.Stop();
string value = _buffer.ToString().Trim();
_buffer.Clear();
if (value.Length > 0)
BarcodeScanned?.Invoke(this, value);
}
else
{
_buffer.Append(e.KeyChar);
_burstTimer.Stop();
_burstTimer.Start();
}
e.Handled = true;
}
private void OnBurstTimeout(object sender, EventArgs e)
{
_burstTimer.Stop();
_buffer.Clear(); // incomplete burst -- discard
}
public void StartListening() => _inputBox.Focus();
public void StopListening() => _inputBox.Enabled = false;
}
public class SerialPortScanner : IScannerInput
{
public event EventHandler<string> BarcodeScanned;
private readonly System.IO.Ports.SerialPort _port;
public SerialPortScanner(string portName, int baudRate = 9600)
{
_port = new System.IO.Ports.SerialPort(portName, baudRate);
_port.DataReceived += OnDataReceived;
}
private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string data = _port.ReadLine().Trim();
if (data.Length > 0)
BarcodeScanned?.Invoke(this, data);
}
public void StartListening() => _port.Open();
public void StopListening() => _port.Close();
}
public interface IScannerInput
{
event EventHandler<string> BarcodeScanned;
void StartListening();
void StopListening();
}
public class KeyboardWedgeScanner : IScannerInput
{
public event EventHandler<string> BarcodeScanned;
private readonly TextBox _inputBox;
private readonly System.Windows.Forms.Timer _burstTimer;
private readonly System.Text.StringBuilder _buffer = new();
public KeyboardWedgeScanner(TextBox inputBox)
{
_inputBox = inputBox;
_burstTimer = new System.Windows.Forms.Timer { Interval = 80 };
_burstTimer.Tick += OnBurstTimeout;
_inputBox.KeyPress += OnKeyPress;
}
private void OnKeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
_burstTimer.Stop();
string value = _buffer.ToString().Trim();
_buffer.Clear();
if (value.Length > 0)
BarcodeScanned?.Invoke(this, value);
}
else
{
_buffer.Append(e.KeyChar);
_burstTimer.Stop();
_burstTimer.Start();
}
e.Handled = true;
}
private void OnBurstTimeout(object sender, EventArgs e)
{
_burstTimer.Stop();
_buffer.Clear(); // incomplete burst -- discard
}
public void StartListening() => _inputBox.Focus();
public void StopListening() => _inputBox.Enabled = false;
}
public class SerialPortScanner : IScannerInput
{
public event EventHandler<string> BarcodeScanned;
private readonly System.IO.Ports.SerialPort _port;
public SerialPortScanner(string portName, int baudRate = 9600)
{
_port = new System.IO.Ports.SerialPort(portName, baudRate);
_port.DataReceived += OnDataReceived;
}
private void OnDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string data = _port.ReadLine().Trim();
if (data.Length > 0)
BarcodeScanned?.Invoke(this, data);
}
public void StartListening() => _port.Open();
public void StopListening() => _port.Close();
}
Imports System
Imports System.Text
Imports System.Windows.Forms
Imports System.IO.Ports
Public Interface IScannerInput
Event BarcodeScanned As EventHandler(Of String)
Sub StartListening()
Sub StopListening()
End Interface
Public Class KeyboardWedgeScanner
Implements IScannerInput
Public Event BarcodeScanned As EventHandler(Of String) Implements IScannerInput.BarcodeScanned
Private ReadOnly _inputBox As TextBox
Private ReadOnly _burstTimer As Timer
Private ReadOnly _buffer As New StringBuilder()
Public Sub New(inputBox As TextBox)
_inputBox = inputBox
_burstTimer = New Timer With {.Interval = 80}
AddHandler _burstTimer.Tick, AddressOf OnBurstTimeout
AddHandler _inputBox.KeyPress, AddressOf OnKeyPress
End Sub
Private Sub OnKeyPress(sender As Object, e As KeyPressEventArgs)
If e.KeyChar = ChrW(Keys.Enter) Then
_burstTimer.Stop()
Dim value As String = _buffer.ToString().Trim()
_buffer.Clear()
If value.Length > 0 Then
RaiseEvent BarcodeScanned(Me, value)
End If
Else
_buffer.Append(e.KeyChar)
_burstTimer.Stop()
_burstTimer.Start()
End If
e.Handled = True
End Sub
Private Sub OnBurstTimeout(sender As Object, e As EventArgs)
_burstTimer.Stop()
_buffer.Clear() ' incomplete burst -- discard
End Sub
Public Sub StartListening() Implements IScannerInput.StartListening
_inputBox.Focus()
End Sub
Public Sub StopListening() Implements IScannerInput.StopListening
_inputBox.Enabled = False
End Sub
End Class
Public Class SerialPortScanner
Implements IScannerInput
Public Event BarcodeScanned As EventHandler(Of String) Implements IScannerInput.BarcodeScanned
Private ReadOnly _port As SerialPort
Public Sub New(portName As String, Optional baudRate As Integer = 9600)
_port = New SerialPort(portName, baudRate)
AddHandler _port.DataReceived, AddressOf OnDataReceived
End Sub
Private Sub OnDataReceived(sender As Object, e As SerialDataReceivedEventArgs)
Dim data As String = _port.ReadLine().Trim()
If data.Length > 0 Then
RaiseEvent BarcodeScanned(Me, data)
End If
End Sub
Public Sub StartListening() Implements IScannerInput.StartListening
_port.Open()
End Sub
Public Sub StopListening() Implements IScannerInput.StopListening
_port.Close()
End Sub
End Class
El temporizador de ráfaga en la implementación del teclado en cuña es el detalle clave. Se reinicia con cada pulsación de tecla y solo se activa si dejan de llegar caracteres, lo que significa que los usuarios de teclado genuinos que escriben lentamente verán su entrada incompleta descartada en lugar de ser tratada como un escaneo de código de barras.
¿Cómo gestionar múltiples marcas de escáneres?
Los entornos empresariales con frecuencia utilizan una combinación de escáneres Honeywell, Zebra (anteriormente Symbol/Motorola) y Datalogic en el mismo piso. Cada proveedor tiene sus propios caracteres de terminación predeterminados, velocidades en baudios y convenciones de prefijo/sufijo. Un modelo de configuración mantiene su aplicación flexible:
public class ScannerConfiguration
{
public string ScannerType { get; set; } = "KeyboardWedge";
public string PortName { get; set; } = "COM3";
public int BaudRate { get; set; } = 9600;
public string Terminator { get; set; } = "\r\n";
public bool EnableBeep { get; set; } = true;
public Dictionary<string, string> BrandSettings { get; set; } = new();
public static ScannerConfiguration GetHoneywellConfig() => new()
{
ScannerType = "Serial",
BaudRate = 115200,
BrandSettings = new Dictionary<string, string>
{
{ "Prefix", "STX" },
{ "Suffix", "ETX" },
{ "TriggerMode", "Manual" }
}
};
public static ScannerConfiguration GetZebraConfig() => new()
{
ScannerType = "KeyboardWedge",
BrandSettings = new Dictionary<string, string>
{
{ "ScanMode", "Continuous" },
{ "BeepVolume", "High" }
}
};
}
public class ScannerConfiguration
{
public string ScannerType { get; set; } = "KeyboardWedge";
public string PortName { get; set; } = "COM3";
public int BaudRate { get; set; } = 9600;
public string Terminator { get; set; } = "\r\n";
public bool EnableBeep { get; set; } = true;
public Dictionary<string, string> BrandSettings { get; set; } = new();
public static ScannerConfiguration GetHoneywellConfig() => new()
{
ScannerType = "Serial",
BaudRate = 115200,
BrandSettings = new Dictionary<string, string>
{
{ "Prefix", "STX" },
{ "Suffix", "ETX" },
{ "TriggerMode", "Manual" }
}
};
public static ScannerConfiguration GetZebraConfig() => new()
{
ScannerType = "KeyboardWedge",
BrandSettings = new Dictionary<string, string>
{
{ "ScanMode", "Continuous" },
{ "BeepVolume", "High" }
}
};
}
Option Strict On
Public Class ScannerConfiguration
Public Property ScannerType As String = "KeyboardWedge"
Public Property PortName As String = "COM3"
Public Property BaudRate As Integer = 9600
Public Property Terminator As String = vbCrLf
Public Property EnableBeep As Boolean = True
Public Property BrandSettings As Dictionary(Of String, String) = New Dictionary(Of String, String)()
Public Shared Function GetHoneywellConfig() As ScannerConfiguration
Return New ScannerConfiguration() With {
.ScannerType = "Serial",
.BaudRate = 115200,
.BrandSettings = New Dictionary(Of String, String) From {
{"Prefix", "STX"},
{"Suffix", "ETX"},
{"TriggerMode", "Manual"}
}
}
End Function
Public Shared Function GetZebraConfig() As ScannerConfiguration
Return New ScannerConfiguration() With {
.ScannerType = "KeyboardWedge",
.BrandSettings = New Dictionary(Of String, String) From {
{"ScanMode", "Continuous"},
{"BeepVolume", "High"}
}
}
End Function
End Class
Almacenar estas configuraciones en un archivo de configuración o una base de datos significa que el personal del almacén puede cambiar los modelos de escáner sin necesidad de una redistribución. El campo ScannerType determina qué implementación de IScannerInput se instancia al inicio.
¿Cómo instalar IronBarcode en un proyecto C#?
¿Cuál es la forma más rápida de agregar IronBarcode a través de NuGet?
Abra la consola del gestor de paquetes en Visual Studio y ejecute:
Install-Package IronBarCode
Install-Package IronBarCode
Alternativamente, utilice la CLI de .NET :
dotnet add package IronBarCode
dotnet add package IronBarCode
Ambos comandos extraen la versión actual de NuGet y añaden la referencia del ensamblado al archivo de proyecto. La biblioteca está diseñada for .NET Standard 2.0, por lo que funciona en .NET Framework 4.6.2 a .NET 10 sin necesidad de correcciones de compatibilidad adicionales.
Después de la instalación, configure su clave de licencia antes de llamar a cualquier método IronBarcode . Para desarrollo y evaluación, hay una clave de prueba gratuita disponible en la página de licencias de IronBarcode :
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
Para implementaciones en contenedores, IronBarcode funciona con Docker en Linux y, para funciones en la nube, es compatible con AWS Lambda y Azure Functions .
¿Cómo validar códigos de barras escaneados con IronBarcode?
¿Cuál es el enfoque correcto para la verificación de formato?
IronBarcode admite más de 30 simbologías de códigos de barras, incluidos Code 128 , EAN-13 , Code 39 , códigos QR y Data Matrix . Para las aplicaciones de escáner USB, el patrón de validación vuelve a codificar la cadena escaneada como una imagen de código de barras y la lee inmediatamente a través del decodificador. Este viaje de ida y vuelta confirma que la cadena es un valor válido para el formato declarado:
public class BarcodeValidator
{
public async Task<ValidationResult> ValidateAsync(string scannedText, BarcodeEncoding preferredFormat = BarcodeEncoding.Code128)
{
var result = new ValidationResult { RawInput = scannedText };
try
{
var barcode = BarcodeWriter.CreateBarcode(scannedText, preferredFormat);
var readResults = await BarcodeReader.ReadAsync(barcode.ToBitmap());
if (readResults.Any())
{
var first = readResults.First();
result.IsValid = true;
result.Format = first.BarcodeType;
result.Value = first.Value;
result.Confidence = first.Confidence;
}
else
{
result.IsValid = false;
result.Error = "No barcode could be decoded from the scanned input.";
}
}
catch (Exception ex)
{
result.IsValid = false;
result.Error = ex.Message;
}
return result;
}
}
public record ValidationResult
{
public string RawInput { get; init; } = "";
public bool IsValid { get; set; }
public BarcodeEncoding Format { get; set; }
public string Value { get; set; } = "";
public float Confidence { get; set; }
public string Error { get; set; } = "";
}
public class BarcodeValidator
{
public async Task<ValidationResult> ValidateAsync(string scannedText, BarcodeEncoding preferredFormat = BarcodeEncoding.Code128)
{
var result = new ValidationResult { RawInput = scannedText };
try
{
var barcode = BarcodeWriter.CreateBarcode(scannedText, preferredFormat);
var readResults = await BarcodeReader.ReadAsync(barcode.ToBitmap());
if (readResults.Any())
{
var first = readResults.First();
result.IsValid = true;
result.Format = first.BarcodeType;
result.Value = first.Value;
result.Confidence = first.Confidence;
}
else
{
result.IsValid = false;
result.Error = "No barcode could be decoded from the scanned input.";
}
}
catch (Exception ex)
{
result.IsValid = false;
result.Error = ex.Message;
}
return result;
}
}
public record ValidationResult
{
public string RawInput { get; init; } = "";
public bool IsValid { get; set; }
public BarcodeEncoding Format { get; set; }
public string Value { get; set; } = "";
public float Confidence { get; set; }
public string Error { get; set; } = "";
}
Imports System
Imports System.Linq
Imports System.Threading.Tasks
Public Class BarcodeValidator
Public Async Function ValidateAsync(scannedText As String, Optional preferredFormat As BarcodeEncoding = BarcodeEncoding.Code128) As Task(Of ValidationResult)
Dim result As New ValidationResult With {.RawInput = scannedText}
Try
Dim barcode = BarcodeWriter.CreateBarcode(scannedText, preferredFormat)
Dim readResults = Await BarcodeReader.ReadAsync(barcode.ToBitmap())
If readResults.Any() Then
Dim first = readResults.First()
result.IsValid = True
result.Format = first.BarcodeType
result.Value = first.Value
result.Confidence = first.Confidence
Else
result.IsValid = False
result.Error = "No barcode could be decoded from the scanned input."
End If
Catch ex As Exception
result.IsValid = False
result.Error = ex.Message
End Try
Return result
End Function
End Class
Public Class ValidationResult
Public Property RawInput As String = ""
Public Property IsValid As Boolean
Public Property Format As BarcodeEncoding
Public Property Value As String = ""
Public Property Confidence As Single
Public Property Error As String = ""
End Class
Para los códigos de barras GS1-128 utilizados en aplicaciones de la cadena de suministro, la cadena escaneada incluye prefijos de identificador de aplicación entre paréntesis, como (01) para GTIN y (17) para fecha de vencimiento. IronBarcode analiza estos identificadores de aplicación automáticamente cuando usted especifica BarcodeEncoding.GS1_128.
¿Qué lógica de suma de comprobación EAN-13 deberían implementar los desarrolladores?
Las aplicaciones de punto de venta minorista suelen necesitar verificar los dígitos de control EAN-13 de forma independiente antes de pasar el valor a una consulta de precios. La suma de comprobación estilo Luhn para EAN-13 alterna pesos de 1 y 3 en los primeros 12 dígitos:
public static bool ValidateEan13Checksum(string value)
{
if (value.Length != 13 || !value.All(char.IsDigit))
return false;
int sum = 0;
for (int i = 0; i < 12; i++)
{
int digit = value[i] - '0';
sum += (i % 2 == 0) ? digit : digit * 3;
}
int expectedCheck = (10 - (sum % 10)) % 10;
return expectedCheck == (value[12] - '0');
}
public static bool ValidateEan13Checksum(string value)
{
if (value.Length != 13 || !value.All(char.IsDigit))
return false;
int sum = 0;
for (int i = 0; i < 12; i++)
{
int digit = value[i] - '0';
sum += (i % 2 == 0) ? digit : digit * 3;
}
int expectedCheck = (10 - (sum % 10)) % 10;
return expectedCheck == (value[12] - '0');
}
Public Shared Function ValidateEan13Checksum(value As String) As Boolean
If value.Length <> 13 OrElse Not value.All(AddressOf Char.IsDigit) Then
Return False
End If
Dim sum As Integer = 0
For i As Integer = 0 To 11
Dim digit As Integer = AscW(value(i)) - AscW("0"c)
sum += If(i Mod 2 = 0, digit, digit * 3)
Next
Dim expectedCheck As Integer = (10 - (sum Mod 10)) Mod 10
Return expectedCheck = (AscW(value(12)) - AscW("0"c))
End Function
Esta verificación de lógica pura se ejecuta antes de la codificación para evitar la sobrecarga de la generación de imágenes de ida y vuelta para cada escaneo en un entorno minorista de gran volumen. Según la especificación GS1 , el algoritmo del dígito de verificación es idéntico para UPC-A (12 dígitos) cuando se elimina el cero inicial.
¿Cómo generar códigos de barras de respuesta a partir de una entrada escaneada?
¿Cuándo debe una aplicación crear nuevos códigos de barras después de un escaneo?
Un patrón común en la recepción en el almacén es el flujo de trabajo de "escanear y volver a etiquetar": un artículo entrante lleva un código de barras de proveedor (a menudo EAN-13 o ITF-14), y el sistema de gestión del almacén necesita imprimir una etiqueta interna Código 128 con su propia ubicación y códigos de lote. Las capacidades de generación de IronBarcode manejan esto en unas pocas líneas:
public class InventoryLabelGenerator
{
private readonly string _outputDirectory;
public InventoryLabelGenerator(string outputDirectory)
{
_outputDirectory = outputDirectory;
Directory.CreateDirectory(_outputDirectory);
}
public async Task<string> GenerateLabelAsync(string internalCode, string locationCode)
{
string fullCode = $"{internalCode}|{locationCode}|{DateTime.UtcNow:yyyyMMdd}";
// Primary Code 128 label for scanners
var linearBarcode = BarcodeWriter.CreateBarcode(fullCode, BarcodeEncoding.Code128);
linearBarcode.ResizeTo(500, 140);
linearBarcode.SetMargins(12);
linearBarcode.AddAnnotationTextAboveBarcode(fullCode);
linearBarcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Black);
// QR code companion for mobile apps
var qrCode = BarcodeWriter.CreateQrCode(fullCode);
qrCode.ResizeTo(200, 200);
qrCode.SetMargins(8);
string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
string pngPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.png");
string pdfPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.pdf");
await Task.Run(() =>
{
linearBarcode.SaveAsPng(pngPath);
linearBarcode.SaveAsPdf(pdfPath);
});
return pngPath;
}
}
public class InventoryLabelGenerator
{
private readonly string _outputDirectory;
public InventoryLabelGenerator(string outputDirectory)
{
_outputDirectory = outputDirectory;
Directory.CreateDirectory(_outputDirectory);
}
public async Task<string> GenerateLabelAsync(string internalCode, string locationCode)
{
string fullCode = $"{internalCode}|{locationCode}|{DateTime.UtcNow:yyyyMMdd}";
// Primary Code 128 label for scanners
var linearBarcode = BarcodeWriter.CreateBarcode(fullCode, BarcodeEncoding.Code128);
linearBarcode.ResizeTo(500, 140);
linearBarcode.SetMargins(12);
linearBarcode.AddAnnotationTextAboveBarcode(fullCode);
linearBarcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Black);
// QR code companion for mobile apps
var qrCode = BarcodeWriter.CreateQrCode(fullCode);
qrCode.ResizeTo(200, 200);
qrCode.SetMargins(8);
string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
string pngPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.png");
string pdfPath = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.pdf");
await Task.Run(() =>
{
linearBarcode.SaveAsPng(pngPath);
linearBarcode.SaveAsPdf(pdfPath);
});
return pngPath;
}
}
Imports System.IO
Imports System.Threading.Tasks
Public Class InventoryLabelGenerator
Private ReadOnly _outputDirectory As String
Public Sub New(outputDirectory As String)
_outputDirectory = outputDirectory
Directory.CreateDirectory(_outputDirectory)
End Sub
Public Async Function GenerateLabelAsync(internalCode As String, locationCode As String) As Task(Of String)
Dim fullCode As String = $"{internalCode}|{locationCode}|{DateTime.UtcNow:yyyyMMdd}"
' Primary Code 128 label for scanners
Dim linearBarcode = BarcodeWriter.CreateBarcode(fullCode, BarcodeEncoding.Code128)
linearBarcode.ResizeTo(500, 140)
linearBarcode.SetMargins(12)
linearBarcode.AddAnnotationTextAboveBarcode(fullCode)
linearBarcode.ChangeBarCodeColor(IronSoftware.Drawing.Color.Black)
' QR code companion for mobile apps
Dim qrCode = BarcodeWriter.CreateQrCode(fullCode)
qrCode.ResizeTo(200, 200)
qrCode.SetMargins(8)
Dim timestamp As String = DateTime.UtcNow.ToString("yyyyMMddHHmmss")
Dim pngPath As String = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.png")
Dim pdfPath As String = Path.Combine(_outputDirectory, $"{internalCode}_{timestamp}.pdf")
Await Task.Run(Sub()
linearBarcode.SaveAsPng(pngPath)
linearBarcode.SaveAsPdf(pdfPath)
End Sub)
Return pngPath
End Function
End Class
Guardar como PDF es especialmente útil para impresoras de etiquetas que aceptan la entrada de PDF a través de un recurso compartido de red. También puede exportar como SVG para obtener una salida de etiqueta térmica con calidad vectorial, o exportar como un flujo de bytes para enviar directamente a una API de impresora de etiquetas.
IronBarcode admite una amplia personalización de estilo que incluye colores personalizados, ajustes de márgenes , superposiciones de texto legible por humanos y, para códigos QR, incrustación de logotipos para etiquetas móviles con la marca marcada.

¿Cómo manejar casos extremos y errores en aplicaciones de escáner?
¿Qué modos de fallo deberían anticipar los desarrolladores?
Las aplicaciones de escáner USB fallan de manera predecible. Los problemas más comunes y sus mitigaciones son:
Desconexión del escáner : cuando se desconecta un escáner USB, el teclado TextBox pierde su teclado virtual. La mitigación más simple es un temporizador periódico que verifica _inputBox.Focused y lo vuelve a enfocar si el escáner todavía aparece en los dispositivos HID conectados. Para los escáneres en serie, SerialPort.GetPortNames() detecta la reconexión.
Formatos de códigos de barras ambiguos : algunos productos llevan códigos de barras que son válidos en múltiples simbologías. Por ejemplo, una cadena de 12 dígitos es un UPC-A válido y también un Código 128 válido. Especificar ExpectBarcodeTypes en BarcodeReaderOptions restringe el decodificador a los formatos esperados y elimina la ambigüedad. La guía de solución de problemas de IronBarcode cubre consejos de reconocimiento específicos del formato.
Excepciones de formato no válido : si BarcodeWriter.CreateBarcode recibe una cadena que viola las reglas de codificación seleccionada (por ejemplo, caracteres alfabéticos en un campo EAN-13 solo numérico), genera un IronBarCode.Exceptions.InvalidBarcodeException. Envolver la llamada en un try-catch y volver a una ruta de validación de solo cadena mantiene la aplicación en ejecución.
Colisiones de tiempos de pulsaciones de teclas : en entornos donde los operadores también escriben manualmente en el mismo cuadro de texto, el enfoque del temporizador de ráfaga descrito anteriormente es la defensa principal. Una protección secundaria es la longitud mínima: la mayoría de los códigos de barras reales tienen al menos 8 caracteres, por lo que las cadenas más cortas pueden tratarse como entrada de teclado.
La documentación de Microsoft .NET sobre System.IO.Ports.SerialPort es útil para solucionar problemas de conectividad del escáner en serie, particularmente en torno a las configuraciones ReadTimeout y WriteTimeout. Para el cumplimiento normativo en el comercio minorista, las Especificaciones Generales GS1 definen rangos de valores válidos para cada identificador de aplicación.
¿Cómo ampliar la aplicación a plataformas móviles y web?
El patrón de interfaz del escáner que se muestra arriba -- IScannerInput con evento BarcodeScanned -- abstrae el hardware de la lógica de procesamiento. El intercambio de implementaciones permite que el mismo código de validación y generación se ejecute en diferentes plataformas:
- .NET MAUI proporciona una implementación de escáner basada en cámara para tabletas Android e iOS utilizadas como estaciones receptoras móviles
- Blazor Server admite el escaneo basado en navegador con acceso a la cámara JavaScript que alimenta el mismo evento
BarcodeScanned - Las implementaciones nativas de Android e iOS brindan a los desarrolladores móviles la capacidad de escanear la cámara con el mismo decodificador IronBarcode en el backend.
Para las arquitecturas nativas de la nube, los pasos de validación y generación de etiquetas se pueden ejecutar como funciones de Azure activadas por mensajes de cola, y la aplicación de escritorio actúa solo como puerta de enlace de entrada del escáner. Esta separación es particularmente útil cuando la lógica de impresión de etiquetas debe centralizarse para la auditoría de cumplimiento.
¿Cuales son tus próximos pasos?
La creación de una aplicación de escáner de código de barras USB con IronBarcode implica cuatro etapas concretas: capturar la entrada del teclado con detección de ráfagas de tiempo, validar el valor escaneado a través del decodificador de IronBarcode, generar etiquetas de respuesta en el formato requerido y procesar grandes volúmenes de escaneo con una cola simultánea. Cada etapa es independiente y se puede probar de forma aislada.
Desde aquí, considere ampliar la aplicación con lectura de múltiples códigos de barras para escenarios de procesamiento por lotes, optimización de la región de cultivo para entradas basadas en imágenes o compatibilidad con códigos de barras MSI para equipos de almacén más antiguos. La documentación de IronBarcode cubre todos los formatos compatibles y las opciones avanzadas de configuración del lector.
Comience una prueba gratuita para obtener una clave de licencia de desarrollo y comience a integrar IronBarcode en su aplicación de escaneo hoy mismo.
Preguntas Frecuentes
¿Qué es IronBarcode y cómo se relaciona con los escáneres de código de barras USB?
IronBarcode es una biblioteca que permite a los desarrolladores construir aplicaciones robustas de C# para escaneo de códigos de barras USB. Ofrece funciones como validación de códigos de barras, extracción de datos y generación de códigos de barras.
¿Puede IronBarcode validar datos de código de barras de un escáner USB?
Sí, IronBarcode puede validar datos de códigos de barras capturados desde un escáner USB, asegurando la integridad y precisión de los datos en tus aplicaciones C#.
¿Cómo maneja IronBarcode la generación de códigos de barras?
IronBarcode puede generar nuevos códigos de barras al instante, permitiendo a los desarrolladores crear e imprimir códigos de barras fácilmente dentro de sus aplicaciones C#.
¿Existe soporte para manejo de errores en IronBarcode para el escaneo de códigos de barras USB?
Sí, IronBarcode incluye un manejo de errores completo para gestionar problemas comunes que pueden surgir durante la escaneo y proceso de códigos de barras USB.
¿Qué tipos de códigos de barras se pueden escanear con IronBarcode?
IronBarcode admite el escaneo de una amplia gama de simbologías de códigos de barras, incluyendo códigos QR, UPC, Código 39 y más, lo que lo hace versátil para diversas aplicaciones.
¿Puede IronBarcode extraer información estructurada de los códigos de barras escaneados?
Sí, IronBarcode puede extraer información estructurada de los códigos de barras escaneados, ayudando en el procesamiento y gestión eficiente de datos.
¿Cómo puedo comenzar a construir una aplicación de escáner de código de barras USB en C#?
Para comenzar a construir una aplicación de escáner de código de barras USB en C#, puedes utilizar IronBarcode junto con los ejemplos de código y la documentación proporcionada para guiar tu proceso de desarrollo.


