使用IRONBARCODE 在C#中建立條碼掃描器API(開發者指南) Jordi Bardia 更新:2026年2月27日 下載 IronBarcode NuGet 下載 DLL 下載 開始免費試用 LLM副本 LLM副本 將頁面複製為 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透過簡單的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}"); } } } $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" }; } } } $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; } } $vbLabelText $csharpLabel 這個完整實施方案針對的是現實世界的企業場景。 URL 掃描端點包含網域驗證,以防止伺服器端要求偽造 (SSRF) 攻擊。 Base64 處理程序會移除資料 URL 前綴,這在從 Web 應用程式接收圖片時很常見。 損壞的條碼端點展示了 IronBarcode 的影像校正功能。 透過應用多種濾波器並嘗試不同的方法,它可以從嚴重退化的圖像中恢復資料。 在處理舊的庫存標籤或受天氣損壞的運輸單據時,這非常有用。 選擇PDF掃描還是影像掃描 PDF 檔案為企業條碼掃描帶來了獨特的挑戰和機會。 許多商業文件,如發票、發貨清單和合規表格,都是以帶有嵌入式條碼的 PDF 格式提供的。 IronBarcode的PDF 條碼讀取功能可以很好地處理這些情況。 設想一個典型的企業情境:您的應付帳款部門每月收到數千張發票,每張發票都包含用於自動處理的條碼。 有些供應商發送高品質的PDF文件,有些供應商發送品質參差不齊的掃描文件。 進階PDF掃描終端可以處理這兩種情況。 對於高品質 PDF 文件,標準設定即可完美滿足需求。 對於掃描文檔,提高 DPI 和縮放參數可以提高偵測率。 頁面特定處理功能可讓您從特定頁面提取條碼,當您知道發票的第一頁總是有條碼時,此功能非常有用。 按頁面分組的結果提供了有價值的背景資訊。 您的工作流程系統可以根據哪些頁麵包含條碼來路由文檔,從而實現文檔分類的自動化。 這種結構化的多頁文件處理方法將手動流程轉變為高效的自動化工作流程。 高效率處理多個條碼 企業文件通常包含多個條碼,用於不同的用途。 運輸標籤可能包含追蹤條碼、產品條碼和目的地條碼。 妥善處理多種條碼應用程式場景需要周詳的 API 設計。 批次處理端點示範如何有效率地處理大容量場景。 透過並行處理多個文件,可以顯著縮短總處理時間。 Task.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; } } $vbLabelText $csharpLabel 這種先進的最佳化方法展示了多種專業技術。 智慧型設定確定功能透過分析影像特性自動選擇最佳處理參數。 現代相機拍攝的高解析度影像可以使用更快的處理速度,而低品質掃描影像則可以進行增強的濾波處理。 區域掃描對於大幅面文件尤其有效。 透過將影像分割成多個區域並並行處理,可以顯著提高效能。 這種方法對於條碼位置可預測的標準化表格尤其有效。 選擇正確的 ReadingSpeed 設定 自適應增強方法會逐步嘗試更激進的處理技術,直到成功為止。 這樣既能確保高品質條碼得到最快的處理,又能成功處理損壞的條碼。 置信度閾值功能利用機器學習來驗證結果,從而減少生產環境中的誤報。 針對特定的最佳化場景,下表將常見用例與建議設定進行了對應: 按使用場景設定閱讀速度 用例 推薦速度 其他選項 預期的權衡 大批量處理 `Faster` 依預期條碼類型篩選 吞吐量最快;但可能漏掉劣化條碼。 品質參差不齊的文件 `Balanced` 自適應增強回退 速度和精準度平衡良好 破損或老化的條碼 `ExtremeDetail` 完整的影像濾波流程 精度最高;吞吐量較低 即時 API 端點 `Balanced` 快取 + 區域掃描 始終保持在 200 毫秒以下的回應時間 PDF發票提取 `Balanced` DPI 300,縮放比例 3 最適合文本層 PDF 基準測試服務可協助您根據數據做出配置決策。 使用實際條碼樣本進行基準測試,以找到適合您特定用例的速度和準確性之間的最佳平衡點。 微軟針對ASP.NET Core的效能最佳實務中的產業指導原則也直接適用於調整掃描器 API 端點。 影像濾波器的影響 影像濾波器可以顯著提高複雜條碼的辨識率。 影像校正文件解釋了每個濾波器的用途。 但是,濾鏡也會增加處理時間,所以要謹慎使用。 對於企業部署,可以考慮採用分層方法: 首次嘗試快速掃描,不使用過濾器 如果第一次嘗試失敗,則套用基本過濾器。 僅在必要時才使用強力過濾。 快取結果以避免重複處理 該策略在保持快速平均回應時間的同時,也能成功處理疑難案件。 對於使用者可能以各種角度握持裝置的行動裝置拍攝的照片而言,方向校正功能尤其有價值。 如何在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; } } $vbLabelText $csharpLabel 這些生成範例展示了企業特定的使用案例。 資產追蹤二維碼包含維護歷史記錄和與資產管理系統的直接連結。 訪客證包含有效期限和存取權限級別,以符合安全規定。 運輸標籤結合了多種條碼格式,以滿足承運商的要求。 安全文檔二維碼實作展示如何為敏感資料整合加密。 這種方法確保即使有人取得了二維碼,也沒有正確的解密金鑰,也無法存取其中的資訊。 這對於合規文件、財務記錄或機密通訊至關重要。 下一步計劃是什麼? 使用IronBarcode建立企業級條碼掃描器 API 為數位轉型計畫提供了可靠的基礎。 全面的格式支援、先進的影像處理和跨平台相容性相結合,滿足了現代企業複雜的需求。 在最終確定架構之前,查閱GS1 條碼標準文件有助於您了解供應鍊和零售條碼的編碼要求。 對於上面控制器範例中使用的 REST API 設計模式, .NET的 RESTful API 設計指南提供了實用的參考。 在部署到容器環境時, Docker 官方關於.NET映像的文件是選擇基礎映像的權威來源。 實施過程中需要注意的關鍵要點: 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框架提供強大的性能。 Jordi Bardia 立即與工程團隊聊天 軟體工程師 Jordi 在 Python、C# 和 C++ 上最得心應手,當他不在 Iron Software 展現技術時,便在做遊戲編程。在分担產品测测试,產品開發和研究的责任時,Jordi 為持续的產品改進增值。他说这种多样化的经验使他受到挑战并保持参与, 而这也是他与 Iron Software 中工作一大乐趣。Jordi 在佛罗里达州迈阿密长大,曾在佛罗里达大学学习计算机科学和统计学。 相關文章 發表日期 2026年3月8日 創建.NET應用程式的條碼專業SDK 全面的.NET條碼SDK,用於QR Codes、GS1、Data Matrix等。支持.NET 6-10、Core和Framework。 閱讀更多 發表日期 2026年3月8日 構建Barcode SDK C#:通過一個程式庫生成、讀取和掃描條碼 在C#中使用IronBarcode構建條碼SDK功能。生成條碼圖像,從文件掃描多個條碼,並使用一個.NET程式庫讀取QR Code。包含範例代碼。 閱讀更多 更新2026年3月1日 VB .NET條碼字體:如何在沒有字體依賴的情況下生成和列印條碼 在VB.NET中以現代方式處理條碼字體。使用IronBarcode生成Code 39和Code 128條碼圖像-無字體依賴。提供免費試用。 閱讀更多 使用IronBarcode的MAUI條碼掃描器:逐步指南如何使用VB.NET在Crystal Report...
發表日期 2026年3月8日 創建.NET應用程式的條碼專業SDK 全面的.NET條碼SDK,用於QR Codes、GS1、Data Matrix等。支持.NET 6-10、Core和Framework。 閱讀更多
發表日期 2026年3月8日 構建Barcode SDK C#:通過一個程式庫生成、讀取和掃描條碼 在C#中使用IronBarcode構建條碼SDK功能。生成條碼圖像,從文件掃描多個條碼,並使用一個.NET程式庫讀取QR Code。包含範例代碼。 閱讀更多
更新2026年3月1日 VB .NET條碼字體:如何在沒有字體依賴的情況下生成和列印條碼 在VB.NET中以現代方式處理條碼字體。使用IronBarcode生成Code 39和Code 128條碼圖像-無字體依賴。提供免費試用。 閱讀更多