C# USB Barkod Tarayıcı: Tam Bir Tarama Uygulaması Oluşturun
USB barkod tarayıcılar, C# uygulamalarına standart klavye giriş aygıtları olarak bağlanır ve taranan verileri bir Enter tuş vuruşunun ardından yazılmış karakterler olarak gönderir. Bu HID klavye kama davranışı, entegrasyonu basit hale getirir -- uygulamanızın metin girişi alması için özel bir sürücü veya SDK gerekmez. IronBarcode, bu ham girdiyi formatları doğrulamak, yapılandırılmış verileri çıkarmak ve yanıt barkodları oluşturmak için işler ve basit bir tarama olayını envanter yönetimi, perakende satış noktası ve lojistik takip sistemleri için eksiksiz bir veri hattına dönüştürür.
Perakende, depolama ve üretim operasyonlarının tümü, doğru ve hızlı barkod taramaya dayanır. Bir geliştirici, bir USB tarayıcıyı bir Windows Forms veya WPF uygulamasına bağladığında, tarayıcı klavye ile aynı şekilde davranır -- veriler bir TextBox'a gelir ve Enter tuşuna basıldığında tam bir barkod alındığını bildirir. Mesele veriyi yakalamakta değildir; doğru işlemede yatmaktadır. IronBarcode'un barkod doğrulaması biçim bütünlüğünü kontrol eder, parti numaraları veya GS1 uygulama tanımlayıcıları gibi alanları çıkarır ve bir yanıt olarak hemen yeni bir barkod oluşturabilir.
Bu kılavuz, üretime hazır bir C# USB barkod tarayıcı uygulamasını adım adım oluşturmaya yönlendirir. Kütüphaneyi yükleyeceksiniz, tarayıcı girdisini yakalayacaksınız, barkod formatlarını doğrulayacaksınız, yanıt etiketleri oluşturacaksınız ve yüksek hacimli bir kuytu tabanlı işlemci toplayacaksınız. Her bölüm, uygun olduğunda üst düzey ifadelerle .NET 10'u hedefleyen eksiksiz ve çalıştırılabilir kod içerir.
USB Barkod Tarayıcılar C# İle Nasıl Çalışır?
HID Klavye Kama Modu Entegrasyonu Neden Basitleştirir?
Çoğu USB barkod tarayıcı, varsayılan olarak HID klavye kama modunda yapılandırılarak gelir. Bir tanesini bir Windows makinesine taktığınızda, işletim sistemi bunu hem bir USB depolama aygıtı (konfigürasyon için) hem de bir klavye (veri girişi için) olarak kaydeder. Bir barkod tarandığında, cihaz, çözümlenmiş barkod değerini tuş vuruşlarına çevirir ve odaklı herhangi bir uygulama penceresine gönderir, sonunda bir taşıma dönüşü ekleyerek.
C# geliştiricisi açısından, bu, satıcı SDK'larına, COM kütüphanelerine veya özel USB API'lerine ihtiyaç duyulmadığı anlamına gelir. Girdiyi yakalamak için bir KeyDown işleyicisi olan standart bir TextBox yeterlidir. Ana entegrasyon zorluğu, tarayıcı girdisini gerçek klavye yazımından ayırt etmektir. Tarayıcılar genellikle tüm karakterleri çok kısa bir patlama süresinde iletir - genellikle 50 milisaniyenin altında - oysa insan yazımı tuş vuruşlarını yüzlerce milisaniye boyunca yayar. Bu patlamanın zamanlaması, yanlışlıkla yapılan tuş vuruşlarını filtrelemek için güvenilir bir yoldur.
Profesyonel dereceli tarayıcılar ayrıca seri (RS-232 veya sanal COM port) ve doğrudan USB HID modlarını destekler, bu da ön ek/son ek karakterleri ve tarama tetikleyicileri üzerinde daha fazla kontrol sağlar. Aşağıdaki arayüz deseni her iki durumu da ele alır:
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
Klavyedeki kama uygulamasının patlama zamanlayıcısı kritik bir detaydır. Her tuş vuruşunda sıfırlanır ve karakterler gelmeyi durdurursa tetiklenir - yani yavaşça yazan gerçek klavye kullanıcılarının eksik girdileri, bir barkod taraması gibi muamele edileceğine atılmış olur.
Birden Fazla Tarayıcı Markasını Nasıl Ele Alırsınız?
Kurumsal ortamlar, genellikle aynı katta Honeywell, Zebra (eski isimleriyle Symbol/Motorola) ve Datalogic tarayıcıları çalıştırır. Her satıcının kendi varsayılan terminal karakteri, baud oranı ve ön ek/son ek gelenekleri vardır. Bir konfigürasyon modeli uygulamanızı esnek tutar:
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
Bu konfigürasyonları bir ayarlar dosyasında veya veritabanında depolamak, depo çalışanlarının tarayıcı modellerini yeniden dağıtım gerektirmeden değiştirmelerini sağlar. ScannerType alanı, başlangıçta hangi IScannerInput uygulamasının oluşturulacağını belirler.
IronBarcode Nasıl Yüklenir Bir C# Projesine?
IronBarcode'u NuGet ile Eklemek İçin En Hızlı Yol Nedir?
Visual Studio'da Paket Yöneticisi Konsolunu açın ve şu komutu çalıştırın:
Install-Package BarCode
Alternatif olarak, .NET CLI'yi kullanın:
dotnet add package BarCode
Her iki komut da NuGet.org'dan mevcut sürümü çeker ve derlemeye bağlı referansı proje dosyanıza ekler. Kütüphane, .NET Framework 4.6.2'den .NET 10'a kadar, herhangi bir ek uyumluluk katmanı olmadan .NET Standard 2.0'ı hedefler.
Yükledikten sonra, herhangi bir IronBarcode yöntemini çağırmadan önce lisans anahtarınızı ayarlayın. Geliştirme ve değerlendirme için, ücretsiz bir deneme anahtarı, IronBarcode lisanslama sayfasından mevcuttur:
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
Kapsüllü dağıtımlar için, IronBarcode, Docker ile Linux üzerinde çalışır ve bulut işlevlerinde, AWS Lambda ve Azure Functions desteklerini sunar.
Taradığınız Barkodları IronBarcode ile Nasıl Doğrularsınız?
Format Doğrulaması İçin Doğru Yaklaşım Hangisidir?
IronBarcode, 30'dan fazla barkod simgolojisini destekler, Kod 128, EAN-13, Kod 39, QR kodları ve Data Matrix dahil. USB tarayıcı uygulamaları için, doğrulama deseni, taranan dizeyi bir barkod resmi olarak yeniden şifreler ve derhal dekoder aracılığıyla geri okur. Bu, dizinin beyan edilen format için geçerli bir değer olduğunu doğrular:
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
Tedarik zinciri uygulamalarında kullanılan GS1-128 barkodları için, taranan dizi, uygulama tanımlayıcı öneklerini parantez içinde içerir, örneğin GTIN için (01) ve son kullanma tarihi için (17). IronBarcode, BarcodeEncoding.GS1_128 belirttiğinizde bu uygulama tanımlayıcılarını otomatik olarak işler.
Geliştiriciler Hangi EAN-13 Checksum Mantığını Uygulamalıdır?
Perakende satış noktası uygulamaları genellikle bir değer fiyat araması yapmadan önce EAN-13 kontrol hanelerini bağımsız olarak doğrulamalıdır. EAN-13 için Luhn tarzı kontrol hattı, ilk 12 basamak boyunca 1 ve 3 ağırlıklarını değiştirir:
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
Bu saf mantıksal kontrol, yüksek hacimli bir perakende ortamında her taramada yuvarlak yol görüntü oluşturma maliyetini önlemek için şifrelemeden önce çalışır. GS1 spesifikasyonu na göre, kontrol hanesi algoritması, önde gelen sıfırı düşürdüğünüzde UPC-A (12 basamak) için aynıdır.
Taranan Girdiden Yanıt Barkodlarını Nasıl Oluşturursunuz?
Bir Uygulama Bir Taramanın Ardından Ne Zaman Yeni Barkodlar Oluşturmalıdır?
Depo teslim alma biriminin ortak bir deseni "tara ve yeniden etiketle" iş akışıdır: Gelen bir ürün bir tedarikçi barkodu taşır (genellikle EAN-13 veya ITF-14) ve depo yönetim sistemi, kendi konum ve parti kodlarıyla bir içsel Kod 128 etiketi yazdırmalıdır. IronBarcode'un oluşturma yetenekleri bunu birkaç satırda halleder:
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
PDF olarak kaydetme, bir paylaşımlı ağ üzerinden PDF girdi kabul eden etiket yazıcıları için özellikle yararlıdır. Ayrıca SVG olarak dışa aktarabilir ve vektör kalitesinde termal etiket çıktısı için veya bir bayt akışı olarak dışa aktarabilir ve doğrudan bir etiket yazıcı API'sine gönderebilirsiniz.
IronBarcode, kapsamlı stil özelleştirme dahil olmak üzere özel renkler, kenar boşluğu ayarlamaları, insan tarafından okunabilir metin yer arayüzleri ve QR kodları için marka işaretli mobil etiketler için logo yerleştirme destekler.
Windows Forms uygulama arayüzü, IronBarcode'un çift barkod oluşturma yeteneklerini gösteriyor. Arayüz, envanter sayısı 'INV-20250917-helloworld' için bir Kod 128 lineer barkod ve bir QR kodunun başarıyla oluşturulduğunu gösterir. Üstteki giriş alanı, kullanıcıların özel envanter kodları girmesine izin verir, 'Oluştur' düğmesi barkodları oluşturmak için basılır. Başarılı işlem 'Öğe başarıyla işlendi - Üretilen Etiketler' mesajı operasyonun tamamlandığını onaylar. Kod 128 barkodu, birincil envanter izleme formatı olarak, QR kodu ise mobil uyumlu bir alternatif olarak etiketlenmiştir. Uygulama, profesyonel bir gri arka plan kullanır ve nasıl net bir görsel hiyerarşi sağlandığını gösterir. IronBarcode, geliştiricilere eksiksiz envanter yönetimi için çok formatlı barkod oluşturma sistemleri oluşturma yeteneği sağlar.
Nasıl Tam Yüksek Hacimli Tarama Uygulaması İnşa Edilir?
Üretim Kuyruk Tabınlı Bir Uygulama Nasıl Görünür?
Dakikada düzinelerce tarama işleyen uygulamalar için, kullanıcı arayüzü iş parçacığını üzerindeki basit senkron işleyici darboğaz haline gelir. Aşağıdaki desen, tarama yakalamayı bir ConcurrentQueue<t> ve bir arka plan işleme döngüsü kullanarak işlemden ayırır. IronBarcode'ın async API'si UI'yi engellemeden doğrulamayı yönetir:
using IronBarCode;
using System.Collections.Concurrent;
public partial class HighVolumeScanner : Form
{
private readonly ConcurrentQueue<(string Data, DateTime Timestamp)> _scanQueue = new();
private readonly SemaphoreSlim _semaphore;
private readonly CancellationTokenSource _cts = new();
private IScannerInput _scanner;
public HighVolumeScanner()
{
InitializeComponent();
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
_semaphore = new SemaphoreSlim(Environment.ProcessorCount);
InitializeScanner();
_ = RunProcessingLoopAsync();
}
private void InitializeScanner()
{
_scanner = System.IO.Ports.SerialPort.GetPortNames().Any()
? new SerialPortScanner("COM3", 115200)
: new KeyboardWedgeScanner(txtScannerInput);
_scanner.BarcodeScanned += (_, barcode) =>
_scanQueue.Enqueue((barcode, DateTime.UtcNow));
_scanner.StartListening();
}
private async Task RunProcessingLoopAsync()
{
while (!_cts.Token.IsCancellationRequested)
{
if (_scanQueue.TryDequeue(out var scan))
{
await _semaphore.WaitAsync(_cts.Token);
_ = Task.Run(async () =>
{
try { await ProcessScanAsync(scan.Data, scan.Timestamp); }
finally { _semaphore.Release(); }
}, _cts.Token);
}
else
{
await Task.Delay(10, _cts.Token);
}
}
}
private async Task ProcessScanAsync(string rawData, DateTime scanTime)
{
var options = new BarcodeReaderOptions
{
Speed = ReadingSpeed.Dengeli,
ExpectMultipleBarcodes = false,
ExpectBarcodeTypes = BarcodeEncoding.Code128 | BarcodeEncoding.QRCode,
MaxParallelThreads = 1
};
var testBarcode = BarcodeWriter.CreateBarcode(rawData, BarcodeEncoding.Code128);
var results = await BarcodeReader.ReadAsync(testBarcode.ToBitmap(), options);
if (results.Any())
{
var item = results.First();
BeginInvoke(() => UpdateInventoryDisplay(item.Value, scanTime));
}
else
{
BeginInvoke(() => LogRejectedScan(rawData, scanTime));
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
_cts.Cancel();
_scanner.StopListening();
base.OnFormClosing(e);
}
}
using IronBarCode;
using System.Collections.Concurrent;
public partial class HighVolumeScanner : Form
{
private readonly ConcurrentQueue<(string Data, DateTime Timestamp)> _scanQueue = new();
private readonly SemaphoreSlim _semaphore;
private readonly CancellationTokenSource _cts = new();
private IScannerInput _scanner;
public HighVolumeScanner()
{
InitializeComponent();
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
_semaphore = new SemaphoreSlim(Environment.ProcessorCount);
InitializeScanner();
_ = RunProcessingLoopAsync();
}
private void InitializeScanner()
{
_scanner = System.IO.Ports.SerialPort.GetPortNames().Any()
? new SerialPortScanner("COM3", 115200)
: new KeyboardWedgeScanner(txtScannerInput);
_scanner.BarcodeScanned += (_, barcode) =>
_scanQueue.Enqueue((barcode, DateTime.UtcNow));
_scanner.StartListening();
}
private async Task RunProcessingLoopAsync()
{
while (!_cts.Token.IsCancellationRequested)
{
if (_scanQueue.TryDequeue(out var scan))
{
await _semaphore.WaitAsync(_cts.Token);
_ = Task.Run(async () =>
{
try { await ProcessScanAsync(scan.Data, scan.Timestamp); }
finally { _semaphore.Release(); }
}, _cts.Token);
}
else
{
await Task.Delay(10, _cts.Token);
}
}
}
private async Task ProcessScanAsync(string rawData, DateTime scanTime)
{
var options = new BarcodeReaderOptions
{
Speed = ReadingSpeed.Dengeli,
ExpectMultipleBarcodes = false,
ExpectBarcodeTypes = BarcodeEncoding.Code128 | BarcodeEncoding.QRCode,
MaxParallelThreads = 1
};
var testBarcode = BarcodeWriter.CreateBarcode(rawData, BarcodeEncoding.Code128);
var results = await BarcodeReader.ReadAsync(testBarcode.ToBitmap(), options);
if (results.Any())
{
var item = results.First();
BeginInvoke(() => UpdateInventoryDisplay(item.Value, scanTime));
}
else
{
BeginInvoke(() => LogRejectedScan(rawData, scanTime));
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
_cts.Cancel();
_scanner.StopListening();
base.OnFormClosing(e);
}
}
Imports IronBarCode
Imports System.Collections.Concurrent
Imports System.Threading
Public Partial Class HighVolumeScanner
Inherits Form
Private ReadOnly _scanQueue As New ConcurrentQueue(Of (Data As String, Timestamp As DateTime))()
Private ReadOnly _semaphore As SemaphoreSlim
Private ReadOnly _cts As New CancellationTokenSource()
Private _scanner As IScannerInput
Public Sub New()
InitializeComponent()
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
_semaphore = New SemaphoreSlim(Environment.ProcessorCount)
InitializeScanner()
_ = RunProcessingLoopAsync()
End Sub
Private Sub InitializeScanner()
_scanner = If(System.IO.Ports.SerialPort.GetPortNames().Any(),
New SerialPortScanner("COM3", 115200),
New KeyboardWedgeScanner(txtScannerInput))
AddHandler _scanner.BarcodeScanned, Sub(_, barcode)
_scanQueue.Enqueue((barcode, DateTime.UtcNow))
End Sub
_scanner.StartListening()
End Sub
Private Async Function RunProcessingLoopAsync() As Task
While Not _cts.Token.IsCancellationRequested
Dim scan As (Data As String, Timestamp As DateTime)
If _scanQueue.TryDequeue(scan) Then
Await _semaphore.WaitAsync(_cts.Token)
_ = Task.Run(Async Function()
Try
Await ProcessScanAsync(scan.Data, scan.Timestamp)
Finally
_semaphore.Release()
End Try
End Function, _cts.Token)
Else
Await Task.Delay(10, _cts.Token)
End If
End While
End Function
Private Async Function ProcessScanAsync(rawData As String, scanTime As DateTime) As Task
Dim options As New BarcodeReaderOptions With {
.Speed = ReadingSpeed.Dengeli,
.ExpectMultipleBarcodes = False,
.ExpectBarcodeTypes = BarcodeEncoding.Code128 Or BarcodeEncoding.QRCode,
.MaxParallelThreads = 1
}
Dim testBarcode = BarcodeWriter.CreateBarcode(rawData, BarcodeEncoding.Code128)
Dim results = Await BarcodeReader.ReadAsync(testBarcode.ToBitmap(), options)
If results.Any() Then
Dim item = results.First()
BeginInvoke(Sub() UpdateInventoryDisplay(item.Value, scanTime))
Else
BeginInvoke(Sub() LogRejectedScan(rawData, scanTime))
End If
End Function
Protected Overrides Sub OnFormClosing(e As FormClosingEventArgs)
_cts.Cancel()
_scanner.StopListening()
MyBase.OnFormClosing(e)
End Sub
End Class
SemaphoreSlim, eşzamanlı doğrulama görevlerini mantıksal işlemci sayısıyla sınırlar ve dalgalı tarama olayları sırasında kontrolsüz iş parçacığı oluşturulmasını engeller. BeginInvoke çağrıları, UI güncellemelerini ana iş parçacığına güvenli bir şekilde yeniden yönlendirir.
Farklı Tarama Hacimleri İçin Performansı Nasıl Ayarlarsınız?
BarcodeReaderOptions.Speed özelliği ReadingSpeed.Faster, ReadingSpeed.Balanced ve ReadingSpeed.Detailed kabul eder. Dizgi değerinin zaten bilindiği USB tarayıcı girişi için, Balanced uygundur -- kod çözücü yalnızca formatı doğrulamalı, bir görüntüde barkod bulmamalıdır. IronBarcode'un okuma hızı belgelerine göre, Faster modu bazı bozulma düzeltme algoritmalarını atlar, bu temiz tarayıcı çıktısı için güvenlidir ancak görüntü tabanlı senaryolarda zarar görmüş barkodları kaçırabilir.
Aşağıdaki tablo, her hız modunun ne zaman kullanılacağını özetlemektedir:
| Hız Modu | En İyi İçin | Takas |
|---|---|---|
| Daha hızlı | Temiz USB tarayıcı girişi, yüksek hacimli aktarım | Kötü hasarlı veya eğik barkodları kaçırabilir |
| Dengeli | Karışık girdi - USB tarayıcı artı görüntü içe aktarımları | Orta CPU kullanımı, iyi doğruluk |
| Detaylı | Hasarlı etiketler, düşük kontrast baskı, PDF içe aktarımları | Daha yüksek CPU kullanımı, en yavaş çıktı |
Ayrıca görüntüleri veya PDF'leri USB tarayıcı girdisiyle birlikte işleyen uygulamalar için IronBarcode, PDF belgelerinden barkod okuyabilir ve aynı API yüzeyini kullanarak çok sayfalı TIFF dosyaları okuyabilir.
Profesyonel Windows Forms barkod tarayıcı uygulaması, IronBarcode'un gerçek zamanlı envanter izleme yeteneklerini gösteriyor. Arayüz, sofistike koyu mavi başlığa sahip temiz iki panel tasarımı içerir. Sol panel, dört başarılı taranmış envanter öğesi (INV-001'den INV-004'e) ile kesin zaman damgaları ve tarama durum göstergeleri içeren bir tarama geçmiş listesi gösterir. Her öğe, barkod türü ve güven düzeyi gibi ayrıntılı meta verileri içerir. Sağ panel, 'Öğeler: 4' ifadesini profesyonel stil ve uygun kenar boşluklarıyla gösteren dinamik bir şekilde oluşturulmuş özet barkodu gösterir. Envanter yönetimi için tam aksiyon düğmeleri, 'Listeyi Temizle', 'Verileri Dışa Aktar' ve 'Etiketleri Yazdır' içerir. Durum çubuğu 'Tarayıcı: Bağlı | Modu: Kesintisiz | Son Tarama: 2 saniye önce', uygulamanın gerçek zamanlı izleme yeteneklerini ve üretime hazır kurumsal profesyonel tasarımını gösteriyor. IronBarcode, üretim envanter sistemleri için etkinleştirir.
Tarayıcı Uygulamalarında Kenar Durumları ve Hataları Nasıl Ele Alırsınız?
Geliştiricilerin Hangi Hata Modlarını Tahmin Etmeli?
USB tarayıcı uygulamaları tahmin edilebilir şekillerde başarısız olur. En yaygın sorunlar ve bunların önlemleri şunlardır:
Tarayıcı bağlantısı kesilmesi -- Bir USB tarayıcı çekildiğinde, klavye kama TextBox sanal klavyesini kaybeder. En basit önlem, periyodik bir zamanlayıcı olup, _inputBox.Focused kontrol eder ve tarayıcı hala bağlı HID cihazları listesinde ise yeniden odaklar. Seri tarayıcılar için, SerialPort.GetPortNames() yeniden bağlanmayı algılar.
Belirsiz barkod formatları -- Bazı ürünler, birden fazla simgolojide geçerli olan barkodları taşır. Örneğin, 12 basamaklı bir dizi hem geçerli bir UPC-A hem de geçerli bir Code 128'dir. ExpectBarcodeTypes belirtmek BarcodeReaderOptions içinde kod çözücüyü beklenen formatlarınıza sınırlar ve belirsizliği ortadan kaldırır. IronBarcode sorun giderme kılavuzu, formata özgü tanıma ipuçlarını kapsar.
Geçersiz format istisnaları -- BarcodeWriter.CreateBarcode seçili kodlama kurallarını ihlal eden bir dizi alırsa (örneğin, yalnızca sayısal EAN-13 alanında alfabetik karakterler) bir IronBarCode.Exceptions.InvalidBarcodeException fırlatır. Tekrarlama çağrısını bir try-catch içinde sararak sadece dize doğrulama yoluna geri dönülür ve uygulamanın çalışması sağlanır.
Tuş vuruşu zamanlama çarpışmaları -- Aynı TextBox'a operatörlerin manuel olarak yazdığı ortamlarda, daha önce açıklanan patlama zamanlayıcısı yaklaşımı birincil savunmadır. İkincil bir koruma, minimum uzunluktur: Çoğu gerçek barkod en az 8 karakterdir, bu nedenle bundan daha kısa dizeler klavye girişi gibi muamele görebilir.
System.IO.Ports.SerialPort ile ilgili Microsoft .NET belgelendirmesi, özellikle ReadTimeout ve WriteTimeout ayarları çevresinde, seri tarayıcı bağlantı sorunlarını giderirken yararlıdır. Perakende düzenlemelerine uyum sağlamak için GS1 Genel Spesifikasyonları, her uygulama tanımlayıcısı için geçerli değer aralıklarını tanımlar.
Uygulamayı Mobil ve Web Platformlarına Nasıl Genişletirsiniz?
Yukarıda gösterilen tarayıcı arayüzü deseni -- IScannerInput ile BarcodeScanned olay -- donanımı işleme mantığından soyutlar. Uygulamalar arasındaki geçiş aynı doğrulama ve üretim kodunun farklı platformlarda çalışmasına imkan tanır:
- .NET MAUI, mobil alım istasyonları olarak kullanılan Android ve iOS tabletler için kamera tabanlı tarayıcı uygulaması sağlar
- Blazor Server, tarayıcı tabanlı taramayı, JavaScript kamera erişimi ile aynı
BarcodeScannedetkinliğine besleme ile destekler. - Android ve iOS yerel uygulamaları, mobil geliştiriciler için arka planda aynı IronBarcode dekoder ile kamera tarama yeteneği sağlar
Buluta özgü mimariler için, doğrulama ve etiket üretim adımları kuyruğundaki ileti tetiklemeleriyle çalışan Azure İşlevleri gibi hale gelebilir, masaüstü uygulaması sadece tarayıcı giriş kapısı olarak çalışır. Bu ayrım, etiket basma mantığının uyum denetimleri için merkezileştirilmesi gerektiğinde özellikle yararlıdır.
Sonraki Adımlarınız Neler?
IronBarcode ile USB barkod tarayıcı uygulaması oluşturmak, klavye kama girdisini patlama zamanlaması algılamayla yakalamak, taranan değeri IronBarcode'un dekoderi aracılığıyla doğrulamak, gerekli formatta yanıt etiketler oluşturmak ve eşzamanlı bir kuyruğa sahip yüksek tarama hacimli işlemlerle dört somut aşama içerir. Her aşama bağımsızdır ve izole olarak test edilebilir.
Buradan, uygulamayı toplu işlem senaryoları için çoklu barkod okuması, görüntü bazlı girdiler için kırpılmış alan iyileştirmesi veya eski depo ekipmanları için MSI barkod desteği ile genişletmeyi düşünün. IronBarcode belgeleri, tüm desteklenen formatları ve gelişmiş okuyucu yapılandırma seçeneklerini kapsar.
Ücretsiz bir denemeye başlayın, geliştirme lisans anahtarı alarak IronBarcode'u tarama uygulamanıza entegre etmeye başlayın.
Sıkça Sorulan Sorular
IronBarcode nedir ve USB barkod tarayıcıları ile nasıl ilişkilidir?
IronBarcode, geliştiricilerin USB barkod tarama için sağlam C# uygulamaları oluşturmasına olanak tanıyan bir kütüphanedir. Barkod geçerliliği, veri çıkarımı ve barkod oluşturma gibi özellikler sunar.
IronBarcode USB tarayıcıdan gelen barkod verilerini doğrulayabilir mi?
Evet, IronBarcode, USB tarayıcıdan alınan barkod verilerini doğrulayabilir, bu da C# uygulamalarınızda veri bütünlüğü ve doğruluğu sağlar.
IronBarcode barkod oluşturmayı nasıl halleder?
IronBarcode, geliştiricilerin C# uygulamalarında kolayca barkod oluşturmasına ve yazdırmasına olanak tanıyan yeni barkodlar oluşturabilir.
USB barkod tarama için IronBarcode'da hata işleme desteği var mı?
Evet, IronBarcode, USB barkod tarama ve işleme sırasında ortaya çıkabilecek yaygın sorunları yönetmek için kapsamlı hata işleme içerir.
Hangi tipte barkodlar IronBarcode ile taranabilir?
IronBarcode, QR kodları, UPC, Code 39 ve daha fazlasını içeren geniş bir barkod semboloji yelpazesinin taranmasını destekler ve bu da onu çeşitli uygulamalar için çok yönlü kılar.
IronBarcode taranmış barkodlardan yapısal bilgi çıkarabilir mi?
Evet, IronBarcode taranmış barkodlardan yapısal bilgi çıkarabilir, bu da verimli veri işleme ve yönetimine yardımcı olur.
C#'ta bir USB barkod tarayıcı uygulaması oluşturmaya nasıl başlayabilirim?
C#'ta bir USB barkod tarayıcı uygulaması oluşturmaya başlamak için, IronBarcode'u sağlanan kod örnekleri ve belgelerle birlikte kullanarak geliştirme sürecine rehberlik edebilirsiniz.




