C# USB Çizgikodu Tarayıcı: Tam Bir Tarayıcı Uygulaması Oluşturun
USB barkod tarayıcılar, taranan verileri yazılı karakterler ve ardından Enter tuşu vuruşuyla gönderen standart klavye giriş cihazları olarak C# uygulamalarına bağlanır. Bu HID klavye wedge davranışı entegrasyonu kolaylaştırır -- uygulamanızda herhangi bir özel sürücü veya SDK gerekmeden metin girişi alırsınız. IronBarcode, bu ham girişi formatları doğrulamak, yapılandırılmış veriler çıkarmak ve yanıt barkodları üretmek için işler, envanter yönetimi, perakende satış noktası ve lojistik takip sistemleri için tam bir veri hattı oluşturur.
Perakende, depolama ve üretim operasyonları, doğru ve hızlı barkod taramaya bağlıdır. Bir geliştirici, bir USB tarayıcıyı Windows Forms veya WPF uygulamasına bağladığında, tarayıcı, bir klavye gibi davranır -- veri bir TextBox'a gelir ve Enter tuşuna basmak, tam bir barkodun alındığını sinyaller. Zorluk, veriyi kaydetmek değil; onu doğru bir şekilde işlemektir. IronBarcode'un barkod doğrulaması, format bütünlüğünü kontrol eder, parti numaraları veya GS1 uygulama tanımlayıcıları gibi alanları çıkarır ve hemen yanıt olarak yeni bir barkod üretebilir.
Bu kılavuz, adım adım üretim hazır bir C# USB barkod tarayıcı uygulaması oluşturmanın yolunu gösterir. Kütüphaneyi kuracak, tarayıcı girişini yakalayacak, barkod formatlarını doğrulayacak, yanıt etiketlerini üretecek ve yüksek hacimli bir sıra tabanlı işlemci kuracaksınız. Her bölüm, .NET 10'u hedefleyen ve uygun yerlerde üst düzey ifade tarzını kullanan eksiksiz, çalıştırılabilir kod içerir.
C# ile USB Barkod Tarayıcıları Nasıl Çalışır?
HID Klavye Wedge Modu Entegrasyonu Neden Kolaylaştırır?
Çoğu USB barkod tarayıcı, varsayılan olarak HID klavye wedge modunda gönderilir. Birini bir Windows makinesine taktığınızda, işletim sistemi onu hem bir USB depolama cihazı (yapılandırma için) hem de bir klavye (veri girişi için) olarak kaydeder. Bir barkod tarandığında, cihaz kodlanmış barkod değerini tuş vuruşlarına çevirir ve odaklanmış olan uygulama penceresine gönderir, sonunda taşıyıcı dönüşü ekleyerek.
Bir C# geliştiricisi olarak, bu, satıcı SDK'larına, COM kütüphanelerine veya özel USB API'lerine ihtiyaçınız olmadığı anlamına gelir. Bir KeyDown işleyicisine sahip standart bir TextBox, giriş yakalamak için gereken tek şeydir. Ana entegrasyon zorluğu, tarayıcı girdisini gerçek klavye yazısından ayırt etmektir. Tarayıcılar genellikle tüm karakterleri çok kısa bir patlama içinde iletir -- genellikle 50 milisaniyeden kısa -- insan yazımı ise tuş vuruşlarını yüzlerce milisaniye boyunca yayar. Patlamanın zamanlaması, kazara tuş vuruşlarını filtrelemenin güvenilir bir yoludur.
Profesyonel sınıf tarayıcılar ayrıca seri (RS-232 veya sanal COM port) ve doğrudan USB HID modlarını destekler, bu da size ön ek/son ek karakterler 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
Klavye kama uygulamasındaki zaman patlaması detayı anahtardır. Her tuş vuruşunda sıfırlanır ve yalnızca karakterler gelmeyi durdurduğunda çalışır -- bu, yavaş yavaş yazan gerçek klavye kullanıcılarının tamamlanmamış girdilerinin barkod taraması olarak değerlendirilmek yerine atılacağı anlamına gelir.
Çoklu Tarayıcı Markaları Nasıl Yönetilir?
Enterprise ortamları sıklıkla aynı katta bir karışım Honeywell, Zebra (eski adıyla Symbol/Motorola) ve Datalogic tarayıcıları çalıştırır. Her satıcının kendi varsayılan sonlandırıcı karakterleri, baud hızları ve önek/son ek konvansiyonları vardır. Bir yapılandırma 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 yapılandırmaları bir ayar dosyasında veya veritabanında depolamak, depo personelinin tarayıcı modellerini yeniden dağıtım gerektirmeden değiştirebileceği anlamına gelir. ScannerType alanı, başlangıçta hangi IScannerInput uygulamasının örnekleneceğini belirler.
IronBarcode Bir C# Projesine Nasıl Yüklenir?
NuGet Üzerinden IronBarcode Eklemek için En Hızlı Yol Nedir?
Visual Studio'da Paket Yöneticisi Konsolunu açın ve çalıştırın:
Install-Package IronBarCode
Install-Package IronBarCode
Alternatif olarak, .NET CLI'yi kullanın:
dotnet add package IronBarCode
dotnet add package IronBarCode
Her iki komut da mevcut sürümü NuGet.org'dan çeker ve derleme referansını proje dosyanıza ekler. Kütüphane .NET Standard 2.0'ı hedefler, böylece .NET Framework 4.6.2'den .NET 10'a kadar ek uyumluluk dolgu gerektirmeden çalışır.
Yükledikten sonra, herhangi bir IronBarcode metodunu çağırmadan önce lisans anahtarınızı ayarlayın. Geliştirme ve değerlendirme için, IronBarcode lisans sayfasından ücretsiz bir deneme anahtarı mevcuttur:
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
Konteynerleştirilmiş dağıtımlar için, IronBarcode Docker ile Linux'ta çalışır ve bulut fonksiyonları için AWS Lambda ve Azure Fonksiyonları desteklenir.
Tarama Barkodları IronBarcode ile Nasıl Doğrulanır?
Format Doğrulama İçin Doğru Yaklaşım Nedir?
IronBarcode 30'dan fazla barkod sembolojisini destekler bunlar arasında Code 128, EAN-13, Code 39, QR kodları ve Data Matrix bulunur. USB tarayıcı uygulamaları için doğrulama deseni, taranmış dizgiyi barkod resmi olarak yeniden kodlar ve hemen dekoder aracılığıyla okur. Bu gidiş-dönüş, dizginin bildirilen 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 dize parantez içinde uygulama tanımlayıcı ön eklerini 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 ayrıştırır.
Geliştiriciler Hangi EAN-13 Kontrol Toplamı Mantığını Uygulamalıdır?
Perakende satış noktası uygulamaları genellikle EAN-13 kontrol rakamlarını fiyat sorgulamasına geçmeden önce bağımsız olarak doğrulama gerektirir. EAN-13 için Luhn tarzı kontrol toplamı, 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 tarama için gidiş-dönüş resim oluşturma yükünü önlemek amacıyla kodlamadan önce çalışır. GS1 spesifikasyonuna göre, kontrol rakamı algoritması UPC-A (12 haneli) için lider sıfırı bıraktığınızda aynıdır.
Taranan Girdiden Yanıt Barkodları Nasıl Üretilir?
Bir Uygulama Taramadan Sonra Ne Zaman Yeni Barkod Üretmelidir?
Depo alımında yaygın bir desen 'tara ve etiketle' iş akışıdır: gelen bir öğe bir tedarikçi barkodu taşır (genellikle EAN-13 veya ITF-14) ve depo yönetim sistemi kendi konumu ve parti kodları ile bir iç Code 128 etiketini yazdırmalıdır. IronBarcode'un oluşturma yetenekleri bunu birkaç satırda işler:
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, özellikle PDF girişini bir ağ paylaşımı üzerinden kabul eden etiket yazıcıları için kullanışlıdır. Ayrıca, SVG olarak dışa aktarabilirsiniz vektör kalitesinde termal etiket çıktısı için veya etiket yazıcı API'sine doğrudan göndermek üzere bir bayt akışı olarak dışa aktarabilirsiniz.
IronBarcode geniş stil özelleştirmelerini destekler; özel renkler, kenar boşluğu ayarlamaları, okunabilir metin eklemeleri ve QR kodları için logo gömme markalı mobil etiketler için.

Yüksek Hacimli Tam Bir Tarama Uygulaması Nasıl Kurulur?
Üretim Kuyruk Tabanlı Bir Uygulama Nasıl Görünür?
Dakikada düzinelerce taramayı işleyen uygulamalar için, UI iş parçacığında basit bir senkron işleyici dar boğaz olur. Aşağıdaki desen, tarama yakalama işlemini bir ConcurrentQueue<t> ve bir arka plan işleme döngüsü kullanarak işlemden ayırır. IronBarcode'un eşzamansız API'si doğrulamayı UI'yi engellemeden gerçekleştirir:
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, mantıksal işlemci sayısını eşzamanlı doğrulama görevlerine sınırlar, ani tarama olaylarında aşırı iş parçacığı oluşturulmasını önler. BeginInvoke, UI güncellemelerini güvenli bir şekilde ana iş parçacığına geri yönlendirir.
Değişken Tarama Hacimleri İçin Performans Nasıl Ayarlanır?
BarcodeReaderOptions.Speed özelliği, ReadingSpeed.Daha hızlı, ReadingSpeed.Dengeli ve ReadingSpeed.Detaylı kabul eder. Dize değerinin zaten bilindiği USB tarayıcı girişi için, Dengeli uygundur -- kod çözücü yalnızca formatı doğrulamalı, bir görüntüde barkod aramamalıdır. IronBarcode'un okuma hızı belgelerine göre, Daha hızlı modu bazı bozulma düzeltme algoritmalarını atlar, bu temiz tarayıcı çıkışı için güvenlidir, ancak görüntü tabanlı senaryolarda hasarlı barkodları kaçırabilir.
Aşağıdaki tablo, her hız modunu ne zaman kullanacağınızı özetlemektedir:
| Hız Modu | En İyi Kullanım Amacı | Takas |
|---|---|---|
| Daha hızlı | Temiz USB tarayıcı girişi, yüksek hacimli çıktı | Kötü hasar görmüş veya eğik barkodları gözden kaçırabilir |
| Dengeli | Karışık giriş -- USB tarayıcı ve görüntü ithalatları | Orta CPU kullanımı, iyi doğruluk |
| Detaylı | Hasar görmüş etiketler, düşük kontrastlı baskılar, PDF girişleri | Daha yüksek CPU kullanımı, en yavaş çıktı |
USB tarayıcı girişine ek olarak görüntü veya PDF işleyen uygulamalar için, IronBarcode, PDF belgelerinden barkodları okuyabilir ve çok sayfalı TIFF dosyaları aynı API yüzeyi kullanılarak.

Kenar Durumlar ve Hatalar Tarayıcı Uygulamalarında Nasıl Ele Alınır?
Geliştiriciler Hangi Arıza Modlarını Tahmin Etmelidir?
USB tarayıcı uygulamaları öngörülebilir yollarla başarısız olur. En yaygın sorunlar ve hafifletmeleri şunlardır:
Tarayıcı bağlantısının kesilmesi -- Bir USB tarayıcı çıkarıldığında, klavye kama TextBox'u sanal klavyesini kaybeder. En basit önlem, _inputBox.Focused kontrol eden ve tarayıcı hala bağlı HID aygıtları listesinde yer alıyorsa onu yeniden odaklayan periyodik bir zamanlayıcıdır. Seri tarayıcılar için, SerialPort.GetPortNames() yeniden bağlanmayı algılar.
Belirsiz barkod formatları -- Bazı ürünler birden fazla sembolojide geçerli barkodlar taşır. Örneğin, 12 basamaklı bir dize geçerli bir UPC-A'dir ve aynı zamanda geçerli bir Kod 128'dir. BarcodeReaderOptions'de ExpectBarcodeTypes belirtmek, kod çözücüyü beklenen formatlarınıza kısıtlar ve belirsizliği ortadan kaldırır. IronBarcode sorun giderme kılavuzu, format özelinde tanıma ipuçlarını kapsar.
Geçersiz format istisnaları -- Eğer BarcodeWriter.CreateBarcode seçilen kodlamanın kurallarını ihlal eden bir dize alırsa (örneğin, yalnızca sayısal EAN-13 alanında alfabetik karakterler), bir IronBarCode.Exceptions.InvalidBarcodeException fırlatır. Çağrıyı try-catch içinde sarmak ve sadece dizgi doğrulama yoluna düşmek uygulamanın çalışmaya devam etmesini sağlar.
Tuş vuruşu zamanlama çakışmaları -- Operatörlerin aynı TextBox'a elle yazdığı ortamlarda, önceki açıklanan patlama timer yaklaşımı birincil savunmadır. İkincil bir savunma minimum uzunluktur: çoğu gerçek barkod en az 8 karakter uzunluğundadır, bu nedenle daha kısa dizgiler klavye girişi olarak değerlendirilebilir.
Seri tarayıcı bağlantısını giderirken System.IO.Ports.SerialPort konusundaki Microsoft .NET belgeleri özellikle ReadTimeout ve WriteTimeout ayarları etrafında faydalıdır. Perakende sektörü mevzuat uyumu için, GS1 Genel Spesifikasyonları her uygulama tanımlayıcı için geçerli değer aralıklarını tanımlar.
Uygulama Mobil ve Web Platformlarına Nasıl Genişletilir?
Yukarıda gösterilen tarayıcı arayüz deseni -- IScannerInput ve BarcodeScanned olayı ile -- donanımı işleme mantığından soyutlar. Uygulama değişiklikleri, aynı doğrulama ve oluşturma kodunun farklı platformlarda çalışmasına izin verir:
- .NET MAUI, mobil alım istasyonu olarak kullanılan Android ve iOS tabletlerde kamera tabanlı bir tarayıcı uygulaması sağlar
- Blazor Server, aynı
BarcodeScannedetkinliğine beslenen JavaScript kamera erişimi ile tarayıcı tabanlı taramayı destekler. - Mobil geliştiricilere kamerayla tarama yapma olanağı veren, ancak aynı IronBarcode deşifreleyiciye sahip olan Android ve iOS yerel uygulamaları
bulut tabanlı mimariler için, doğrulama ve etiket oluşturma adımları yalnızca tarayıcı girişi geçişi yapan masaüstü uygulaması olarak bir Azure Fonksiyonları olarak çalıştırılabilir. Bu ayrım, özellikle etiket yazdırma mantığı merkezileştirilmesi gerektiğinde uyumluluk denetimi açısından kullanışlıdır.
Sıradaki Adımlarınız Neler?
IronBarcode ile bir USB barkod tarayıcı uygulaması oluşturmak dört somut aşama içerir: gidip-gelme zamanlaması algılama ile klavye kama girdisini yakalamak, IronBarcode'un dekoderi ile taranan değeri doğrulamak, gerekli biçimde yanıt etiketleri oluşturmak ve eşzamanlı bir kuyrukla yüksek tarama hacimlerini işlemek. Her aşama bağımsızdır ve izole edilmiş olarak test edilebilir.
Buradan, toplu işleme senaryoları için çoklu barkod okuma, görüntü tabanlı girdiler için kırpma bölgesi optimizasyonu, veya eski depo ekipmanları için MSI barkod desteği ile uygulamayı genişletmeyi dikkate alın. IronBarcode dökümantasyonu, tüm desteklenen formatları ve gelişmiş okuyucu yapılandırma seçeneklerini kapsar.
Ücretsiz bir deneme başlatın, bir geliştirme lisans anahtarı alın ve IronBarcode'u tarayıcı uygulamanıza bugün entegre etmeye başlayın.
Sıkça Sorulan Sorular
IronBarcode nedir ve USB barkod tarayıcılarıyla nasıl ilişkilidir?
IronBarcode, geliştiricilerin USB barkod taraması için sağlam C# uygulamaları oluşturmasını sağlayan bir kütüphanedir. Barkod doğrulama, veri çıkarma ve barkod oluşturma gibi özellikler sunar.
IronBarcode, USB tarayıcısından barkod verilerini doğrulayabilir mi?
Evet, IronBarcode USB tarayıcısından alınan barkod verilerini doğrulayabilir, böylece C# uygulamalarınızda veri bütünlüğünü ve doğruluğunu sağlar.
IronBarcode, barkod oluşturmayı nasıl ele alır?
IronBarcode, geliştiricilerin C# uygulamaları içinde kolayca barkod oluşturup yazdırmasına olanak tanıyan uçucu barkodlar oluşturabilir.
USB barkod tarama için IronBarcode'da hata işleme desteği var mı?
Evet, IronBarcode USB barkod tarama ve işlem sırasında ortaya çıkabilecek yaygın sorunları yönetmek için kapsamlı hata işleme içerir.
Hangi tur barkodlar IronBarcode ile taranabilir?
IronBarcode, QR kodlar, UPC, Code 39 ve daha fazlası dahil olmak üzere çeşitli barkod sembolojilerini taramayı destekler, bu da onu çeşitli uygulamalar için çok yönlü kılar.
IronBarcode taranmış barkodlardan yapılandırılmış bilgi çıkarabilir mi?
Evet, IronBarcode taranmış barkodlardan yapılandırılmış bilgiyi çıkarabilir, bu da verimli veri işleme ve yönetimine yardımcı olur.
C# ile bir USB barkod tarayıcı uygulaması oluşturmaya nasıl başlayabilirim?
C# ile USB barkod tarayıcı uygulaması oluşturmaya başlamak için IronBarcode'u kullanabilir ve geliştirmenizi yönlendirmek için sağlanan kod örneklerini ve belgeleri kullanabilirsiniz.




