使用 IRONBARCODE 使用 IronBarcode 建立 C# 掃描器 API Curtis Chau 發表日期:2026年1月21日 下載 IronBarcode NuGet 下載 DLL 下載 開始免費試用 法學碩士副本 法學碩士副本 將頁面複製為 Markdown 格式,用於 LLMs 在 ChatGPT 中打開 請向 ChatGPT 諮詢此頁面 在雙子座打開 請向 Gemini 詢問此頁面 在 Grok 中打開 向 Grok 詢問此頁面 打開困惑 向 Perplexity 詢問有關此頁面的信息 分享 在 Facebook 上分享 分享到 X(Twitter) 在 LinkedIn 上分享 複製連結 電子郵件文章 使用 IronBarcode 和 ASP.NET Core 建立一個 RESTful 條碼掃描器 API,無需硬體即可管理來自影像、PDF 和損壞掃描的條碼,確保在 Windows、Linux 和 macOS 上具有可靠的效能。 IronBarcode 透過 ASP.NET Core 中的 RESTful API 實現專業的條碼掃描,無需硬體依賴即可處理影像、PDF 和損壞的掃描件,同時支援跨平台部署,並具有內建的安全性和合規性功能。 企業條碼挑戰 想像一下,你是財富 500 強物流公司的企業架構師。 您的倉庫團隊正為損壞的運輸標籤而苦惱,您的財務部門需要處理數千份帶有嵌入式條碼的發票 PDF 文件,而您的 IT 安全團隊則要求找到一種符合 SOC2 合規性且不會在您的全球基礎架構中引入硬體依賴性的解決方案。 這種情況促使我們的一位企業客戶發現了IronBarcode的 REST API 功能。 最初只是一個簡單的讀取條碼的需求,後來發展成為一個完整的掃描解決方案,現在每月在整個組織內處理超過 200 萬個條碼。 傳統上,這需要在每個地點配備昂貴的硬體掃描器、複雜的驅動程式管理以及大量的安全審查。 相反,他們建立了一個集中式 RESTful API,任何部門都可以安全地存取該 API,無論是掃描損壞的倉庫標籤還是從供應商 PDF 中提取發票資料。 本教學將引導您建立相同的專業條碼掃描器 API。 您將學習如何創建安全的端點,以應對現實世界的挑戰,例如撕破的標籤、傾斜的圖像和多頁文件。 更重要的是,您將了解如何在滿足企業環境所需的安全性、可擴展性和供應商穩定性的前提下實現這一點。 建立可靠的 C# 掃描器 API 建立企業級條碼掃描器 API 需要預先解決幾個關鍵問題。 安全團隊需要對資料處理方式得到保證。 合規官需要審計追蹤記錄。 維運團隊要求不同平台之間具備可靠性。 IronBarcode 的完整文件有系統地解決了所有這些問題。 RESTful 方法的優點在於其簡潔性和安全性。 透過將條碼處理集中在安全的 API 端點之後,您可以完全控制資料流。 用戶端設備無需直接存取您的條碼處理邏輯。 該架構自然支援您的零信任安全模型,同時能夠與現有企業系統無縫整合。 讓我們從基礎開始。 IronBarcode 的讀取功能支援您的企業可能遇到的所有主要條碼格式。 從製造業中使用的傳統Code 39 條碼到行銷活動中使用的現代二維碼,該程式庫都能處理。 支援的條碼格式指南為您的實施方案規劃提供了完整的參考。 該庫的容錯能力使其在企業場景中特別有價值。 現實世界中的條碼並不完美。 它們可能會損壞、印刷品質差或掃描角度不對。 IronBarcode 的先進影像處理技術可自動應對這些挑戰,從而減少支援工單並提高營運效率。 安裝和設定 IronBarcode 企業部署需要仔細考慮依賴關係和授權問題。 IronBarcode 以簡單的 NuGet 安裝和透明的許可方式簡化了這個過程。 以下是如何開始您的 ASP.NET Core 專案: Install-Package IronBarCode Install-Package IronBarCode SHELL 對於有特定平台需求的企業環境,請參閱進階 NuGet 安裝指南。 這涵蓋了諸如針對特定 .NET 版本或針對特定平台進行最佳化等場景。 安裝完成後,透過簡單的測試來驗證您的設定。以下程式碼示範了該程式庫在極少配置下讀取條碼的能力: using IronBarCode; // Verify installation with a basic barcode read public class InstallationTest { public static void VerifySetup() { try { // Test with a sample barcode image var result = BarcodeReader.Read("test-barcode.png"); if (result.Any()) { Console.WriteLine($"Success! Detected: {result.First().Value}"); Console.WriteLine($"Format: {result.First().BarcodeType}"); Console.WriteLine($"Confidence: {result.First().Confidence}%"); } else { Console.WriteLine("No barcode detected in test image"); } } catch (Exception ex) { Console.WriteLine($"Setup issue: {ex.Message}"); } } } using IronBarCode; // Verify installation with a basic barcode read public class InstallationTest { public static void VerifySetup() { try { // Test with a sample barcode image var result = BarcodeReader.Read("test-barcode.png"); if (result.Any()) { Console.WriteLine($"Success! Detected: {result.First().Value}"); Console.WriteLine($"Format: {result.First().BarcodeType}"); Console.WriteLine($"Confidence: {result.First().Confidence}%"); } else { Console.WriteLine("No barcode detected in test image"); } } catch (Exception ex) { Console.WriteLine($"Setup issue: {ex.Message}"); } } } Imports IronBarCode ' Verify installation with a basic barcode read Public Class InstallationTest Public Shared Sub VerifySetup() Try ' Test with a sample barcode image Dim result = BarcodeReader.Read("test-barcode.png") If result.Any() Then Console.WriteLine($"Success! Detected: {result.First().Value}") Console.WriteLine($"Format: {result.First().BarcodeType}") Console.WriteLine($"Confidence: {result.First().Confidence}%") Else Console.WriteLine("No barcode detected in test image") End If Catch ex As Exception Console.WriteLine($"Setup issue: {ex.Message}") End Try End Sub End Class $vbLabelText $csharpLabel 此驗證步驟對於企業部署至關重要。 它確認該庫已正確安裝、獲得許可,並且可以存取必要的系統資源。 置信度評分輸出有助於為您的特定條碼類型建立基準預期。 對於生產環境部署,請仔細閱讀許可文件。 企業許可證支援在您的組織內進行無限次部署,這對於跨多個資料中心進行擴展至關重要。 許可證金鑰配置指南解釋了各種啟動方法,包括符合您的DevOps實務的環境變數和設定檔。 企業平台相容性 您的企業很可能運作的是一個異質環境。 開發工作在 Windows 系統上進行,測試環境運行在 Linux 容器上,有些團隊可能會使用 macOS 系統。 IronBarcode 的跨平台相容性確保了在所有這些平台上行為的一致性。 對於容器化部署, Docker 設定指南提供了針對 Linux 容器的具體說明。 這包括處理依賴關係和優化鏡像大小以實現高效的雲端部署。 如果您要部署到Azure或AWS Lambda ,平台特定的指南可確保在這些環境中獲得最佳效能。 該庫甚至透過.NET MAUI 整合支援行動場景,使您能夠在現場工作人員需要行動掃描功能時,將條碼掃描功能擴展到iOS和Android設備。 建立完整的掃描器 API 控制器 讓我們建立一個能夠滿足企業實際需求、可用於生產環境的掃描器 API。 此實現方案包含了適當的錯誤處理、安全考量和效能最佳化: using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using IronBarCode; using System.Drawing; using System.ComponentModel.DataAnnotations; namespace BarcodeScannerAPI.Controllers { [ApiController] [Route("api/v1/[controller]")] [Authorize] // Require authentication for all endpoints public class ScannerController : ControllerBase { private readonly ILogger<ScannerController> _logger; private readonly IConfiguration _configuration; public ScannerController(ILogger<ScannerController> logger, IConfiguration configuration) { _logger = logger; _configuration = configuration; } // Enhanced result model with audit fields public class ScanResult { public bool Success { get; set; } public List<BarcodeData> Barcodes { get; set; } = new List<BarcodeData>(); public string RequestId { get; set; } = Guid.NewGuid().ToString(); public DateTime ProcessedAt { get; set; } = DateTime.UtcNow; public long ProcessingTimeMs { get; set; } public string ErrorMessage { get; set; } public Dictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>(); } public class BarcodeData { public string Value { get; set; } public string Format { get; set; } public double Confidence { get; set; } public Rectangle Location { get; set; } public int PageNumber { get; set; } // For PDF processing } // Input validation model public class ScanRequest { [Required] public IFormFile File { get; set; } [Range(1, 10)] public int MaxBarcodes { get; set; } = 5; public string[] ExpectedFormats { get; set; } public bool EnableImageCorrection { get; set; } = true; } [HttpPost("scan")] [RequestSizeLimit(52428800)] // 50MB limit public async Task<ActionResult<ScanResult>> ScanDocument([FromForm] ScanRequest request) { var stopwatch = System.Diagnostics.Stopwatch.StartNew(); var result = new ScanResult(); try { // Validate file type for security var allowedExtensions = new[] { ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".tiff", ".bmp" }; var fileExtension = Path.GetExtension(request.File.FileName).ToLowerInvariant(); if (!allowedExtensions.Contains(fileExtension)) { _logger.LogWarning($"Rejected file type: {fileExtension}"); return BadRequest(new ScanResult { Success = false, ErrorMessage = "Unsupported file type. Allowed: PDF, PNG, JPG, GIF, TIFF, BMP" }); } // Process the file using var stream = new MemoryStream(); await request.File.CopyToAsync(stream); var fileBytes = stream.ToArray(); // Log for audit trail _logger.LogInformation($"Processing {request.File.FileName} ({fileBytes.Length} bytes) - RequestId: {result.RequestId}"); // Configure scanner based on requirements var options = ConfigureOptions(request); // Handle different file types BarcodeResults scanResults; if (fileExtension == ".pdf") { var pdfOptions = new PdfBarcodeReaderOptions { Scale = 3, DPI = 300, MaxThreads = 4 }; scanResults = BarcodeReader.ReadPdf(fileBytes, pdfOptions); } else { scanResults = BarcodeReader.Read(fileBytes, options); } // Process results if (scanResults.Any()) { result.Success = true; foreach (var barcode in scanResults.Take(request.MaxBarcodes)) { result.Barcodes.Add(new BarcodeData { Value = barcode.Value, Format = barcode.BarcodeType.ToString(), Confidence = barcode.Confidence, Location = barcode.Bounds, PageNumber = barcode.PageNumber }); } result.Metadata["TotalFound"] = scanResults.Count(); result.Metadata["FileSize"] = fileBytes.Length; result.Metadata["FileName"] = request.File.FileName; _logger.LogInformation($"Successfully scanned {scanResults.Count()} barcodes - RequestId: {result.RequestId}"); } else { result.Success = false; result.ErrorMessage = "No barcodes detected in the document"; _logger.LogWarning($"No barcodes found - RequestId: {result.RequestId}"); } } catch (Exception ex) { _logger.LogError(ex, $"Scanning error - RequestId: {result.RequestId}"); result.Success = false; result.ErrorMessage = "An error occurred during processing"; // Don't expose internal errors to clients if (_configuration.GetValue<bool>("DetailedErrors")) { result.Metadata["Exception"] = ex.Message; } } finally { stopwatch.Stop(); result.ProcessingTimeMs = stopwatch.ElapsedMilliseconds; } return result; } private BarcodeReaderOptions ConfigureOptions(ScanRequest request) { var options = new BarcodeReaderOptions { Speed = ReadingSpeed.Balanced, ExpectMultipleBarcodes = request.MaxBarcodes > 1, RemoveFalsePositive = true, Multithreaded = true, MaxParallelThreads = Environment.ProcessorCount }; // Apply format filtering if specified if (request.ExpectedFormats?.Any() == true) { var formats = BarcodeEncoding.None; foreach (var format in request.ExpectedFormats) { if (Enum.TryParse<BarcodeEncoding>(format, true, out var encoding)) { formats |= encoding; } } options.ExpectBarcodeTypes = formats; } // Enable image correction for damaged barcodes if (request.EnableImageCorrection) { options.ImageFilters = new ImageFilterCollection { new SharpenFilter(2), new ContrastFilter(1.5f), new BrightnessFilter(1.1f) }; options.AutoRotate = true; } return options; } // Batch processing endpoint for high-volume scenarios [HttpPost("scan-batch")] [RequestSizeLimit(524288000)] // 500MB for batch operations public async Task<ActionResult<List<ScanResult>>> ScanBatch(List<IFormFile> files) { if (files == null || !files.Any()) { return BadRequest("No files provided"); } if (files.Count > 50) { return BadRequest("Maximum 50 files per batch"); } var tasks = files.Select(file => ProcessFileAsync(file)); var results = await Task.WhenAll(tasks); _logger.LogInformation($"Batch processed {files.Count} files, {results.Count(r => r.Success)} successful"); return Ok(results); } private async Task<ScanResult> ProcessFileAsync(IFormFile file) { // Reuse the scanning logic var request = new ScanRequest { File = file, EnableImageCorrection = true }; var actionResult = await ScanDocument(request); if (actionResult.Result is OkObjectResult okResult) { return okResult.Value as ScanResult; } else if (actionResult.Result is BadRequestObjectResult badResult) { return badResult.Value as ScanResult; } return new ScanResult { Success = false, ErrorMessage = "Processing failed" }; } } } using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using IronBarCode; using System.Drawing; using System.ComponentModel.DataAnnotations; namespace BarcodeScannerAPI.Controllers { [ApiController] [Route("api/v1/[controller]")] [Authorize] // Require authentication for all endpoints public class ScannerController : ControllerBase { private readonly ILogger<ScannerController> _logger; private readonly IConfiguration _configuration; public ScannerController(ILogger<ScannerController> logger, IConfiguration configuration) { _logger = logger; _configuration = configuration; } // Enhanced result model with audit fields public class ScanResult { public bool Success { get; set; } public List<BarcodeData> Barcodes { get; set; } = new List<BarcodeData>(); public string RequestId { get; set; } = Guid.NewGuid().ToString(); public DateTime ProcessedAt { get; set; } = DateTime.UtcNow; public long ProcessingTimeMs { get; set; } public string ErrorMessage { get; set; } public Dictionary<string, object> Metadata { get; set; } = new Dictionary<string, object>(); } public class BarcodeData { public string Value { get; set; } public string Format { get; set; } public double Confidence { get; set; } public Rectangle Location { get; set; } public int PageNumber { get; set; } // For PDF processing } // Input validation model public class ScanRequest { [Required] public IFormFile File { get; set; } [Range(1, 10)] public int MaxBarcodes { get; set; } = 5; public string[] ExpectedFormats { get; set; } public bool EnableImageCorrection { get; set; } = true; } [HttpPost("scan")] [RequestSizeLimit(52428800)] // 50MB limit public async Task<ActionResult<ScanResult>> ScanDocument([FromForm] ScanRequest request) { var stopwatch = System.Diagnostics.Stopwatch.StartNew(); var result = new ScanResult(); try { // Validate file type for security var allowedExtensions = new[] { ".pdf", ".png", ".jpg", ".jpeg", ".gif", ".tiff", ".bmp" }; var fileExtension = Path.GetExtension(request.File.FileName).ToLowerInvariant(); if (!allowedExtensions.Contains(fileExtension)) { _logger.LogWarning($"Rejected file type: {fileExtension}"); return BadRequest(new ScanResult { Success = false, ErrorMessage = "Unsupported file type. Allowed: PDF, PNG, JPG, GIF, TIFF, BMP" }); } // Process the file using var stream = new MemoryStream(); await request.File.CopyToAsync(stream); var fileBytes = stream.ToArray(); // Log for audit trail _logger.LogInformation($"Processing {request.File.FileName} ({fileBytes.Length} bytes) - RequestId: {result.RequestId}"); // Configure scanner based on requirements var options = ConfigureOptions(request); // Handle different file types BarcodeResults scanResults; if (fileExtension == ".pdf") { var pdfOptions = new PdfBarcodeReaderOptions { Scale = 3, DPI = 300, MaxThreads = 4 }; scanResults = BarcodeReader.ReadPdf(fileBytes, pdfOptions); } else { scanResults = BarcodeReader.Read(fileBytes, options); } // Process results if (scanResults.Any()) { result.Success = true; foreach (var barcode in scanResults.Take(request.MaxBarcodes)) { result.Barcodes.Add(new BarcodeData { Value = barcode.Value, Format = barcode.BarcodeType.ToString(), Confidence = barcode.Confidence, Location = barcode.Bounds, PageNumber = barcode.PageNumber }); } result.Metadata["TotalFound"] = scanResults.Count(); result.Metadata["FileSize"] = fileBytes.Length; result.Metadata["FileName"] = request.File.FileName; _logger.LogInformation($"Successfully scanned {scanResults.Count()} barcodes - RequestId: {result.RequestId}"); } else { result.Success = false; result.ErrorMessage = "No barcodes detected in the document"; _logger.LogWarning($"No barcodes found - RequestId: {result.RequestId}"); } } catch (Exception ex) { _logger.LogError(ex, $"Scanning error - RequestId: {result.RequestId}"); result.Success = false; result.ErrorMessage = "An error occurred during processing"; // Don't expose internal errors to clients if (_configuration.GetValue<bool>("DetailedErrors")) { result.Metadata["Exception"] = ex.Message; } } finally { stopwatch.Stop(); result.ProcessingTimeMs = stopwatch.ElapsedMilliseconds; } return result; } private BarcodeReaderOptions ConfigureOptions(ScanRequest request) { var options = new BarcodeReaderOptions { Speed = ReadingSpeed.Balanced, ExpectMultipleBarcodes = request.MaxBarcodes > 1, RemoveFalsePositive = true, Multithreaded = true, MaxParallelThreads = Environment.ProcessorCount }; // Apply format filtering if specified if (request.ExpectedFormats?.Any() == true) { var formats = BarcodeEncoding.None; foreach (var format in request.ExpectedFormats) { if (Enum.TryParse<BarcodeEncoding>(format, true, out var encoding)) { formats |= encoding; } } options.ExpectBarcodeTypes = formats; } // Enable image correction for damaged barcodes if (request.EnableImageCorrection) { options.ImageFilters = new ImageFilterCollection { new SharpenFilter(2), new ContrastFilter(1.5f), new BrightnessFilter(1.1f) }; options.AutoRotate = true; } return options; } // Batch processing endpoint for high-volume scenarios [HttpPost("scan-batch")] [RequestSizeLimit(524288000)] // 500MB for batch operations public async Task<ActionResult<List<ScanResult>>> ScanBatch(List<IFormFile> files) { if (files == null || !files.Any()) { return BadRequest("No files provided"); } if (files.Count > 50) { return BadRequest("Maximum 50 files per batch"); } var tasks = files.Select(file => ProcessFileAsync(file)); var results = await Task.WhenAll(tasks); _logger.LogInformation($"Batch processed {files.Count} files, {results.Count(r => r.Success)} successful"); return Ok(results); } private async Task<ScanResult> ProcessFileAsync(IFormFile file) { // Reuse the scanning logic var request = new ScanRequest { File = file, EnableImageCorrection = true }; var actionResult = await ScanDocument(request); if (actionResult.Result is OkObjectResult okResult) { return okResult.Value as ScanResult; } else if (actionResult.Result is BadRequestObjectResult badResult) { return badResult.Value as ScanResult; } return new ScanResult { Success = false, ErrorMessage = "Processing failed" }; } } } Imports Microsoft.AspNetCore.Mvc Imports Microsoft.AspNetCore.Authorization Imports IronBarCode Imports System.Drawing Imports System.ComponentModel.DataAnnotations Namespace BarcodeScannerAPI.Controllers <ApiController> <Route("api/v1/[controller]")> <Authorize> Public Class ScannerController Inherits ControllerBase Private ReadOnly _logger As ILogger(Of ScannerController) Private ReadOnly _configuration As IConfiguration Public Sub New(logger As ILogger(Of ScannerController), configuration As IConfiguration) _logger = logger _configuration = configuration End Sub ' Enhanced result model with audit fields Public Class ScanResult Public Property Success As Boolean Public Property Barcodes As List(Of BarcodeData) = New List(Of BarcodeData)() Public Property RequestId As String = Guid.NewGuid().ToString() Public Property ProcessedAt As DateTime = DateTime.UtcNow Public Property ProcessingTimeMs As Long Public Property ErrorMessage As String Public Property Metadata As Dictionary(Of String, Object) = New Dictionary(Of String, Object)() End Class Public Class BarcodeData Public Property Value As String Public Property Format As String Public Property Confidence As Double Public Property Location As Rectangle Public Property PageNumber As Integer End Class ' Input validation model Public Class ScanRequest <Required> Public Property File As IFormFile <Range(1, 10)> Public Property MaxBarcodes As Integer = 5 Public Property ExpectedFormats As String() Public Property EnableImageCorrection As Boolean = True End Class <HttpPost("scan")> <RequestSizeLimit(52428800)> Public Async Function ScanDocument(<FromForm> request As ScanRequest) As Task(Of ActionResult(Of ScanResult)) Dim stopwatch = System.Diagnostics.Stopwatch.StartNew() Dim result = New ScanResult() Try ' Validate file type for security Dim allowedExtensions = {".pdf", ".png", ".jpg", ".jpeg", ".gif", ".tiff", ".bmp"} Dim fileExtension = Path.GetExtension(request.File.FileName).ToLowerInvariant() If Not allowedExtensions.Contains(fileExtension) Then _logger.LogWarning($"Rejected file type: {fileExtension}") Return BadRequest(New ScanResult With { .Success = False, .ErrorMessage = "Unsupported file type. Allowed: PDF, PNG, JPG, GIF, TIFF, BMP" }) End If ' Process the file Using stream = New MemoryStream() Await request.File.CopyToAsync(stream) Dim fileBytes = stream.ToArray() ' Log for audit trail _logger.LogInformation($"Processing {request.File.FileName} ({fileBytes.Length} bytes) - RequestId: {result.RequestId}") ' Configure scanner based on requirements Dim options = ConfigureOptions(request) ' Handle different file types Dim scanResults As BarcodeResults If fileExtension = ".pdf" Then Dim pdfOptions = New PdfBarcodeReaderOptions With { .Scale = 3, .DPI = 300, .MaxThreads = 4 } scanResults = BarcodeReader.ReadPdf(fileBytes, pdfOptions) Else scanResults = BarcodeReader.Read(fileBytes, options) End If ' Process results If scanResults.Any() Then result.Success = True For Each barcode In scanResults.Take(request.MaxBarcodes) result.Barcodes.Add(New BarcodeData With { .Value = barcode.Value, .Format = barcode.BarcodeType.ToString(), .Confidence = barcode.Confidence, .Location = barcode.Bounds, .PageNumber = barcode.PageNumber }) Next result.Metadata("TotalFound") = scanResults.Count() result.Metadata("FileSize") = fileBytes.Length result.Metadata("FileName") = request.File.FileName _logger.LogInformation($"Successfully scanned {scanResults.Count()} barcodes - RequestId: {result.RequestId}") Else result.Success = False result.ErrorMessage = "No barcodes detected in the document" _logger.LogWarning($"No barcodes found - RequestId: {result.RequestId}") End If End Using Catch ex As Exception _logger.LogError(ex, $"Scanning error - RequestId: {result.RequestId}") result.Success = False result.ErrorMessage = "An error occurred during processing" ' Don't expose internal errors to clients If _configuration.GetValue(Of Boolean)("DetailedErrors") Then result.Metadata("Exception") = ex.Message End If Finally stopwatch.Stop() result.ProcessingTimeMs = stopwatch.ElapsedMilliseconds End Try Return result End Function Private Function ConfigureOptions(request As ScanRequest) As BarcodeReaderOptions Dim options = New BarcodeReaderOptions With { .Speed = ReadingSpeed.Balanced, .ExpectMultipleBarcodes = request.MaxBarcodes > 1, .RemoveFalsePositive = True, .Multithreaded = True, .MaxParallelThreads = Environment.ProcessorCount } ' Apply format filtering if specified If request.ExpectedFormats?.Any() = True Then Dim formats = BarcodeEncoding.None For Each format In request.ExpectedFormats Dim encoding As BarcodeEncoding If [Enum].TryParse(format, True, encoding) Then formats = formats Or encoding End If Next options.ExpectBarcodeTypes = formats End If ' Enable image correction for damaged barcodes If request.EnableImageCorrection Then options.ImageFilters = New ImageFilterCollection From { New SharpenFilter(2), New ContrastFilter(1.5F), New BrightnessFilter(1.1F) } options.AutoRotate = True End If Return options End Function ' Batch processing endpoint for high-volume scenarios <HttpPost("scan-batch")> <RequestSizeLimit(524288000)> Public Async Function ScanBatch(files As List(Of IFormFile)) As Task(Of ActionResult(Of List(Of ScanResult))) If files Is Nothing OrElse Not files.Any() Then Return BadRequest("No files provided") End If If files.Count > 50 Then Return BadRequest("Maximum 50 files per batch") End If Dim tasks = files.Select(Function(file) ProcessFileAsync(file)) Dim results = Await Task.WhenAll(tasks) _logger.LogInformation($"Batch processed {files.Count} files, {results.Count(Function(r) r.Success)} successful") Return Ok(results) End Function Private Async Function ProcessFileAsync(file As IFormFile) As Task(Of ScanResult) ' Reuse the scanning logic Dim request = New ScanRequest With { .File = file, .EnableImageCorrection = True } Dim actionResult = Await ScanDocument(request) If TypeOf actionResult.Result Is OkObjectResult Then Return DirectCast(actionResult.Result, OkObjectResult).Value ElseIf TypeOf actionResult.Result Is BadRequestObjectResult Then Return DirectCast(actionResult.Result, BadRequestObjectResult).Value End If Return New ScanResult With { .Success = False, .ErrorMessage = "Processing failed" } End Function End Class End Namespace $vbLabelText $csharpLabel 此專業版本包含生產部署所需的多項關鍵功能。身份驗證可確保只有授權使用者才能存取掃描服務。請求大小限制可防止拒絕服務攻擊。 完整的日誌記錄為合規團隊提供了所需的審計追蹤。 結構化回應模型不僅傳回條碼值,還傳回置信度分數和位置資料。 這些元資料對於品質保證流程來說非常寶貴。 當供應商的條碼掃描置信度較低時,您的系統可以將其標記為需要人工審核。 專業錯誤處理 請注意,控制器從未向客戶端公開內部異常詳細資訊。 這符合安全最佳實踐,可以防止資訊外洩。 詳細的日誌記錄可以捕獲調試所需的所有信息,同時保持錯誤回應的通用性。 RequestId欄位支援跨分散式系統進行端到端追蹤。 當倉庫工人回報掃描問題時,您的支援團隊可以快速在集中式日誌系統中找到確切的請求。 這大大縮短了生產問題的平均解決時間(MTTR)。 透過ProcessingTimeMs進行效能監控有助於識別瓶頸。 如果某些條碼類型的處理時間總是較長,您可以相應地調整讀取速度設定。 閱讀速度範例展示了不同的設定如何影響效能。 處理不同的輸入來源 企業系統很少採用單一標準格式。 您的掃描器 API 需要處理從高解析度倉庫攝影機到幾十年前傳真機產生的低品質 PDF 掃描件的所有資料。 以下是如何建構這種靈活性的方法: // Extended controller with multiple input handlers [ApiController] [Route("api/v1/[controller]")] [Authorize] public class AdvancedScannerController : ControllerBase { private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<AdvancedScannerController> _logger; public AdvancedScannerController( IHttpClientFactory httpClientFactory, ILogger<AdvancedScannerController> logger) { _httpClientFactory = httpClientFactory; _logger = logger; } // Handle Base64 input (common in web applications) [HttpPost("scan-base64")] public ActionResult<ScanResult> ScanBase64([FromBody] Base64Request request) { if (!ModelState.IsValid) { return BadRequest(ModelState); } try { // Validate Base64 format var base64Data = request.ImageData; if (base64Data.Contains(",")) { // Handle data URL format: "data:image/png;base64,..." base64Data = base64Data.Substring(base64Data.IndexOf(",") + 1); } var imageBytes = Convert.FromBase64String(base64Data); // Implement size validation if (imageBytes.Length > 10 * 1024 * 1024) // 10MB limit { return BadRequest(new ScanResult { Success = false, ErrorMessage = "Image size exceeds 10MB limit" }); } // Configure for web-uploaded images (often lower quality) var options = new BarcodeReaderOptions { Speed = ReadingSpeed.Detailed, ImageFilters = new ImageFilterCollection { new SharpenFilter(3), new ContrastFilter(2), new DeNoise() }, TryInvertColor = true, // Handle inverted barcodes AutoRotate = true }; var results = BarcodeReader.Read(imageBytes, options); return ProcessResults(results, "base64", request.FileName); } catch (FormatException) { return BadRequest(new ScanResult { Success = false, ErrorMessage = "Invalid Base64 format" }); } } // Handle URL input (for cloud storage integration) [HttpPost("scan-url")] public async Task<ActionResult<ScanResult>> ScanFromUrl([FromBody] UrlScanRequest request) { if (!Uri.TryCreate(request.Url, UriKind.Absolute, out var uri)) { return BadRequest(new ScanResult { Success = false, ErrorMessage = "Invalid URL format" }); } // Validate URL domain (security measure) var allowedDomains = _configuration.GetSection("AllowedDomains").Get<string[]>() ?? new[] { "blob.core.windows.net", "s3.amazonaws.com" }; if (!allowedDomains.Any(domain => uri.Host.EndsWith(domain))) { _logger.LogWarning($"Rejected URL from unauthorized domain: {uri.Host}"); return BadRequest(new ScanResult { Success = false, ErrorMessage = "URL domain not authorized" }); } try { using var httpClient = _httpClientFactory.CreateClient("BarcodeScanner"); httpClient.Timeout = TimeSpan.FromSeconds(30); // Add headers to avoid being blocked httpClient.DefaultRequestHeaders.Add("User-Agent", "BarcodeScannerAPI/2.0"); var response = await httpClient.GetAsync(uri); response.EnsureSuccessStatusCode(); // Check content type var contentType = response.Content.Headers.ContentType?.MediaType; if (!IsValidContentType(contentType)) { return BadRequest(new ScanResult { Success = false, ErrorMessage = $"Unsupported content type: {contentType}" }); } var imageBytes = await response.Content.ReadAsByteArrayAsync(); // Use async processing for better scalability var results = await BarcodeReader.ReadAsync(imageBytes); return ProcessResults(results, "url", uri.ToString()); } catch (HttpRequestException ex) { _logger.LogError(ex, $"Failed to download from URL: {uri}"); return BadRequest(new ScanResult { Success = false, ErrorMessage = "Failed to download image from URL" }); } catch (TaskCanceledException) { return BadRequest(new ScanResult { Success = false, ErrorMessage = "Download timeout - file too large or slow connection" }); } } // Handle multi-page PDFs with page-specific processing [HttpPost("scan-pdf-advanced")] public async Task<ActionResult<PdfScanResult>> ScanPdfAdvanced([FromForm] PdfScanRequest request) { using var stream = new MemoryStream(); await request.File.CopyToAsync(stream); var pdfOptions = new PdfBarcodeReaderOptions { Scale = request.Scale ?? 3, DPI = request.DPI ?? 300, PageNumbers = request.PageNumbers, Password = request.Password, MaxThreads = Math.Min(request.MaxThreads ?? 4, Environment.ProcessorCount) }; // For large PDFs, process in chunks if (stream.Length > 50 * 1024 * 1024) // 50MB { _logger.LogInformation($"Large PDF detected ({stream.Length / 1024 / 1024}MB), using chunked processing"); pdfOptions.MaxThreads = 2; // Reduce memory pressure } var results = BarcodeReader.ReadPdf(stream.ToArray(), pdfOptions); // Group results by page var pageResults = results.GroupBy(r => r.PageNumber) .OrderBy(g => g.Key) .Select(g => new PageBarcodeResult { PageNumber = g.Key, BarcodeCount = g.Count(), Barcodes = g.Select(b => new BarcodeData { Value = b.Value, Format = b.BarcodeType.ToString(), Confidence = b.Confidence, Location = b.Bounds }).ToList() }).ToList(); return Ok(new PdfScanResult { Success = true, TotalPages = pageResults.Count, TotalBarcodes = results.Count(), PageResults = pageResults, RequestId = Guid.NewGuid().ToString() }); } // Handle damaged or low-quality barcodes [HttpPost("scan-damaged")] public async Task<ActionResult<ScanResult>> ScanDamagedBarcode([FromForm] IFormFile file) { using var stream = new MemoryStream(); await file.CopyToAsync(stream); // Aggressive image correction for damaged barcodes var options = new BarcodeReaderOptions { Speed = ReadingSpeed.ExtremeDetail, ImageFilters = new ImageFilterCollection { new SharpenFilter(4), new ContrastFilter(3), new BrightnessFilter(1.5f), new BinaryThresholdFilter(128), new DeNoise(3) }, TryInvertColor = true, AutoRotate = true, UseCode39ExtendedMode = true, RemoveFalsePositive = false, // Accept lower confidence Confidence = ConfidenceLevel.Low }; var results = BarcodeReader.Read(stream.ToArray(), options); // If still no results, try with different threshold if (!results.Any()) { options.ImageFilters = new ImageFilterCollection { new AdaptiveThresholdFilter(9), new MedianFilter(3), new Dilate(1) }; results = BarcodeReader.Read(stream.ToArray(), options); } return ProcessResults(results, "damaged", file.FileName); } private bool IsValidContentType(string contentType) { var validTypes = new[] { "image/jpeg", "image/jpg", "image/png", "image/gif", "image/tiff", "image/bmp", "application/pdf" }; return validTypes.Contains(contentType?.ToLower()); } private ActionResult<ScanResult> ProcessResults(BarcodeResults results, string source, string identifier) { var scanResult = new ScanResult { Metadata = new Dictionary<string, object> { ["Source"] = source, ["Identifier"] = identifier, ["ProcessedAt"] = DateTime.UtcNow } }; if (results.Any()) { scanResult.Success = true; scanResult.Barcodes = results.Select(r => new BarcodeData { Value = r.Value, Format = r.BarcodeType.ToString(), Confidence = r.Confidence, Location = r.Bounds }).ToList(); // Log low confidence results for quality monitoring var lowConfidence = results.Where(r => r.Confidence < 70).ToList(); if (lowConfidence.Any()) { _logger.LogWarning($"Low confidence barcodes detected: {lowConfidence.Count} of {results.Count()} from {identifier}"); } } else { scanResult.Success = false; scanResult.ErrorMessage = "No barcodes detected"; } return Ok(scanResult); } } // Request models public class Base64Request { [Required] public string ImageData { get; set; } public string FileName { get; set; } } public class UrlScanRequest { [Required] [Url] public string Url { get; set; } } public class PdfScanRequest { [Required] public IFormFile File { get; set; } public int? Scale { get; set; } public int? DPI { get; set; } public int[] PageNumbers { get; set; } public string Password { get; set; } public int? MaxThreads { get; set; } } // Response models public class PdfScanResult : ScanResult { public int TotalPages { get; set; } public int TotalBarcodes { get; set; } public List<PageBarcodeResult> PageResults { get; set; } } public class PageBarcodeResult { public int PageNumber { get; set; } public int BarcodeCount { get; set; } public List<BarcodeData> Barcodes { get; set; } } // Extended controller with multiple input handlers [ApiController] [Route("api/v1/[controller]")] [Authorize] public class AdvancedScannerController : ControllerBase { private readonly IHttpClientFactory _httpClientFactory; private readonly ILogger<AdvancedScannerController> _logger; public AdvancedScannerController( IHttpClientFactory httpClientFactory, ILogger<AdvancedScannerController> logger) { _httpClientFactory = httpClientFactory; _logger = logger; } // Handle Base64 input (common in web applications) [HttpPost("scan-base64")] public ActionResult<ScanResult> ScanBase64([FromBody] Base64Request request) { if (!ModelState.IsValid) { return BadRequest(ModelState); } try { // Validate Base64 format var base64Data = request.ImageData; if (base64Data.Contains(",")) { // Handle data URL format: "data:image/png;base64,..." base64Data = base64Data.Substring(base64Data.IndexOf(",") + 1); } var imageBytes = Convert.FromBase64String(base64Data); // Implement size validation if (imageBytes.Length > 10 * 1024 * 1024) // 10MB limit { return BadRequest(new ScanResult { Success = false, ErrorMessage = "Image size exceeds 10MB limit" }); } // Configure for web-uploaded images (often lower quality) var options = new BarcodeReaderOptions { Speed = ReadingSpeed.Detailed, ImageFilters = new ImageFilterCollection { new SharpenFilter(3), new ContrastFilter(2), new DeNoise() }, TryInvertColor = true, // Handle inverted barcodes AutoRotate = true }; var results = BarcodeReader.Read(imageBytes, options); return ProcessResults(results, "base64", request.FileName); } catch (FormatException) { return BadRequest(new ScanResult { Success = false, ErrorMessage = "Invalid Base64 format" }); } } // Handle URL input (for cloud storage integration) [HttpPost("scan-url")] public async Task<ActionResult<ScanResult>> ScanFromUrl([FromBody] UrlScanRequest request) { if (!Uri.TryCreate(request.Url, UriKind.Absolute, out var uri)) { return BadRequest(new ScanResult { Success = false, ErrorMessage = "Invalid URL format" }); } // Validate URL domain (security measure) var allowedDomains = _configuration.GetSection("AllowedDomains").Get<string[]>() ?? new[] { "blob.core.windows.net", "s3.amazonaws.com" }; if (!allowedDomains.Any(domain => uri.Host.EndsWith(domain))) { _logger.LogWarning($"Rejected URL from unauthorized domain: {uri.Host}"); return BadRequest(new ScanResult { Success = false, ErrorMessage = "URL domain not authorized" }); } try { using var httpClient = _httpClientFactory.CreateClient("BarcodeScanner"); httpClient.Timeout = TimeSpan.FromSeconds(30); // Add headers to avoid being blocked httpClient.DefaultRequestHeaders.Add("User-Agent", "BarcodeScannerAPI/2.0"); var response = await httpClient.GetAsync(uri); response.EnsureSuccessStatusCode(); // Check content type var contentType = response.Content.Headers.ContentType?.MediaType; if (!IsValidContentType(contentType)) { return BadRequest(new ScanResult { Success = false, ErrorMessage = $"Unsupported content type: {contentType}" }); } var imageBytes = await response.Content.ReadAsByteArrayAsync(); // Use async processing for better scalability var results = await BarcodeReader.ReadAsync(imageBytes); return ProcessResults(results, "url", uri.ToString()); } catch (HttpRequestException ex) { _logger.LogError(ex, $"Failed to download from URL: {uri}"); return BadRequest(new ScanResult { Success = false, ErrorMessage = "Failed to download image from URL" }); } catch (TaskCanceledException) { return BadRequest(new ScanResult { Success = false, ErrorMessage = "Download timeout - file too large or slow connection" }); } } // Handle multi-page PDFs with page-specific processing [HttpPost("scan-pdf-advanced")] public async Task<ActionResult<PdfScanResult>> ScanPdfAdvanced([FromForm] PdfScanRequest request) { using var stream = new MemoryStream(); await request.File.CopyToAsync(stream); var pdfOptions = new PdfBarcodeReaderOptions { Scale = request.Scale ?? 3, DPI = request.DPI ?? 300, PageNumbers = request.PageNumbers, Password = request.Password, MaxThreads = Math.Min(request.MaxThreads ?? 4, Environment.ProcessorCount) }; // For large PDFs, process in chunks if (stream.Length > 50 * 1024 * 1024) // 50MB { _logger.LogInformation($"Large PDF detected ({stream.Length / 1024 / 1024}MB), using chunked processing"); pdfOptions.MaxThreads = 2; // Reduce memory pressure } var results = BarcodeReader.ReadPdf(stream.ToArray(), pdfOptions); // Group results by page var pageResults = results.GroupBy(r => r.PageNumber) .OrderBy(g => g.Key) .Select(g => new PageBarcodeResult { PageNumber = g.Key, BarcodeCount = g.Count(), Barcodes = g.Select(b => new BarcodeData { Value = b.Value, Format = b.BarcodeType.ToString(), Confidence = b.Confidence, Location = b.Bounds }).ToList() }).ToList(); return Ok(new PdfScanResult { Success = true, TotalPages = pageResults.Count, TotalBarcodes = results.Count(), PageResults = pageResults, RequestId = Guid.NewGuid().ToString() }); } // Handle damaged or low-quality barcodes [HttpPost("scan-damaged")] public async Task<ActionResult<ScanResult>> ScanDamagedBarcode([FromForm] IFormFile file) { using var stream = new MemoryStream(); await file.CopyToAsync(stream); // Aggressive image correction for damaged barcodes var options = new BarcodeReaderOptions { Speed = ReadingSpeed.ExtremeDetail, ImageFilters = new ImageFilterCollection { new SharpenFilter(4), new ContrastFilter(3), new BrightnessFilter(1.5f), new BinaryThresholdFilter(128), new DeNoise(3) }, TryInvertColor = true, AutoRotate = true, UseCode39ExtendedMode = true, RemoveFalsePositive = false, // Accept lower confidence Confidence = ConfidenceLevel.Low }; var results = BarcodeReader.Read(stream.ToArray(), options); // If still no results, try with different threshold if (!results.Any()) { options.ImageFilters = new ImageFilterCollection { new AdaptiveThresholdFilter(9), new MedianFilter(3), new Dilate(1) }; results = BarcodeReader.Read(stream.ToArray(), options); } return ProcessResults(results, "damaged", file.FileName); } private bool IsValidContentType(string contentType) { var validTypes = new[] { "image/jpeg", "image/jpg", "image/png", "image/gif", "image/tiff", "image/bmp", "application/pdf" }; return validTypes.Contains(contentType?.ToLower()); } private ActionResult<ScanResult> ProcessResults(BarcodeResults results, string source, string identifier) { var scanResult = new ScanResult { Metadata = new Dictionary<string, object> { ["Source"] = source, ["Identifier"] = identifier, ["ProcessedAt"] = DateTime.UtcNow } }; if (results.Any()) { scanResult.Success = true; scanResult.Barcodes = results.Select(r => new BarcodeData { Value = r.Value, Format = r.BarcodeType.ToString(), Confidence = r.Confidence, Location = r.Bounds }).ToList(); // Log low confidence results for quality monitoring var lowConfidence = results.Where(r => r.Confidence < 70).ToList(); if (lowConfidence.Any()) { _logger.LogWarning($"Low confidence barcodes detected: {lowConfidence.Count} of {results.Count()} from {identifier}"); } } else { scanResult.Success = false; scanResult.ErrorMessage = "No barcodes detected"; } return Ok(scanResult); } } // Request models public class Base64Request { [Required] public string ImageData { get; set; } public string FileName { get; set; } } public class UrlScanRequest { [Required] [Url] public string Url { get; set; } } public class PdfScanRequest { [Required] public IFormFile File { get; set; } public int? Scale { get; set; } public int? DPI { get; set; } public int[] PageNumbers { get; set; } public string Password { get; set; } public int? MaxThreads { get; set; } } // Response models public class PdfScanResult : ScanResult { public int TotalPages { get; set; } public int TotalBarcodes { get; set; } public List<PageBarcodeResult> PageResults { get; set; } } public class PageBarcodeResult { public int PageNumber { get; set; } public int BarcodeCount { get; set; } public List<BarcodeData> Barcodes { get; set; } } Imports System Imports System.Collections.Generic Imports System.IO Imports System.Linq Imports System.Net.Http Imports System.Threading.Tasks Imports Microsoft.AspNetCore.Authorization Imports Microsoft.AspNetCore.Http Imports Microsoft.AspNetCore.Mvc Imports Microsoft.Extensions.Configuration Imports Microsoft.Extensions.Logging <ApiController> <Route("api/v1/[controller]")> <Authorize> Public Class AdvancedScannerController Inherits ControllerBase Private ReadOnly _httpClientFactory As IHttpClientFactory Private ReadOnly _logger As ILogger(Of AdvancedScannerController) Private ReadOnly _configuration As IConfiguration Public Sub New(httpClientFactory As IHttpClientFactory, logger As ILogger(Of AdvancedScannerController), configuration As IConfiguration) _httpClientFactory = httpClientFactory _logger = logger _configuration = configuration End Sub ' Handle Base64 input (common in web applications) <HttpPost("scan-base64")> Public Function ScanBase64(<FromBody> request As Base64Request) As ActionResult(Of ScanResult) If Not ModelState.IsValid Then Return BadRequest(ModelState) End If Try ' Validate Base64 format Dim base64Data = request.ImageData If base64Data.Contains(",") Then ' Handle data URL format: "data:image/png;base64,..." base64Data = base64Data.Substring(base64Data.IndexOf(",") + 1) End If Dim imageBytes = Convert.FromBase64String(base64Data) ' Implement size validation If imageBytes.Length > 10 * 1024 * 1024 Then ' 10MB limit Return BadRequest(New ScanResult With { .Success = False, .ErrorMessage = "Image size exceeds 10MB limit" }) End If ' Configure for web-uploaded images (often lower quality) Dim options = New BarcodeReaderOptions With { .Speed = ReadingSpeed.Detailed, .ImageFilters = New ImageFilterCollection From { New SharpenFilter(3), New ContrastFilter(2), New DeNoise() }, .TryInvertColor = True, ' Handle inverted barcodes .AutoRotate = True } Dim results = BarcodeReader.Read(imageBytes, options) Return ProcessResults(results, "base64", request.FileName) Catch ex As FormatException Return BadRequest(New ScanResult With { .Success = False, .ErrorMessage = "Invalid Base64 format" }) End Try End Function ' Handle URL input (for cloud storage integration) <HttpPost("scan-url")> Public Async Function ScanFromUrl(<FromBody> request As UrlScanRequest) As Task(Of ActionResult(Of ScanResult)) Dim uri As Uri = Nothing If Not Uri.TryCreate(request.Url, UriKind.Absolute, uri) Then Return BadRequest(New ScanResult With { .Success = False, .ErrorMessage = "Invalid URL format" }) End If ' Validate URL domain (security measure) Dim allowedDomains = _configuration.GetSection("AllowedDomains").Get(Of String())() _ ?? New String() {"blob.core.windows.net", "s3.amazonaws.com"} If Not allowedDomains.Any(Function(domain) uri.Host.EndsWith(domain)) Then _logger.LogWarning($"Rejected URL from unauthorized domain: {uri.Host}") Return BadRequest(New ScanResult With { .Success = False, .ErrorMessage = "URL domain not authorized" }) End If Try Using httpClient = _httpClientFactory.CreateClient("BarcodeScanner") httpClient.Timeout = TimeSpan.FromSeconds(30) ' Add headers to avoid being blocked httpClient.DefaultRequestHeaders.Add("User-Agent", "BarcodeScannerAPI/2.0") Dim response = Await httpClient.GetAsync(uri) response.EnsureSuccessStatusCode() ' Check content type Dim contentType = response.Content.Headers.ContentType?.MediaType If Not IsValidContentType(contentType) Then Return BadRequest(New ScanResult With { .Success = False, .ErrorMessage = $"Unsupported content type: {contentType}" }) End If Dim imageBytes = Await response.Content.ReadAsByteArrayAsync() ' Use async processing for better scalability Dim results = Await BarcodeReader.ReadAsync(imageBytes) Return ProcessResults(results, "url", uri.ToString()) End Using Catch ex As HttpRequestException _logger.LogError(ex, $"Failed to download from URL: {uri}") Return BadRequest(New ScanResult With { .Success = False, .ErrorMessage = "Failed to download image from URL" }) Catch ex As TaskCanceledException Return BadRequest(New ScanResult With { .Success = False, .ErrorMessage = "Download timeout - file too large or slow connection" }) End Try End Function ' Handle multi-page PDFs with page-specific processing <HttpPost("scan-pdf-advanced")> Public Async Function ScanPdfAdvanced(<FromForm> request As PdfScanRequest) As Task(Of ActionResult(Of PdfScanResult)) Using stream = New MemoryStream() Await request.File.CopyToAsync(stream) Dim pdfOptions = New PdfBarcodeReaderOptions With { .Scale = If(request.Scale, 3), .DPI = If(request.DPI, 300), .PageNumbers = request.PageNumbers, .Password = request.Password, .MaxThreads = Math.Min(If(request.MaxThreads, 4), Environment.ProcessorCount) } ' For large PDFs, process in chunks If stream.Length > 50 * 1024 * 1024 Then ' 50MB _logger.LogInformation($"Large PDF detected ({stream.Length / 1024 / 1024}MB), using chunked processing") pdfOptions.MaxThreads = 2 ' Reduce memory pressure End If Dim results = BarcodeReader.ReadPdf(stream.ToArray(), pdfOptions) ' Group results by page Dim pageResults = results.GroupBy(Function(r) r.PageNumber) _ .OrderBy(Function(g) g.Key) _ .Select(Function(g) New PageBarcodeResult With { .PageNumber = g.Key, .BarcodeCount = g.Count(), .Barcodes = g.Select(Function(b) New BarcodeData With { .Value = b.Value, .Format = b.BarcodeType.ToString(), .Confidence = b.Confidence, .Location = b.Bounds }).ToList() }).ToList() Return Ok(New PdfScanResult With { .Success = True, .TotalPages = pageResults.Count, .TotalBarcodes = results.Count(), .PageResults = pageResults, .RequestId = Guid.NewGuid().ToString() }) End Using End Function ' Handle damaged or low-quality barcodes <HttpPost("scan-damaged")> Public Async Function ScanDamagedBarcode(<FromForm> file As IFormFile) As Task(Of ActionResult(Of ScanResult)) Using stream = New MemoryStream() Await file.CopyToAsync(stream) ' Aggressive image correction for damaged barcodes Dim options = New BarcodeReaderOptions With { .Speed = ReadingSpeed.ExtremeDetail, .ImageFilters = New ImageFilterCollection From { New SharpenFilter(4), New ContrastFilter(3), New BrightnessFilter(1.5F), New BinaryThresholdFilter(128), New DeNoise(3) }, .TryInvertColor = True, .AutoRotate = True, .UseCode39ExtendedMode = True, .RemoveFalsePositive = False, ' Accept lower confidence .Confidence = ConfidenceLevel.Low } Dim results = BarcodeReader.Read(stream.ToArray(), options) ' If still no results, try with different threshold If Not results.Any() Then options.ImageFilters = New ImageFilterCollection From { New AdaptiveThresholdFilter(9), New MedianFilter(3), New Dilate(1) } results = BarcodeReader.Read(stream.ToArray(), options) End If Return ProcessResults(results, "damaged", file.FileName) End Using End Function Private Function IsValidContentType(contentType As String) As Boolean Dim validTypes = New String() { "image/jpeg", "image/jpg", "image/png", "image/gif", "image/tiff", "image/bmp", "application/pdf" } Return validTypes.Contains(contentType?.ToLower()) End Function Private Function ProcessResults(results As BarcodeResults, source As String, identifier As String) As ActionResult(Of ScanResult) Dim scanResult = New ScanResult With { .Metadata = New Dictionary(Of String, Object) From { {"Source", source}, {"Identifier", identifier}, {"ProcessedAt", DateTime.UtcNow} } } If results.Any() Then scanResult.Success = True scanResult.Barcodes = results.Select(Function(r) New BarcodeData With { .Value = r.Value, .Format = r.BarcodeType.ToString(), .Confidence = r.Confidence, .Location = r.Bounds }).ToList() ' Log low confidence results for quality monitoring Dim lowConfidence = results.Where(Function(r) r.Confidence < 70).ToList() If lowConfidence.Any() Then _logger.LogWarning($"Low confidence barcodes detected: {lowConfidence.Count} of {results.Count()} from {identifier}") End If Else scanResult.Success = False scanResult.ErrorMessage = "No barcodes detected" End If Return Ok(scanResult) End Function End Class ' Request models Public Class Base64Request <Required> Public Property ImageData As String Public Property FileName As String End Class Public Class UrlScanRequest <Required> <Url> Public Property Url As String End Class Public Class PdfScanRequest <Required> Public Property File As IFormFile Public Property Scale As Integer? Public Property DPI As Integer? Public Property PageNumbers As Integer() Public Property Password As String Public Property MaxThreads As Integer? End Class ' Response models Public Class PdfScanResult Inherits ScanResult Public Property TotalPages As Integer Public Property TotalBarcodes As Integer Public Property PageResults As List(Of PageBarcodeResult) End Class Public Class PageBarcodeResult Public Property PageNumber As Integer Public Property BarcodeCount As Integer Public Property Barcodes As List(Of BarcodeData) End Class $vbLabelText $csharpLabel 這個完整實施方案針對的是現實世界的企業場景。 URL 掃描端點包含網域驗證,以防止伺服器端要求偽造 (SSRF) 攻擊。 Base64 處理程序會移除資料 URL 前綴,這在從 Web 應用程式接收圖片時很常見。 損壞的條碼端點展示了 IronBarcode 的影像校正功能。 透過應用多種濾波器並嘗試不同的方法,它可以從嚴重退化的圖像中恢復資料。 在處理舊的庫存標籤或受天氣損壞的運輸單據時,這非常有用。 選擇PDF掃描還是影像掃描 PDF 檔案為企業條碼掃描帶來了獨特的挑戰和機會。 許多商業文件,如發票、發貨清單和合規表格,都是以帶有嵌入式條碼的 PDF 格式提供的。 IronBarcode 的PDF 條碼讀取功能可以很好地處理這些情況。 設想一個典型的企業情境:您的應付帳款部門每月收到數千張發票,每張發票都包含用於自動處理的條碼。 有些供應商發送高品質的PDF文件,有些供應商發送品質參差不齊的掃描文件。 進階PDF掃描終端可以處理這兩種情況。 對於高品質 PDF 文件,標準設定即可完美滿足需求。 對於掃描文檔,提高 DPI 和縮放參數可以提高偵測率。 頁面特定處理功能可讓您從特定頁面提取條碼,當您知道發票的第一頁總是有條碼時,此功能非常有用。 按頁面分組的結果提供了有價值的背景資訊。 您的工作流程系統可以根據哪些頁麵包含條碼來路由文檔,從而實現文檔分類的自動化。 這種結構化的多頁文件處理方法將手動流程轉變為高效的自動化工作流程。 高效率處理多個條碼 企業文件通常包含多個條碼,用於不同的用途。 運輸標籤可能包含追蹤條碼、產品條碼和目的地條碼。 妥善處理多種條碼應用程式場景需要周詳的 API 設計。 批次處理端點示範如何有效率地處理大容量場景。 透過並行處理多個文件,可以顯著縮短總處理時間。 Task.WhenAll 模式可確保最佳資源利用率WhenAll同時維持系統穩定性。 對於在您的應用程式中建立條碼,IronBarcode 提供了同樣有效的功能。 無論您是需要為庫存系統產生一維線性條碼,還是為行動應用程式建立二維矩陣碼,都適用相同的簡單 API 方法。 提高性能和準確性 企業條碼掃描的效能最佳化不僅僅是速度的問題,而是要找到適合您特定用例的合適平衡點。 讓我們來探索能夠顯著提升掃描效能的進階最佳化技術: public class OptimizedScannerService { private readonly ILogger<OptimizedScannerService> _logger; private readonly IMemoryCache _cache; public OptimizedScannerService(ILogger<OptimizedScannerService> logger, IMemoryCache cache) { _logger = logger; _cache = cache; } // Performance-optimized scanning with caching public async Task<ScanResult> ScanWithOptimizationsAsync(byte[] imageData, string cacheKey = null) { // Check cache for repeat scans if (!string.IsNullOrEmpty(cacheKey)) { if (_cache.TryGetValue(cacheKey, out ScanResult cachedResult)) { _logger.LogInformation($"Cache hit for {cacheKey}"); cachedResult.Metadata["CacheHit"] = true; return cachedResult; } } // Determine optimal settings based on image characteristics var settings = await DetermineOptimalSettingsAsync(imageData); // Apply region-specific scanning if applicable if (settings.UseRegionScanning) { return await ScanWithRegionsAsync(imageData, settings); } // Standard optimized scanning var results = await BarcodeReader.ReadAsync(imageData, settings.Options); var scanResult = BuildScanResult(results); // Cache successful results if (!string.IsNullOrEmpty(cacheKey) && scanResult.Success) { _cache.Set(cacheKey, scanResult, TimeSpan.FromMinutes(5)); } return scanResult; } // Intelligent settings determination private async Task<ScanSettings> DetermineOptimalSettingsAsync(byte[] imageData) { var settings = new ScanSettings(); // Quick analysis of image properties using var ms = new MemoryStream(imageData); using var image = Image.FromStream(ms); var width = image.Width; var height = image.Height; var aspectRatio = (double)width / height; _logger.LogInformation($"Image analysis: {width}x{height}, ratio: {aspectRatio:F2}"); // High-resolution images can use faster scanning if (width > 2000 && height > 2000) { settings.Options.Speed = ReadingSpeed.Faster; settings.Options.ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128; } // Low-resolution needs more processing else if (width < 800 || height < 800) { settings.Options.Speed = ReadingSpeed.ExtremeDetail; settings.Options.ImageFilters = new ImageFilterCollection { new SharpenFilter(3), new ContrastFilter(2) }; } else { settings.Options.Speed = ReadingSpeed.Balanced; } // Detect if image might contain multiple barcodes based on aspect ratio if (aspectRatio > 2 || aspectRatio < 0.5) { settings.Options.ExpectMultipleBarcodes = true; settings.UseRegionScanning = true; } // Enable rotation correction for potentially skewed images settings.Options.AutoRotate = true; return settings; } // Region-based scanning for large images private async Task<ScanResult> ScanWithRegionsAsync(byte[] imageData, ScanSettings settings) { var allResults = new List<BarcodeResult>(); using var ms = new MemoryStream(imageData); using var image = Image.FromStream(ms); // Define scanning regions for common document layouts var regions = new[] { new Rectangle(0, 0, image.Width / 2, image.Height / 2), // Top-left new Rectangle(image.Width / 2, 0, image.Width / 2, image.Height / 2), // Top-right new Rectangle(0, image.Height / 2, image.Width / 2, image.Height / 2), // Bottom-left new Rectangle(image.Width / 2, image.Height / 2, image.Width / 2, image.Height / 2), // Bottom-right new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2) // Center }; var tasks = regions.Select(async region => { var regionOptions = new BarcodeReaderOptions { CropArea = region, Speed = ReadingSpeed.Faster, ExpectMultipleBarcodes = false }; try { return await BarcodeReader.ReadAsync(imageData, regionOptions); } catch (Exception ex) { _logger.LogWarning($"Region scan failed: {ex.Message}"); return new BarcodeResult[0]; } }); var regionResults = await Task.WhenAll(tasks); // Combine and deduplicate results var uniqueResults = regionResults .SelectMany(r => r) .GroupBy(r => r.Value) .Select(g => g.OrderByDescending(r => r.Confidence).First()) .ToList(); return BuildScanResult(uniqueResults); } // Adaptive quality enhancement public async Task<ScanResult> ScanWithAdaptiveEnhancementAsync(byte[] imageData) { var attempts = new List<Func<Task<BarcodeResults>>> { // Attempt 1: Fast scan async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions { Speed = ReadingSpeed.Faster, RemoveFalsePositive = true }), // Attempt 2: Standard scan with basic filters async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions { Speed = ReadingSpeed.Balanced, ImageFilters = new ImageFilterCollection { new ContrastFilter(1.5f), new SharpenFilter(1) }, TryInvertColor = true }), // Attempt 3: Detailed scan with aggressive filtering async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions { Speed = ReadingSpeed.Detailed, ImageFilters = new ImageFilterCollection { new AdaptiveThresholdFilter(11), new DeNoise(2), new MedianFilter(3) }, AutoRotate = true, Confidence = ConfidenceLevel.Low }), // Attempt 4: Extreme processing for damaged barcodes async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions { Speed = ReadingSpeed.ExtremeDetail, ImageFilters = new ImageFilterCollection { new BinaryThresholdFilter(100), new Erode(1), new Dilate(2), new SharpenFilter(4) }, RemoveFalsePositive = false, UseCode39ExtendedMode = true, TryInvertColor = true }) }; foreach (var (attempt, index) in attempts.Select((a, i) => (a, i))) { var stopwatch = Stopwatch.StartNew(); var results = await attempt(); stopwatch.Stop(); _logger.LogInformation($"Attempt {index + 1} took {stopwatch.ElapsedMilliseconds}ms, found {results.Count()} barcodes"); if (results.Any()) { var scanResult = BuildScanResult(results); scanResult.Metadata["AttemptNumber"] = index + 1; scanResult.Metadata["ProcessingStrategy"] = GetStrategyName(index); return scanResult; } } return new ScanResult { Success = false, ErrorMessage = "No barcodes found after all enhancement attempts" }; } // Machine learning confidence optimization public class MLOptimizedScanner { private readonly Dictionary<string, double> _formatConfidenceThresholds = new() { { "QRCode", 85.0 }, { "Code128", 90.0 }, { "Code39", 88.0 }, { "DataMatrix", 87.0 }, { "EAN13", 92.0 }, { "PDF417", 86.0 } }; public async Task<ScanResult> ScanWithMLConfidenceAsync(byte[] imageData, string expectedFormat = null) { var options = new BarcodeReaderOptions { Speed = ReadingSpeed.Balanced, Confidence = ConfidenceLevel.Optional }; // If we know the expected format, improve for it if (!string.IsNullOrEmpty(expectedFormat) && Enum.TryParse<BarcodeEncoding>(expectedFormat, out var encoding)) { options.ExpectBarcodeTypes = encoding; } var results = await BarcodeReader.ReadAsync(imageData, options); // Apply ML confidence filtering var confidenceThreshold = expectedFormat != null && _formatConfidenceThresholds.ContainsKey(expectedFormat) ? _formatConfidenceThresholds[expectedFormat] : 80.0; var highConfidenceResults = results .Where(r => r.Confidence >= confidenceThreshold) .ToList(); if (highConfidenceResults.Any()) { return BuildScanResult(highConfidenceResults); } // If no high-confidence results, include lower confidence with warnings var lowConfidenceResults = results .Where(r => r.Confidence < confidenceThreshold) .ToList(); if (lowConfidenceResults.Any()) { var result = BuildScanResult(lowConfidenceResults); result.Metadata["Warning"] = "Low confidence results - manual verification recommended"; result.Metadata["MinConfidence"] = lowConfidenceResults.Min(r => r.Confidence); return result; } return new ScanResult { Success = false, ErrorMessage = "No barcodes met confidence threshold" }; } } private ScanResult BuildScanResult(IEnumerable<BarcodeResult> results) { var resultList = results.ToList(); return new ScanResult { Success = true, Barcodes = resultList.Select(r => new BarcodeData { Value = r.Value, Format = r.BarcodeType.ToString(), Confidence = r.Confidence, Location = r.Bounds }).ToList(), Metadata = new Dictionary<string, object> { ["TotalFound"] = resultList.Count, ["AverageConfidence"] = resultList.Average(r => r.Confidence), ["Formats"] = resultList.Select(r => r.BarcodeType.ToString()).Distinct().ToArray() } }; } private string GetStrategyName(int attemptIndex) { return attemptIndex switch { 0 => "FastScan", 1 => "StandardEnhanced", 2 => "DetailedFiltering", 3 => "ExtremeDamageRecovery", _ => "Unknown" }; } } // Supporting classes public class ScanSettings { public BarcodeReaderOptions Options { get; set; } = new BarcodeReaderOptions(); public bool UseRegionScanning { get; set; } public List<Rectangle> CustomRegions { get; set; } } // Benchmark service for performance testing public class BenchmarkService { private readonly ILogger<BenchmarkService> _logger; public async Task<BenchmarkResult> BenchmarkSettingsAsync(byte[] testImage, int iterations = 10) { var results = new Dictionary<string, BenchmarkData>(); var testConfigurations = new Dictionary<string, BarcodeReaderOptions> { ["Fastest"] = new() { Speed = ReadingSpeed.Faster }, ["Balanced"] = new() { Speed = ReadingSpeed.Balanced }, ["Detailed"] = new() { Speed = ReadingSpeed.Detailed }, ["Parallel"] = new() { Speed = ReadingSpeed.Balanced, Multithreaded = true, MaxParallelThreads = 4 }, ["Filtered"] = new() { Speed = ReadingSpeed.Balanced, ImageFilters = new ImageFilterCollection { new SharpenFilter(2), new ContrastFilter(1.5f) } } }; foreach (var config in testConfigurations) { var times = new List<long>(); var successCount = 0; for (int i = 0; i < iterations; i++) { var sw = Stopwatch.StartNew(); var scanResults = await BarcodeReader.ReadAsync(testImage, config.Value); sw.Stop(); times.Add(sw.ElapsedMilliseconds); if (scanResults.Any()) successCount++; // Small delay between tests await Task.Delay(100); } results[config.Key] = new BenchmarkData { AverageMs = times.Average(), MinMs = times.Min(), MaxMs = times.Max(), SuccessRate = (double)successCount / iterations * 100 }; } return new BenchmarkResult { Results = results }; } } public class BenchmarkData { public double AverageMs { get; set; } public long MinMs { get; set; } public long MaxMs { get; set; } public double SuccessRate { get; set; } } public class BenchmarkResult { public Dictionary<string, BenchmarkData> Results { get; set; } } public class OptimizedScannerService { private readonly ILogger<OptimizedScannerService> _logger; private readonly IMemoryCache _cache; public OptimizedScannerService(ILogger<OptimizedScannerService> logger, IMemoryCache cache) { _logger = logger; _cache = cache; } // Performance-optimized scanning with caching public async Task<ScanResult> ScanWithOptimizationsAsync(byte[] imageData, string cacheKey = null) { // Check cache for repeat scans if (!string.IsNullOrEmpty(cacheKey)) { if (_cache.TryGetValue(cacheKey, out ScanResult cachedResult)) { _logger.LogInformation($"Cache hit for {cacheKey}"); cachedResult.Metadata["CacheHit"] = true; return cachedResult; } } // Determine optimal settings based on image characteristics var settings = await DetermineOptimalSettingsAsync(imageData); // Apply region-specific scanning if applicable if (settings.UseRegionScanning) { return await ScanWithRegionsAsync(imageData, settings); } // Standard optimized scanning var results = await BarcodeReader.ReadAsync(imageData, settings.Options); var scanResult = BuildScanResult(results); // Cache successful results if (!string.IsNullOrEmpty(cacheKey) && scanResult.Success) { _cache.Set(cacheKey, scanResult, TimeSpan.FromMinutes(5)); } return scanResult; } // Intelligent settings determination private async Task<ScanSettings> DetermineOptimalSettingsAsync(byte[] imageData) { var settings = new ScanSettings(); // Quick analysis of image properties using var ms = new MemoryStream(imageData); using var image = Image.FromStream(ms); var width = image.Width; var height = image.Height; var aspectRatio = (double)width / height; _logger.LogInformation($"Image analysis: {width}x{height}, ratio: {aspectRatio:F2}"); // High-resolution images can use faster scanning if (width > 2000 && height > 2000) { settings.Options.Speed = ReadingSpeed.Faster; settings.Options.ExpectBarcodeTypes = BarcodeEncoding.QRCode | BarcodeEncoding.Code128; } // Low-resolution needs more processing else if (width < 800 || height < 800) { settings.Options.Speed = ReadingSpeed.ExtremeDetail; settings.Options.ImageFilters = new ImageFilterCollection { new SharpenFilter(3), new ContrastFilter(2) }; } else { settings.Options.Speed = ReadingSpeed.Balanced; } // Detect if image might contain multiple barcodes based on aspect ratio if (aspectRatio > 2 || aspectRatio < 0.5) { settings.Options.ExpectMultipleBarcodes = true; settings.UseRegionScanning = true; } // Enable rotation correction for potentially skewed images settings.Options.AutoRotate = true; return settings; } // Region-based scanning for large images private async Task<ScanResult> ScanWithRegionsAsync(byte[] imageData, ScanSettings settings) { var allResults = new List<BarcodeResult>(); using var ms = new MemoryStream(imageData); using var image = Image.FromStream(ms); // Define scanning regions for common document layouts var regions = new[] { new Rectangle(0, 0, image.Width / 2, image.Height / 2), // Top-left new Rectangle(image.Width / 2, 0, image.Width / 2, image.Height / 2), // Top-right new Rectangle(0, image.Height / 2, image.Width / 2, image.Height / 2), // Bottom-left new Rectangle(image.Width / 2, image.Height / 2, image.Width / 2, image.Height / 2), // Bottom-right new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2) // Center }; var tasks = regions.Select(async region => { var regionOptions = new BarcodeReaderOptions { CropArea = region, Speed = ReadingSpeed.Faster, ExpectMultipleBarcodes = false }; try { return await BarcodeReader.ReadAsync(imageData, regionOptions); } catch (Exception ex) { _logger.LogWarning($"Region scan failed: {ex.Message}"); return new BarcodeResult[0]; } }); var regionResults = await Task.WhenAll(tasks); // Combine and deduplicate results var uniqueResults = regionResults .SelectMany(r => r) .GroupBy(r => r.Value) .Select(g => g.OrderByDescending(r => r.Confidence).First()) .ToList(); return BuildScanResult(uniqueResults); } // Adaptive quality enhancement public async Task<ScanResult> ScanWithAdaptiveEnhancementAsync(byte[] imageData) { var attempts = new List<Func<Task<BarcodeResults>>> { // Attempt 1: Fast scan async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions { Speed = ReadingSpeed.Faster, RemoveFalsePositive = true }), // Attempt 2: Standard scan with basic filters async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions { Speed = ReadingSpeed.Balanced, ImageFilters = new ImageFilterCollection { new ContrastFilter(1.5f), new SharpenFilter(1) }, TryInvertColor = true }), // Attempt 3: Detailed scan with aggressive filtering async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions { Speed = ReadingSpeed.Detailed, ImageFilters = new ImageFilterCollection { new AdaptiveThresholdFilter(11), new DeNoise(2), new MedianFilter(3) }, AutoRotate = true, Confidence = ConfidenceLevel.Low }), // Attempt 4: Extreme processing for damaged barcodes async () => await BarcodeReader.ReadAsync(imageData, new BarcodeReaderOptions { Speed = ReadingSpeed.ExtremeDetail, ImageFilters = new ImageFilterCollection { new BinaryThresholdFilter(100), new Erode(1), new Dilate(2), new SharpenFilter(4) }, RemoveFalsePositive = false, UseCode39ExtendedMode = true, TryInvertColor = true }) }; foreach (var (attempt, index) in attempts.Select((a, i) => (a, i))) { var stopwatch = Stopwatch.StartNew(); var results = await attempt(); stopwatch.Stop(); _logger.LogInformation($"Attempt {index + 1} took {stopwatch.ElapsedMilliseconds}ms, found {results.Count()} barcodes"); if (results.Any()) { var scanResult = BuildScanResult(results); scanResult.Metadata["AttemptNumber"] = index + 1; scanResult.Metadata["ProcessingStrategy"] = GetStrategyName(index); return scanResult; } } return new ScanResult { Success = false, ErrorMessage = "No barcodes found after all enhancement attempts" }; } // Machine learning confidence optimization public class MLOptimizedScanner { private readonly Dictionary<string, double> _formatConfidenceThresholds = new() { { "QRCode", 85.0 }, { "Code128", 90.0 }, { "Code39", 88.0 }, { "DataMatrix", 87.0 }, { "EAN13", 92.0 }, { "PDF417", 86.0 } }; public async Task<ScanResult> ScanWithMLConfidenceAsync(byte[] imageData, string expectedFormat = null) { var options = new BarcodeReaderOptions { Speed = ReadingSpeed.Balanced, Confidence = ConfidenceLevel.Optional }; // If we know the expected format, improve for it if (!string.IsNullOrEmpty(expectedFormat) && Enum.TryParse<BarcodeEncoding>(expectedFormat, out var encoding)) { options.ExpectBarcodeTypes = encoding; } var results = await BarcodeReader.ReadAsync(imageData, options); // Apply ML confidence filtering var confidenceThreshold = expectedFormat != null && _formatConfidenceThresholds.ContainsKey(expectedFormat) ? _formatConfidenceThresholds[expectedFormat] : 80.0; var highConfidenceResults = results .Where(r => r.Confidence >= confidenceThreshold) .ToList(); if (highConfidenceResults.Any()) { return BuildScanResult(highConfidenceResults); } // If no high-confidence results, include lower confidence with warnings var lowConfidenceResults = results .Where(r => r.Confidence < confidenceThreshold) .ToList(); if (lowConfidenceResults.Any()) { var result = BuildScanResult(lowConfidenceResults); result.Metadata["Warning"] = "Low confidence results - manual verification recommended"; result.Metadata["MinConfidence"] = lowConfidenceResults.Min(r => r.Confidence); return result; } return new ScanResult { Success = false, ErrorMessage = "No barcodes met confidence threshold" }; } } private ScanResult BuildScanResult(IEnumerable<BarcodeResult> results) { var resultList = results.ToList(); return new ScanResult { Success = true, Barcodes = resultList.Select(r => new BarcodeData { Value = r.Value, Format = r.BarcodeType.ToString(), Confidence = r.Confidence, Location = r.Bounds }).ToList(), Metadata = new Dictionary<string, object> { ["TotalFound"] = resultList.Count, ["AverageConfidence"] = resultList.Average(r => r.Confidence), ["Formats"] = resultList.Select(r => r.BarcodeType.ToString()).Distinct().ToArray() } }; } private string GetStrategyName(int attemptIndex) { return attemptIndex switch { 0 => "FastScan", 1 => "StandardEnhanced", 2 => "DetailedFiltering", 3 => "ExtremeDamageRecovery", _ => "Unknown" }; } } // Supporting classes public class ScanSettings { public BarcodeReaderOptions Options { get; set; } = new BarcodeReaderOptions(); public bool UseRegionScanning { get; set; } public List<Rectangle> CustomRegions { get; set; } } // Benchmark service for performance testing public class BenchmarkService { private readonly ILogger<BenchmarkService> _logger; public async Task<BenchmarkResult> BenchmarkSettingsAsync(byte[] testImage, int iterations = 10) { var results = new Dictionary<string, BenchmarkData>(); var testConfigurations = new Dictionary<string, BarcodeReaderOptions> { ["Fastest"] = new() { Speed = ReadingSpeed.Faster }, ["Balanced"] = new() { Speed = ReadingSpeed.Balanced }, ["Detailed"] = new() { Speed = ReadingSpeed.Detailed }, ["Parallel"] = new() { Speed = ReadingSpeed.Balanced, Multithreaded = true, MaxParallelThreads = 4 }, ["Filtered"] = new() { Speed = ReadingSpeed.Balanced, ImageFilters = new ImageFilterCollection { new SharpenFilter(2), new ContrastFilter(1.5f) } } }; foreach (var config in testConfigurations) { var times = new List<long>(); var successCount = 0; for (int i = 0; i < iterations; i++) { var sw = Stopwatch.StartNew(); var scanResults = await BarcodeReader.ReadAsync(testImage, config.Value); sw.Stop(); times.Add(sw.ElapsedMilliseconds); if (scanResults.Any()) successCount++; // Small delay between tests await Task.Delay(100); } results[config.Key] = new BenchmarkData { AverageMs = times.Average(), MinMs = times.Min(), MaxMs = times.Max(), SuccessRate = (double)successCount / iterations * 100 }; } return new BenchmarkResult { Results = results }; } } public class BenchmarkData { public double AverageMs { get; set; } public long MinMs { get; set; } public long MaxMs { get; set; } public double SuccessRate { get; set; } } public class BenchmarkResult { public Dictionary<string, BenchmarkData> Results { get; set; } } Imports System Imports System.Collections.Generic Imports System.Drawing Imports System.IO Imports System.Linq Imports System.Threading.Tasks Public Class OptimizedScannerService Private ReadOnly _logger As ILogger(Of OptimizedScannerService) Private ReadOnly _cache As IMemoryCache Public Sub New(logger As ILogger(Of OptimizedScannerService), cache As IMemoryCache) _logger = logger _cache = cache End Sub ' Performance-optimized scanning with caching Public Async Function ScanWithOptimizationsAsync(imageData As Byte(), Optional cacheKey As String = Nothing) As Task(Of ScanResult) ' Check cache for repeat scans If Not String.IsNullOrEmpty(cacheKey) Then Dim cachedResult As ScanResult = Nothing If _cache.TryGetValue(cacheKey, cachedResult) Then _logger.LogInformation($"Cache hit for {cacheKey}") cachedResult.Metadata("CacheHit") = True Return cachedResult End If End If ' Determine optimal settings based on image characteristics Dim settings = Await DetermineOptimalSettingsAsync(imageData) ' Apply region-specific scanning if applicable If settings.UseRegionScanning Then Return Await ScanWithRegionsAsync(imageData, settings) End If ' Standard optimized scanning Dim results = Await BarcodeReader.ReadAsync(imageData, settings.Options) Dim scanResult = BuildScanResult(results) ' Cache successful results If Not String.IsNullOrEmpty(cacheKey) AndAlso scanResult.Success Then _cache.Set(cacheKey, scanResult, TimeSpan.FromMinutes(5)) End If Return scanResult End Function ' Intelligent settings determination Private Async Function DetermineOptimalSettingsAsync(imageData As Byte()) As Task(Of ScanSettings) Dim settings As New ScanSettings() ' Quick analysis of image properties Using ms As New MemoryStream(imageData) Using image As Image = Image.FromStream(ms) Dim width = image.Width Dim height = image.Height Dim aspectRatio = CDbl(width) / height _logger.LogInformation($"Image analysis: {width}x{height}, ratio: {aspectRatio:F2}") ' High-resolution images can use faster scanning If width > 2000 AndAlso height > 2000 Then settings.Options.Speed = ReadingSpeed.Faster settings.Options.ExpectBarcodeTypes = BarcodeEncoding.QRCode Or BarcodeEncoding.Code128 ElseIf width < 800 OrElse height < 800 Then ' Low-resolution needs more processing settings.Options.Speed = ReadingSpeed.ExtremeDetail settings.Options.ImageFilters = New ImageFilterCollection From { New SharpenFilter(3), New ContrastFilter(2) } Else settings.Options.Speed = ReadingSpeed.Balanced End If ' Detect if image might contain multiple barcodes based on aspect ratio If aspectRatio > 2 OrElse aspectRatio < 0.5 Then settings.Options.ExpectMultipleBarcodes = True settings.UseRegionScanning = True End If ' Enable rotation correction for potentially skewed images settings.Options.AutoRotate = True End Using End Using Return settings End Function ' Region-based scanning for large images Private Async Function ScanWithRegionsAsync(imageData As Byte(), settings As ScanSettings) As Task(Of ScanResult) Dim allResults As New List(Of BarcodeResult)() Using ms As New MemoryStream(imageData) Using image As Image = Image.FromStream(ms) ' Define scanning regions for common document layouts Dim regions = { New Rectangle(0, 0, image.Width \ 2, image.Height \ 2), ' Top-left New Rectangle(image.Width \ 2, 0, image.Width \ 2, image.Height \ 2), ' Top-right New Rectangle(0, image.Height \ 2, image.Width \ 2, image.Height \ 2), ' Bottom-left New Rectangle(image.Width \ 2, image.Height \ 2, image.Width \ 2, image.Height \ 2), ' Bottom-right New Rectangle(image.Width \ 4, image.Height \ 4, image.Width \ 2, image.Height \ 2) ' Center } Dim tasks = regions.Select(Async Function(region) Dim regionOptions As New BarcodeReaderOptions With { .CropArea = region, .Speed = ReadingSpeed.Faster, .ExpectMultipleBarcodes = False } Try Return Await BarcodeReader.ReadAsync(imageData, regionOptions) Catch ex As Exception _logger.LogWarning($"Region scan failed: {ex.Message}") Return New BarcodeResult() {} End Try End Function) Dim regionResults = Await Task.WhenAll(tasks) ' Combine and deduplicate results Dim uniqueResults = regionResults. SelectMany(Function(r) r). GroupBy(Function(r) r.Value). Select(Function(g) g.OrderByDescending(Function(r) r.Confidence).First()). ToList() Return BuildScanResult(uniqueResults) End Using End Using End Function ' Adaptive quality enhancement Public Async Function ScanWithAdaptiveEnhancementAsync(imageData As Byte()) As Task(Of ScanResult) Dim attempts = New List(Of Func(Of Task(Of BarcodeResults))) From { ' Attempt 1: Fast scan Async Function() Await BarcodeReader.ReadAsync(imageData, New BarcodeReaderOptions With { .Speed = ReadingSpeed.Faster, .RemoveFalsePositive = True }), ' Attempt 2: Standard scan with basic filters Async Function() Await BarcodeReader.ReadAsync(imageData, New BarcodeReaderOptions With { .Speed = ReadingSpeed.Balanced, .ImageFilters = New ImageFilterCollection From { New ContrastFilter(1.5F), New SharpenFilter(1) }, .TryInvertColor = True }), ' Attempt 3: Detailed scan with aggressive filtering Async Function() Await BarcodeReader.ReadAsync(imageData, New BarcodeReaderOptions With { .Speed = ReadingSpeed.Detailed, .ImageFilters = New ImageFilterCollection From { New AdaptiveThresholdFilter(11), New DeNoise(2), New MedianFilter(3) }, .AutoRotate = True, .Confidence = ConfidenceLevel.Low }), ' Attempt 4: Extreme processing for damaged barcodes Async Function() Await BarcodeReader.ReadAsync(imageData, New BarcodeReaderOptions With { .Speed = ReadingSpeed.ExtremeDetail, .ImageFilters = New ImageFilterCollection From { New BinaryThresholdFilter(100), New Erode(1), New Dilate(2), New SharpenFilter(4) }, .RemoveFalsePositive = False, .UseCode39ExtendedMode = True, .TryInvertColor = True }) } For Each attempt In attempts.Select(Function(a, i) (a, i)) Dim stopwatch = Stopwatch.StartNew() Dim results = Await attempt.a() stopwatch.Stop() _logger.LogInformation($"Attempt {attempt.i + 1} took {stopwatch.ElapsedMilliseconds}ms, found {results.Count()} barcodes") If results.Any() Then Dim scanResult = BuildScanResult(results) scanResult.Metadata("AttemptNumber") = attempt.i + 1 scanResult.Metadata("ProcessingStrategy") = GetStrategyName(attempt.i) Return scanResult End If Next Return New ScanResult With { .Success = False, .ErrorMessage = "No barcodes found after all enhancement attempts" } End Function ' Machine learning confidence optimization Public Class MLOptimizedScanner Private ReadOnly _formatConfidenceThresholds As New Dictionary(Of String, Double) From { {"QRCode", 85.0}, {"Code128", 90.0}, {"Code39", 88.0}, {"DataMatrix", 87.0}, {"EAN13", 92.0}, {"PDF417", 86.0} } Public Async Function ScanWithMLConfidenceAsync(imageData As Byte(), Optional expectedFormat As String = Nothing) As Task(Of ScanResult) Dim options As New BarcodeReaderOptions With { .Speed = ReadingSpeed.Balanced, .Confidence = ConfidenceLevel.Optional } ' If we know the expected format, improve for it If Not String.IsNullOrEmpty(expectedFormat) AndAlso [Enum].TryParse(Of BarcodeEncoding)(expectedFormat, encoding) Then options.ExpectBarcodeTypes = encoding End If Dim results = Await BarcodeReader.ReadAsync(imageData, options) ' Apply ML confidence filtering Dim confidenceThreshold = If(expectedFormat IsNot Nothing AndAlso _formatConfidenceThresholds.ContainsKey(expectedFormat), _formatConfidenceThresholds(expectedFormat), 80.0) Dim highConfidenceResults = results. Where(Function(r) r.Confidence >= confidenceThreshold). ToList() If highConfidenceResults.Any() Then Return BuildScanResult(highConfidenceResults) End If ' If no high-confidence results, include lower confidence with warnings Dim lowConfidenceResults = results. Where(Function(r) r.Confidence < confidenceThreshold). ToList() If lowConfidenceResults.Any() Then Dim result = BuildScanResult(lowConfidenceResults) result.Metadata("Warning") = "Low confidence results - manual verification recommended" result.Metadata("MinConfidence") = lowConfidenceResults.Min(Function(r) r.Confidence) Return result End If Return New ScanResult With { .Success = False, .ErrorMessage = "No barcodes met confidence threshold" } End Function End Class Private Function BuildScanResult(results As IEnumerable(Of BarcodeResult)) As ScanResult Dim resultList = results.ToList() Return New ScanResult With { .Success = True, .Barcodes = resultList.Select(Function(r) New BarcodeData With { .Value = r.Value, .Format = r.BarcodeType.ToString(), .Confidence = r.Confidence, .Location = r.Bounds }).ToList(), .Metadata = New Dictionary(Of String, Object) From { {"TotalFound", resultList.Count}, {"AverageConfidence", resultList.Average(Function(r) r.Confidence)}, {"Formats", resultList.Select(Function(r) r.BarcodeType.ToString()).Distinct().ToArray()} } } End Function Private Function GetStrategyName(attemptIndex As Integer) As String Return attemptIndex Select Case { 0 : "FastScan", 1 : "StandardEnhanced", 2 : "DetailedFiltering", 3 : "ExtremeDamageRecovery", Else : "Unknown" } End Function End Class ' Supporting classes Public Class ScanSettings Public Property Options As BarcodeReaderOptions = New BarcodeReaderOptions() Public Property UseRegionScanning As Boolean Public Property CustomRegions As List(Of Rectangle) End Class ' Benchmark service for performance testing Public Class BenchmarkService Private ReadOnly _logger As ILogger(Of BenchmarkService) Public Async Function BenchmarkSettingsAsync(testImage As Byte(), Optional iterations As Integer = 10) As Task(Of BenchmarkResult) Dim results As New Dictionary(Of String, BenchmarkData)() Dim testConfigurations = New Dictionary(Of String, BarcodeReaderOptions) From { {"Fastest", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Faster}}, {"Balanced", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Balanced}}, {"Detailed", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Detailed}}, {"Parallel", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Balanced, .Multithreaded = True, .MaxParallelThreads = 4}}, {"Filtered", New BarcodeReaderOptions With {.Speed = ReadingSpeed.Balanced, .ImageFilters = New ImageFilterCollection From {New SharpenFilter(2), New ContrastFilter(1.5F)}}} } For Each config In testConfigurations Dim times As New List(Of Long)() Dim successCount = 0 For i = 0 To iterations - 1 Dim sw = Stopwatch.StartNew() Dim scanResults = Await BarcodeReader.ReadAsync(testImage, config.Value) sw.Stop() times.Add(sw.ElapsedMilliseconds) If scanResults.Any() Then successCount += 1 ' Small delay between tests Await Task.Delay(100) Next results(config.Key) = New BenchmarkData With { .AverageMs = times.Average(), .MinMs = times.Min(), .MaxMs = times.Max(), .SuccessRate = CDbl(successCount) / iterations * 100 } Next Return New BenchmarkResult With {.Results = results} End Function End Class Public Class BenchmarkData Public Property AverageMs As Double Public Property MinMs As Long Public Property MaxMs As Long Public Property SuccessRate As Double End Class Public Class BenchmarkResult Public Property Results As Dictionary(Of String, BenchmarkData) End Class $vbLabelText $csharpLabel 這種先進的最佳化方法展示了多種專業技術。 智慧型設定確定功能透過分析影像特性自動選擇最佳處理參數。 現代相機拍攝的高解析度影像可以使用更快的處理速度,而低品質掃描影像則可以進行增強的濾波處理。 區域掃描對於大幅面文件尤其有效。 透過將影像分割成多個區域並並行處理,可以顯著提高效能。 這種方法對於條碼位置可預測的標準化表格尤其有效。 選擇合適的ReadingSpeed設定 自適應增強方法會逐步嘗試更激進的處理技術,直到成功為止。 這樣既能確保高品質條碼得到最快的處理,又能成功處理損壞的條碼。 置信度閾值功能利用機器學習來驗證結果,從而減少生產環境中的誤報。 針對特定最佳化場景: -大批量處理:使用ReadingSpeed.Faster並進行特定條碼類型篩選 -混合品質文件:首先使用ReadingSpeed.Balanced ,然後實施自適應增強 -條碼損壞或老化:請使用完整影像濾鏡的ReadingSpeed.ExtremeDetail -即時應用:實施快取和基於區域的掃描,以確保效能穩定。 基準測試服務可協助您根據數據做出配置決策。 使用實際條碼樣本進行基準測試,以找到適合您特定用例的速度和準確性之間的最佳平衡點。 影像濾波器的影響 影像濾波器可以顯著提高複雜條碼的辨識率。 影像校正文件解釋了每個濾波器的用途。 但是,濾鏡也會增加處理時間,所以要謹慎使用。 對於企業部署,可以考慮採用分層方法: 首次嘗試快速掃描,不使用過濾器 如果第一次嘗試失敗,則套用基本過濾器。 僅在必要時才使用強力過濾。 快取結果以避免重複處理 該策略在保持快速平均回應時間的同時,也能成功處理疑難案件。 對於使用者可能以各種角度握持裝置的行動裝置拍攝的照片而言,方向校正功能尤其有價值。 在 C# 中建立二維碼圖像 掃描固然重要,但許多企業應用程式也需要產生條碼。 IronBarcode 讓建立條碼就像讀取條碼一樣簡單。 以下是如何在各種企業場景下產生二維碼的方法: public class BarcodeGenerationService { private readonly ILogger<BarcodeGenerationService> _logger; // Generate QR codes for asset tracking public byte[] GenerateAssetQRCode(AssetInfo asset) { // Create JSON payload with asset information var assetData = JsonSerializer.Serialize(new { Id = asset.AssetId, Type = asset.AssetType, Location = asset.CurrentLocation, LastMaintenance = asset.LastMaintenanceDate, Url = "___PROTECTED_URL_45___" }); // Generate QR code with high error correction for durability var qrCode = QRCodeWriter.CreateQrCode(assetData, 500, QRCodeWriter.QrErrorCorrectionLevel.High); // Add company branding qrCode.AddAnnotationTextAboveBarcode($"ASSET: {asset.AssetId}"); qrCode.AddAnnotationTextBelowBarcode(asset.AssetType); qrCode.SetMargins(10); // Style for printing on asset labels qrCode.ChangeBarCodeColor(Color.Black); qrCode.ChangeBackgroundColor(Color.White); return qrCode.ToStream().ToArray(); } // Generate visitor badges with QR codes public GeneratedBarcode CreateVisitorBadgeQR(VisitorInfo visitor) { // Encode visitor information with expiration var visitorData = new { Name = visitor.Name, Company = visitor.Company, Host = visitor.HostEmployee, ValidFrom = visitor.CheckInTime, ValidUntil = visitor.CheckInTime.AddHours(8), AccessLevel = visitor.AccessLevel, BadgeId = Guid.NewGuid().ToString() }; var qrCode = QRCodeWriter.CreateQrCode( JsonSerializer.Serialize(visitorData), 400, QRCodeWriter.QrErrorCorrectionLevel.Medium ); // Add company logo for professional appearance if (File.Exists("company-logo.png")) { qrCode.AddLogo("company-logo.png"); } // Style for badge printing qrCode.SetMargins(15); qrCode.ChangeBarCodeColor(Color.FromArgb(0, 48, 135)); // Company blue // Add visible text for security personnel qrCode.AddAnnotationTextAboveBarcode($"VISITOR: {visitor.Name}"); qrCode.AddAnnotationTextBelowBarcode($"Expires: {visitor.CheckInTime.AddHours(8):HH:mm}"); _logger.LogInformation($"Generated visitor badge for {visitor.Name}, BadgeId: {visitorData.BadgeId}"); return qrCode; } // Generate shipping labels with multiple barcodes public byte[] GenerateShippingLabel(ShippingInfo shipping) { // Create a PDF with multiple barcodes var pdf = new IronPdf.ChromePdfRenderer(); // Generate tracking barcode (Code 128 for USPS/UPS compatibility) var trackingBarcode = BarcodeWriter.CreateBarcode( shipping.TrackingNumber, BarcodeEncoding.Code128 ); trackingBarcode.ResizeTo(300, 75); trackingBarcode.SetMargins(5); // Generate postal code barcode var postalBarcode = BarcodeWriter.CreateBarcode( shipping.PostalCode, BarcodeEncoding.Code128 ); postalBarcode.ResizeTo(200, 50); // Generate QR code with complete shipping data var shippingData = JsonSerializer.Serialize(shipping); var qrCode = QRCodeWriter.CreateQrCode(shippingData, 200); // Combine into shipping label HTML var labelHtml = $@ <html> <body style='font-family: Arial, sans-serif;'> <div style='border: 2px solid black; padding: 20px; width: 4in; height: 6in;'> <h2>SHIPPING LABEL</h2> <hr/> <p><strong>From:</strong><br/>{shipping.SenderAddress}</p> <p><strong>To:</strong><br/>{shipping.RecipientAddress}</p> <hr/> <div style='text-align: center;'> <img src='{trackingBarcode.ToDataUrl()}' alt='Tracking barcode'/> <p>Tracking: {shipping.TrackingNumber}</p> </div> <div style='margin-top: 20px;'> <img src='{postalBarcode.ToDataUrl()}' alt='Postal barcode' style='float: left;'/> <img src='{qrCode.ToDataUrl()}' alt='Shipping QR code' style='float: right; width: 100px;'/> </div> <div style='clear: both; margin-top: 20px; font-size: 10px;'> <p>Service: {shipping.ServiceType} | Weight: {shipping.Weight}lbs</p> </div> </div> </body> </html>"; return pdf.RenderHtmlAsPdf(labelHtml).BinaryData; } // Generate secure document QR codes with encryption public class SecureDocumentQR { private readonly byte[] _encryptionKey; public SecureDocumentQR(byte[] encryptionKey) { _encryptionKey = encryptionKey; } public GeneratedBarcode GenerateSecureDocumentQR(DocumentInfo document) { // Create document reference with security features var documentRef = new { DocumentId = document.Id, Type = document.DocumentType, CreatedDate = document.CreatedDate, Hash = ComputeDocumentHash(document), AccessUrl = "___PROTECTED_URL_46___", ValidUntil = DateTime.UtcNow.AddDays(30) }; // Encrypt sensitive data var jsonData = JsonSerializer.Serialize(documentRef); var encryptedData = EncryptData(jsonData); // Generate QR with encrypted payload var qrCode = QRCodeWriter.CreateQrCode( Convert.ToBase64String(encryptedData), 500, QRCodeWriter.QrErrorCorrectionLevel.High ); // Add visual security indicators qrCode.ChangeBarCodeColor(Color.DarkGreen); qrCode.AddAnnotationTextAboveBarcode("SECURE DOCUMENT"); qrCode.AddAnnotationTextBelowBarcode($"Expires: {documentRef.ValidUntil:yyyy-MM-dd}"); return qrCode; } private string ComputeDocumentHash(DocumentInfo document) { using var sha256 = SHA256.Create(); var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(document.Content ?? document.Id)); return BitConverter.ToString(hash).Replace("-", ""); } private byte[] EncryptData(string data) { // Simplified encryption - use proper encryption in production using var aes = Aes.Create(); aes.Key = _encryptionKey; aes.GenerateIV(); using var encryptor = aes.CreateEncryptor(); var dataBytes = Encoding.UTF8.GetBytes(data); var encrypted = encryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length); // Prepend IV for decryption return aes.IV.Concat(encrypted).ToArray(); } } // Batch generation for high-volume scenarios public async Task<List<GeneratedBarcode>> GenerateBatchQRCodesAsync(List<string> data, QRCodeOptions options) { var tasks = data.Select(item => Task.Run(() => { var qr = QRCodeWriter.CreateQrCode( item, options.Size, options.ErrorCorrection ); if (options.IncludeMargins) qr.SetMargins(options.MarginSize); if (options.CustomColor.HasValue) qr.ChangeBarCodeColor(options.CustomColor.Value); return qr; })); return (await Task.WhenAll(tasks)).ToList(); } } // Supporting models public class AssetInfo { public string AssetId { get; set; } public string AssetType { get; set; } public string CurrentLocation { get; set; } public DateTime LastMaintenanceDate { get; set; } } public class VisitorInfo { public string Name { get; set; } public string Company { get; set; } public string HostEmployee { get; set; } public DateTime CheckInTime { get; set; } public string AccessLevel { get; set; } } public class ShippingInfo { public string TrackingNumber { get; set; } public string SenderAddress { get; set; } public string RecipientAddress { get; set; } public string PostalCode { get; set; } public string ServiceType { get; set; } public decimal Weight { get; set; } } public class DocumentInfo { public string Id { get; set; } public string DocumentType { get; set; } public DateTime CreatedDate { get; set; } public string Content { get; set; } } public class QRCodeOptions { public int Size { get; set; } = 400; public QRCodeWriter.QrErrorCorrectionLevel ErrorCorrection { get; set; } = QRCodeWriter.QrErrorCorrectionLevel.Medium; public bool IncludeMargins { get; set; } = true; public int MarginSize { get; set; } = 10; public Color? CustomColor { get; set; } } public class BarcodeGenerationService { private readonly ILogger<BarcodeGenerationService> _logger; // Generate QR codes for asset tracking public byte[] GenerateAssetQRCode(AssetInfo asset) { // Create JSON payload with asset information var assetData = JsonSerializer.Serialize(new { Id = asset.AssetId, Type = asset.AssetType, Location = asset.CurrentLocation, LastMaintenance = asset.LastMaintenanceDate, Url = "___PROTECTED_URL_45___" }); // Generate QR code with high error correction for durability var qrCode = QRCodeWriter.CreateQrCode(assetData, 500, QRCodeWriter.QrErrorCorrectionLevel.High); // Add company branding qrCode.AddAnnotationTextAboveBarcode($"ASSET: {asset.AssetId}"); qrCode.AddAnnotationTextBelowBarcode(asset.AssetType); qrCode.SetMargins(10); // Style for printing on asset labels qrCode.ChangeBarCodeColor(Color.Black); qrCode.ChangeBackgroundColor(Color.White); return qrCode.ToStream().ToArray(); } // Generate visitor badges with QR codes public GeneratedBarcode CreateVisitorBadgeQR(VisitorInfo visitor) { // Encode visitor information with expiration var visitorData = new { Name = visitor.Name, Company = visitor.Company, Host = visitor.HostEmployee, ValidFrom = visitor.CheckInTime, ValidUntil = visitor.CheckInTime.AddHours(8), AccessLevel = visitor.AccessLevel, BadgeId = Guid.NewGuid().ToString() }; var qrCode = QRCodeWriter.CreateQrCode( JsonSerializer.Serialize(visitorData), 400, QRCodeWriter.QrErrorCorrectionLevel.Medium ); // Add company logo for professional appearance if (File.Exists("company-logo.png")) { qrCode.AddLogo("company-logo.png"); } // Style for badge printing qrCode.SetMargins(15); qrCode.ChangeBarCodeColor(Color.FromArgb(0, 48, 135)); // Company blue // Add visible text for security personnel qrCode.AddAnnotationTextAboveBarcode($"VISITOR: {visitor.Name}"); qrCode.AddAnnotationTextBelowBarcode($"Expires: {visitor.CheckInTime.AddHours(8):HH:mm}"); _logger.LogInformation($"Generated visitor badge for {visitor.Name}, BadgeId: {visitorData.BadgeId}"); return qrCode; } // Generate shipping labels with multiple barcodes public byte[] GenerateShippingLabel(ShippingInfo shipping) { // Create a PDF with multiple barcodes var pdf = new IronPdf.ChromePdfRenderer(); // Generate tracking barcode (Code 128 for USPS/UPS compatibility) var trackingBarcode = BarcodeWriter.CreateBarcode( shipping.TrackingNumber, BarcodeEncoding.Code128 ); trackingBarcode.ResizeTo(300, 75); trackingBarcode.SetMargins(5); // Generate postal code barcode var postalBarcode = BarcodeWriter.CreateBarcode( shipping.PostalCode, BarcodeEncoding.Code128 ); postalBarcode.ResizeTo(200, 50); // Generate QR code with complete shipping data var shippingData = JsonSerializer.Serialize(shipping); var qrCode = QRCodeWriter.CreateQrCode(shippingData, 200); // Combine into shipping label HTML var labelHtml = $@ <html> <body style='font-family: Arial, sans-serif;'> <div style='border: 2px solid black; padding: 20px; width: 4in; height: 6in;'> <h2>SHIPPING LABEL</h2> <hr/> <p><strong>From:</strong><br/>{shipping.SenderAddress}</p> <p><strong>To:</strong><br/>{shipping.RecipientAddress}</p> <hr/> <div style='text-align: center;'> <img src='{trackingBarcode.ToDataUrl()}' alt='Tracking barcode'/> <p>Tracking: {shipping.TrackingNumber}</p> </div> <div style='margin-top: 20px;'> <img src='{postalBarcode.ToDataUrl()}' alt='Postal barcode' style='float: left;'/> <img src='{qrCode.ToDataUrl()}' alt='Shipping QR code' style='float: right; width: 100px;'/> </div> <div style='clear: both; margin-top: 20px; font-size: 10px;'> <p>Service: {shipping.ServiceType} | Weight: {shipping.Weight}lbs</p> </div> </div> </body> </html>"; return pdf.RenderHtmlAsPdf(labelHtml).BinaryData; } // Generate secure document QR codes with encryption public class SecureDocumentQR { private readonly byte[] _encryptionKey; public SecureDocumentQR(byte[] encryptionKey) { _encryptionKey = encryptionKey; } public GeneratedBarcode GenerateSecureDocumentQR(DocumentInfo document) { // Create document reference with security features var documentRef = new { DocumentId = document.Id, Type = document.DocumentType, CreatedDate = document.CreatedDate, Hash = ComputeDocumentHash(document), AccessUrl = "___PROTECTED_URL_46___", ValidUntil = DateTime.UtcNow.AddDays(30) }; // Encrypt sensitive data var jsonData = JsonSerializer.Serialize(documentRef); var encryptedData = EncryptData(jsonData); // Generate QR with encrypted payload var qrCode = QRCodeWriter.CreateQrCode( Convert.ToBase64String(encryptedData), 500, QRCodeWriter.QrErrorCorrectionLevel.High ); // Add visual security indicators qrCode.ChangeBarCodeColor(Color.DarkGreen); qrCode.AddAnnotationTextAboveBarcode("SECURE DOCUMENT"); qrCode.AddAnnotationTextBelowBarcode($"Expires: {documentRef.ValidUntil:yyyy-MM-dd}"); return qrCode; } private string ComputeDocumentHash(DocumentInfo document) { using var sha256 = SHA256.Create(); var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(document.Content ?? document.Id)); return BitConverter.ToString(hash).Replace("-", ""); } private byte[] EncryptData(string data) { // Simplified encryption - use proper encryption in production using var aes = Aes.Create(); aes.Key = _encryptionKey; aes.GenerateIV(); using var encryptor = aes.CreateEncryptor(); var dataBytes = Encoding.UTF8.GetBytes(data); var encrypted = encryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length); // Prepend IV for decryption return aes.IV.Concat(encrypted).ToArray(); } } // Batch generation for high-volume scenarios public async Task<List<GeneratedBarcode>> GenerateBatchQRCodesAsync(List<string> data, QRCodeOptions options) { var tasks = data.Select(item => Task.Run(() => { var qr = QRCodeWriter.CreateQrCode( item, options.Size, options.ErrorCorrection ); if (options.IncludeMargins) qr.SetMargins(options.MarginSize); if (options.CustomColor.HasValue) qr.ChangeBarCodeColor(options.CustomColor.Value); return qr; })); return (await Task.WhenAll(tasks)).ToList(); } } // Supporting models public class AssetInfo { public string AssetId { get; set; } public string AssetType { get; set; } public string CurrentLocation { get; set; } public DateTime LastMaintenanceDate { get; set; } } public class VisitorInfo { public string Name { get; set; } public string Company { get; set; } public string HostEmployee { get; set; } public DateTime CheckInTime { get; set; } public string AccessLevel { get; set; } } public class ShippingInfo { public string TrackingNumber { get; set; } public string SenderAddress { get; set; } public string RecipientAddress { get; set; } public string PostalCode { get; set; } public string ServiceType { get; set; } public decimal Weight { get; set; } } public class DocumentInfo { public string Id { get; set; } public string DocumentType { get; set; } public DateTime CreatedDate { get; set; } public string Content { get; set; } } public class QRCodeOptions { public int Size { get; set; } = 400; public QRCodeWriter.QrErrorCorrectionLevel ErrorCorrection { get; set; } = QRCodeWriter.QrErrorCorrectionLevel.Medium; public bool IncludeMargins { get; set; } = true; public int MarginSize { get; set; } = 10; public Color? CustomColor { get; set; } } Imports System Imports System.Collections.Generic Imports System.IO Imports System.Linq Imports System.Security.Cryptography Imports System.Text Imports System.Text.Json Imports System.Threading.Tasks Public Class BarcodeGenerationService Private ReadOnly _logger As ILogger(Of BarcodeGenerationService) ' Generate QR codes for asset tracking Public Function GenerateAssetQRCode(asset As AssetInfo) As Byte() ' Create JSON payload with asset information Dim assetData = JsonSerializer.Serialize(New With { .Id = asset.AssetId, .Type = asset.AssetType, .Location = asset.CurrentLocation, .LastMaintenance = asset.LastMaintenanceDate, .Url = "___PROTECTED_URL_45___" }) ' Generate QR code with high error correction for durability Dim qrCode = QRCodeWriter.CreateQrCode(assetData, 500, QRCodeWriter.QrErrorCorrectionLevel.High) ' Add company branding qrCode.AddAnnotationTextAboveBarcode($"ASSET: {asset.AssetId}") qrCode.AddAnnotationTextBelowBarcode(asset.AssetType) qrCode.SetMargins(10) ' Style for printing on asset labels qrCode.ChangeBarCodeColor(Color.Black) qrCode.ChangeBackgroundColor(Color.White) Return qrCode.ToStream().ToArray() End Function ' Generate visitor badges with QR codes Public Function CreateVisitorBadgeQR(visitor As VisitorInfo) As GeneratedBarcode ' Encode visitor information with expiration Dim visitorData = New With { .Name = visitor.Name, .Company = visitor.Company, .Host = visitor.HostEmployee, .ValidFrom = visitor.CheckInTime, .ValidUntil = visitor.CheckInTime.AddHours(8), .AccessLevel = visitor.AccessLevel, .BadgeId = Guid.NewGuid().ToString() } Dim qrCode = QRCodeWriter.CreateQrCode( JsonSerializer.Serialize(visitorData), 400, QRCodeWriter.QrErrorCorrectionLevel.Medium ) ' Add company logo for professional appearance If File.Exists("company-logo.png") Then qrCode.AddLogo("company-logo.png") End If ' Style for badge printing qrCode.SetMargins(15) qrCode.ChangeBarCodeColor(Color.FromArgb(0, 48, 135)) ' Company blue ' Add visible text for security personnel qrCode.AddAnnotationTextAboveBarcode($"VISITOR: {visitor.Name}") qrCode.AddAnnotationTextBelowBarcode($"Expires: {visitor.CheckInTime.AddHours(8):HH:mm}") _logger.LogInformation($"Generated visitor badge for {visitor.Name}, BadgeId: {visitorData.BadgeId}") Return qrCode End Function ' Generate shipping labels with multiple barcodes Public Function GenerateShippingLabel(shipping As ShippingInfo) As Byte() ' Create a PDF with multiple barcodes Dim pdf = New IronPdf.ChromePdfRenderer() ' Generate tracking barcode (Code 128 for USPS/UPS compatibility) Dim trackingBarcode = BarcodeWriter.CreateBarcode( shipping.TrackingNumber, BarcodeEncoding.Code128 ) trackingBarcode.ResizeTo(300, 75) trackingBarcode.SetMargins(5) ' Generate postal code barcode Dim postalBarcode = BarcodeWriter.CreateBarcode( shipping.PostalCode, BarcodeEncoding.Code128 ) postalBarcode.ResizeTo(200, 50) ' Generate QR code with complete shipping data Dim shippingData = JsonSerializer.Serialize(shipping) Dim qrCode = QRCodeWriter.CreateQrCode(shippingData, 200) ' Combine into shipping label HTML Dim labelHtml = $" <html> <body style='font-family: Arial, sans-serif;'> <div style='border: 2px solid black; padding: 20px; width: 4in; height: 6in;'> <h2>SHIPPING LABEL</h2> <hr/> <p><strong>From:</strong><br/>{shipping.SenderAddress}</p> <p><strong>To:</strong><br/>{shipping.RecipientAddress}</p> <hr/> <div style='text-align: center;'> <img src='{trackingBarcode.ToDataUrl()}' alt='Tracking barcode'/> <p>Tracking: {shipping.TrackingNumber}</p> </div> <div style='margin-top: 20px;'> <img src='{postalBarcode.ToDataUrl()}' alt='Postal barcode' style='float: left;'/> <img src='{qrCode.ToDataUrl()}' alt='Shipping QR code' style='float: right; width: 100px;'/> </div> <div style='clear: both; margin-top: 20px; font-size: 10px;'> <p>Service: {shipping.ServiceType} | Weight: {shipping.Weight}lbs</p> </div> </div> </body> </html>" Return pdf.RenderHtmlAsPdf(labelHtml).BinaryData End Function ' Generate secure document QR codes with encryption Public Class SecureDocumentQR Private ReadOnly _encryptionKey As Byte() Public Sub New(encryptionKey As Byte()) _encryptionKey = encryptionKey End Sub Public Function GenerateSecureDocumentQR(document As DocumentInfo) As GeneratedBarcode ' Create document reference with security features Dim documentRef = New With { .DocumentId = document.Id, .Type = document.DocumentType, .CreatedDate = document.CreatedDate, .Hash = ComputeDocumentHash(document), .AccessUrl = "___PROTECTED_URL_46___", .ValidUntil = DateTime.UtcNow.AddDays(30) } ' Encrypt sensitive data Dim jsonData = JsonSerializer.Serialize(documentRef) Dim encryptedData = EncryptData(jsonData) ' Generate QR with encrypted payload Dim qrCode = QRCodeWriter.CreateQrCode( Convert.ToBase64String(encryptedData), 500, QRCodeWriter.QrErrorCorrectionLevel.High ) ' Add visual security indicators qrCode.ChangeBarCodeColor(Color.DarkGreen) qrCode.AddAnnotationTextAboveBarcode("SECURE DOCUMENT") qrCode.AddAnnotationTextBelowBarcode($"Expires: {documentRef.ValidUntil:yyyy-MM-dd}") Return qrCode End Function Private Function ComputeDocumentHash(document As DocumentInfo) As String Using sha256 = SHA256.Create() Dim hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(If(document.Content, document.Id))) Return BitConverter.ToString(hash).Replace("-", "") End Using End Function Private Function EncryptData(data As String) As Byte() ' Simplified encryption - use proper encryption in production Using aes = Aes.Create() aes.Key = _encryptionKey aes.GenerateIV() Using encryptor = aes.CreateEncryptor() Dim dataBytes = Encoding.UTF8.GetBytes(data) Dim encrypted = encryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length) ' Prepend IV for decryption Return aes.IV.Concat(encrypted).ToArray() End Using End Using End Function End Class ' Batch generation for high-volume scenarios Public Async Function GenerateBatchQRCodesAsync(data As List(Of String), options As QRCodeOptions) As Task(Of List(Of GeneratedBarcode)) Dim tasks = data.Select(Function(item) Task.Run(Function() Dim qr = QRCodeWriter.CreateQrCode( item, options.Size, options.ErrorCorrection ) If options.IncludeMargins Then qr.SetMargins(options.MarginSize) End If If options.CustomColor.HasValue Then qr.ChangeBarCodeColor(options.CustomColor.Value) End If Return qr End Function)) Return (Await Task.WhenAll(tasks)).ToList() End Function End Class ' Supporting models Public Class AssetInfo Public Property AssetId As String Public Property AssetType As String Public Property CurrentLocation As String Public Property LastMaintenanceDate As DateTime End Class Public Class VisitorInfo Public Property Name As String Public Property Company As String Public Property HostEmployee As String Public Property CheckInTime As DateTime Public Property AccessLevel As String End Class Public Class ShippingInfo Public Property TrackingNumber As String Public Property SenderAddress As String Public Property RecipientAddress As String Public Property PostalCode As String Public Property ServiceType As String Public Property Weight As Decimal End Class Public Class DocumentInfo Public Property Id As String Public Property DocumentType As String Public Property CreatedDate As DateTime Public Property Content As String End Class Public Class QRCodeOptions Public Property Size As Integer = 400 Public Property ErrorCorrection As QRCodeWriter.QrErrorCorrectionLevel = QRCodeWriter.QrErrorCorrectionLevel.Medium Public Property IncludeMargins As Boolean = True Public Property MarginSize As Integer = 10 Public Property CustomColor As Color? End Class $vbLabelText $csharpLabel 這些生成範例展示了企業特定的使用案例。 資產追蹤二維碼包含維護歷史記錄和與資產管理系統的直接連結。 訪客證包含有效期限和存取權限級別,以符合安全規定。 運輸標籤結合了多種條碼格式,以滿足承運商的要求。 安全文檔二維碼實作展示如何為敏感資料整合加密。 這種方法確保即使有人取得了二維碼,也沒有正確的解密金鑰,也無法存取其中的資訊。 這對於合規文件、財務記錄或機密通訊至關重要。 生產部署的後續步驟 使用 IronBarcode 建立企業級條碼掃描器 API 為數位轉型計畫提供了可靠的基礎。 全面的格式支援、先進的影像處理和跨平台相容性相結合,滿足了現代企業的複雜需求。 實施過程中需要注意的關鍵要點: 1.安全第一:從一開始就實施適當的身份驗證、輸入驗證和稽核日誌記錄 2.效能最佳化:根據您的使用場景選擇合適的掃描速度和快取策略 3.錯誤處理:建構能夠優雅地處理極端情況並提供有效回饋的彈性系統 4.可擴展性:設計時要考慮橫向擴展,利用非同步模式和高效率的資源管理 對於生產環境部署,請考慮以下額外資源: 查看更新日誌,了解最新功能和改進 探索新的格式支持,包括專門的企業格式 實作桌面應用程式的MSI 安裝程式部署 為生產環境正確配置許可證密鑰 IronBarcode 的企業級功能不僅限於基本的掃描功能。 此庫的樣式自訂功能支援產生品牌條碼。 支援Unicode條碼可確保全球相容性。 條碼邊距和糾錯等級等進階功能可對輸出品質進行精細控制。 企業支持和資源 在實施關鍵任務條碼解決方案時,擁有可靠的支援至關重要。 IronBarcode提供: 提供具有服務等級協定 (SLA) 保障的專屬企業支持 -工程請求支援定制需求 定期安全性更新和 CVE 監控 常見場景的完整故障排除指南 從人工條碼處理到自動化 API 驅動的處理流程,徹底改變了營運效率。 無論您是處理數千份貨運單據、管理訪客存取權限,還是追蹤企業資產,IronBarcode 都能提供企業環境所需的可靠性和功能。 準備好革新您的條碼處理流程了嗎? 立即開始免費試用,體驗專業條碼處理帶來的不同。 完整的API 文件提供了詳細的實作指南,而範例部分則提供了常見場景的即用程式碼。 您的企業需要一個能夠隨著您的需求擴展、保持安全合規性並在所有平台上提供一致結果的條碼解決方案。 IronBarcode 正是為此而生——公司致力於長期支持和持續改進。 立即開始建立您的掃描器 API,加入數千家信賴 IronBarcode 以滿足其關鍵條碼處理需求的企業行列。 常見問題解答 使用 IronBarcode 在 C# 中建立掃描器 API 的主要優勢是什麼? IronBarcode 讓開發人員能夠以最小的複雜度快速建立功能強大、可用於生產環境的條碼掃描器 API。它簡化了流程,無需整合複雜的掃描器 SDK。 IronBarcode 能否處理損壞的條碼輸入? 是的,IronBarcode 的設計宗旨是即使掃描輸入損壞也能處理條碼數據,從而確保在實際應用中具有高可靠性。 IronBarcode 的 C# 掃描器 API 可以處理哪些類型的輸入? IronBarcode 可以處理來自影像和 PDF 等各種輸入的條碼數據,為不同的掃描需求提供多樣化的解決方案。 是否有關於如何使用 IronBarcode 建立條碼掃描器 API 的教學課程? 是的,網頁提供了全面的教學和程式碼範例,指導開發人員使用 IronBarcode 來建立 RESTful 條碼掃描端點。 使用 IronBarcode 可以多快設定好條碼掃描器 API? 借助 IronBarcode,開發人員可以在幾分鐘內設定條碼掃描器 API,從而簡化開發時間和精力。 IronBarcode是否需要複雜的SDK整合? 不,IronBarcode 消除了對複雜掃描器 SDK 整合的需求,使開發人員更容易實現條碼掃描功能。 IronBarcode 使用哪種程式語言來建立掃描器 API? IronBarcode 與 C# 結合使用,建立掃描器 API,並利用 .NET 框架來實現強大的效能。 Curtis Chau 立即與工程團隊聊天 技術撰稿人 Curtis Chau 擁有電腦科學學士學位(卡爾頓大學),專長於前端開發,精通 Node.js、TypeScript、JavaScript 和 React。Curtis 對製作直覺且美觀的使用者介面充滿熱情,他喜歡使用現代化的架構,並製作結構良好且視覺上吸引人的手冊。除了開發之外,Curtis 對物聯網 (IoT) 也有濃厚的興趣,他喜歡探索整合硬體與軟體的創新方式。在空閒時間,他喜歡玩遊戲和建立 Discord bots,將他對技術的熱愛與創意結合。 相關文章 更新2026年1月22日 ASP.NET 條碼掃描器教學:C# 條碼產生器指南 學習如何使用 IronBarcode 在 ASP.NET 中掃描條碼 閱讀更多 發表日期 2026年1月21日 C# 資料矩陣產生器:IronBarcode 完整指南 C# 資料矩陣條碼產生器教學。學習如何使用 IronBarcode 建立 ECC200 資料矩陣條碼。提供簡單的二維條碼生成程式碼範例。 閱讀更多 發表日期 2026年1月21日 使用 IronBarcode 的 Xamarin 條碼產生器建立專業品質的條碼 使用 IronBarcode 和 Xamarin 條碼產生器,學習如何建立專業品質的條碼。 閱讀更多 MAUI條碼掃描器教學:攝影機與IronBarcode集成如何使用VB.NET在Crystal Report...
發表日期 2026年1月21日 C# 資料矩陣產生器:IronBarcode 完整指南 C# 資料矩陣條碼產生器教學。學習如何使用 IronBarcode 建立 ECC200 資料矩陣條碼。提供簡單的二維條碼生成程式碼範例。 閱讀更多
發表日期 2026年1月21日 使用 IronBarcode 的 Xamarin 條碼產生器建立專業品質的條碼 使用 IronBarcode 和 Xamarin 條碼產生器,學習如何建立專業品質的條碼。 閱讀更多