USING IRONBARCODE 使用 IronBarcode 创建 C# 扫描仪 API Jordi Bardia 已发布: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 构建扫描器 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年1月22日 ASP.NET 条码扫描器教程:C# BarCode 生成器指南 Learn how to Scan Barcodes in ASP.NET using IronBarcode 阅读更多 已发布2026年1月21日 C# 中的数据矩阵生成器:IronBarcode 完整指南 数据矩阵生成器C#教程。了解如何使用IronBarcode创建ECC200数据矩阵条形码。简单的2D条码生成代码示例。 阅读更多 已发布2026年1月21日 使用 IronBarcode 的 Xamarin 条码生成器创建专业品质的条码 Learn how to create professional-quality barcodes with the Xamarin Barcode Generator using IronBarcode. 阅读更多 MAUI 条码扫描器教程:摄像头与 IronBarcode 集成如何使用 VB .NET 在 Crystal Re...
已更新2026年1月22日 ASP.NET 条码扫描器教程:C# BarCode 生成器指南 Learn how to Scan Barcodes in ASP.NET using IronBarcode 阅读更多
已发布2026年1月21日 C# 中的数据矩阵生成器:IronBarcode 完整指南 数据矩阵生成器C#教程。了解如何使用IronBarcode创建ECC200数据矩阵条形码。简单的2D条码生成代码示例。 阅读更多
已发布2026年1月21日 使用 IronBarcode 的 Xamarin 条码生成器创建专业品质的条码 Learn how to create professional-quality barcodes with the Xamarin Barcode Generator using IronBarcode. 阅读更多