跳至页脚内容
USING IRONBARCODE

ASP.NET条形码扫描器:使用IronBarcode实现文件上传和 REST API

使用 IronBarcode,ASP.NET 中的条形码扫描变得非常简单:通过 NuGet 安装,调用 BarcodeReader.Read(),即可一步获取包含类型、置信度和位置数据的解码值——无需复杂的配置。

条形码扫描是现代网络应用程序的标准要求,为库存管理、文档处理和票据验证工作流程提供支持。 据GS1统计,全球每天有超过 60 亿笔交易使用条形码——这一数字凸显了准确读取条形码对于任何商业系统的重要性。 ISO/IEC 15415标准定义了二维条形码符号的质量指标,而ISO/IEC 15416标准涵盖了一维线性条形码, IronBarcode对这两种标准都提供了原生支持。

本指南向您展示如何使用IronBarcode为您的ASP.NET Core应用程序添加可靠的条形码扫描功能,内容涵盖安装、文件上传处理、REST API 集成和生产部署模式。 到最后,你将拥有Razor页面文件上传扫描器和 JSON API 端点的可用代码,该端点可以接受来自任何客户端的 base64 编码图像。

如何在ASP.NET项目中安装IronBarcode ?

入门只需几分钟。 该库同时支持ASP.NET Core和传统的ASP.NET MVC 应用程序,因此能够适应各种项目类型。Enterprise部署在AzureAWS LambdaDocker 容器上都能完美运行。 该库的机器学习检测功能通过自动应用复杂的图像校正来处理具有挑战性的条形码图像,这在处理使用移动相机在多变的光照条件下拍摄的照片时特别有用。

通过NuGet包管理器安装

在 Visual Studio 中打开软件包管理器控制台并运行:

Install-Package BarCode
Install-Package BarCode
SHELL

或者,使用.NET CLI:

dotnet add package BarCode
dotnet add package BarCode
SHELL

或者在 Visual Studio NuGet程序包管理器 UI 中搜索"BarCode",然后单击"安装"。 该软件包会自动管理所有依赖项。

对于特定平台的部署,请考虑使用针对目标环境优化的特定平台NuGet包。 该库提供标准版和BarCode.Slim 版,以适应不同的部署场景。 有关完整的安装步骤,请参阅IronBarcode安装指南

配置您的项目

安装完成后,将必要的 using 语句添加到您的 C# 文件中:

using IronBarCode;
using IronBarCode;
Imports IronBarCode
$vbLabelText   $csharpLabel

导入此软件后,您将可以使用 IronBarcode 的完整条形码读取生成功能。 该库支持超过 30 种条形码格式,包括二维码、Code 128、Code 39、Data Matrix 和 PDF417。查看支持的条形码格式完整列表,以确认其与您的使用场景兼容。

如需排查安装问题,请参阅NuGet程序包故障排除指南或提交工程支持请求以获得专门支持。

选择合适的架构模式

在ASP.NET中实现条形码扫描时,主要有两种架构方法。 了解这些规律有助于您针对每种使用场景选择合适的条形码阅读器设置

// Server-side processing -- recommended for most ASP.NET scenarios
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true,
    UseConfidenceThreshold = true,
    ConfidenceThreshold = 0.85
};

var results = BarcodeReader.Read(stream, options);

foreach (var barcode in results)
{
    Console.WriteLine($"Type: {barcode.BarcodeType}, Value: {barcode.Text}");
}
// Server-side processing -- recommended for most ASP.NET scenarios
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true,
    UseConfidenceThreshold = true,
    ConfidenceThreshold = 0.85
};

var results = BarcodeReader.Read(stream, options);

foreach (var barcode in results)
{
    Console.WriteLine($"Type: {barcode.BarcodeType}, Value: {barcode.Text}");
}
Imports System

' Server-side processing -- recommended for most ASP.NET scenarios
Dim options As New BarcodeReaderOptions With {
    .Speed = ReadingSpeed.Balanced,
    .ExpectMultipleBarcodes = True,
    .UseConfidenceThreshold = True,
    .ConfidenceThreshold = 0.85
}

Dim results = BarcodeReader.Read(stream, options)

For Each barcode In results
    Console.WriteLine($"Type: {barcode.BarcodeType}, Value: {barcode.Text}")
Next
$vbLabelText   $csharpLabel

服务器端方法可让您最大限度地控制图像处理,并且在所有浏览器上都能稳定运行。 当服务器处理每个图像时,您还可以获得清晰的审计跟踪:每个扫描的条形码都会经过您的应用程序层,您可以在其中记录它、根据数据库验证它或触发下游工作流程。 这种模式尤其适用于医疗保健、物流和制造业等受监管行业,因为在这些行业中,每一次扫描都必须记录在案。

对于客户端摄像头采集集成,现代浏览器支持用于访问摄像头的 MediaDevices API,该 API 可以与 IronBarcode 的服务器端处理功能(通过 REST API 实现)相结合——本指南稍后将详细介绍。选择服务器端处理还可以简化您的安全模型:无需向浏览器暴露任何敏感的处理逻辑,所有验证都在您的应用程序边界内进行。

客户端与服务器端条形码扫描的优缺点
方面 客户端捕获 + 服务器处理 纯服务器端处理
最适合 使用摄像头进行实时扫描 批量处理、文件上传
浏览器支持 仅限现代浏览器 所有浏览器
用户体验 即时反馈 标准上传流程
安全模型 更复杂(CORS、身份验证) 直截了当
带宽使用情况 较低(设备上预处理) 更高(原始图像上传)

如何实现文件上传条形码扫描?

文件上传扫描是ASP.NET Web 应用程序中最常见的条形码应用场景。 这种模式适用于处理发票、货运标签或任何带有嵌入式条形码的文档。 为了提高吞吐量,可以考虑采用异步条形码读取来同时处理多个上传任务。

构建上传表单

在ASP.NET视图中创建响应式 HTML 表单:

@* Razor view -- barcode upload form *@
<form method="post" enctype="multipart/form-data" id="barcodeForm">
    <div class="form-group">
        <label for="barcodeFile">Select Barcode Image:</label>
        <input type="file" name="barcodeFile" id="barcodeFile"
               accept="image/*,.pdf" class="form-control"
               capture="environment" />
    </div>
    <button type="submit" class="btn btn-primary" id="scanBtn">
        <span class="spinner-border spinner-border-sm d-none" role="status"></span>
        Scan Barcode
    </button>
</form>
<div id="results">
    @ViewBag.BarcodeResult
</div>
@* Razor view -- barcode upload form *@
<form method="post" enctype="multipart/form-data" id="barcodeForm">
    <div class="form-group">
        <label for="barcodeFile">Select Barcode Image:</label>
        <input type="file" name="barcodeFile" id="barcodeFile"
               accept="image/*,.pdf" class="form-control"
               capture="environment" />
    </div>
    <button type="submit" class="btn btn-primary" id="scanBtn">
        <span class="spinner-border spinner-border-sm d-none" role="status"></span>
        Scan Barcode
    </button>
</form>
<div id="results">
    @ViewBag.BarcodeResult
</div>
@* Razor view -- barcode upload form *@
<form method="post" enctype="multipart/form-data" id="barcodeForm">
    <div class="form-group">
        <label for="barcodeFile">Select Barcode Image:</label>
        <input type="file" name="barcodeFile" id="barcodeFile"
               accept="image/*,.pdf" class="form-control"
               capture="environment" />
    </div>
    <button type="submit" class="btn btn-primary" id="scanBtn">
        <span class="spinner-border spinner-border-sm d-none" role="status"></span>
        Scan Barcode
    </button>
</form>
<div id="results">
    @ViewBag.BarcodeResult
</div>
$vbLabelText   $csharpLabel

capture="environment" 属性激活移动设备上的后置摄像头,为用户提供类似原生相机的体验,而无需 JavaScript。

实施安全后端处理

控制器操作负责文件验证、内存流处理和结果格式化:

[HttpPost]
[ValidateAntiForgeryToken]
[RequestSizeLimit(10_000_000)] // 10MB limit
public async Task<IActionResult> ScanBarcode(IFormFile barcodeFile)
{
    var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif",
                                    ".tiff", ".bmp", ".pdf" };
    var extension = Path.GetExtension(barcodeFile.FileName).ToLowerInvariant();

    if (!allowedExtensions.Contains(extension))
    {
        ModelState.AddModelError("", "Invalid file type");
        return View();
    }

    if (barcodeFile != null && barcodeFile.Length > 0)
    {
        using var stream = new MemoryStream();
        await barcodeFile.CopyToAsync(stream);
        stream.Position = 0;

        var options = new BarcodeReaderOptions
        {
            Speed = ReadingSpeed.Balanced,
            ExpectMultipleBarcodes = true,
            ExpectBarcodeTypes = BarcodeEncoding.AllOneDimensional |
                                BarcodeEncoding.QRCode |
                                BarcodeEncoding.DataMatrix,
            ImageFilters = new ImageFilterCollection
            {
                new SharpenFilter(),
                new ContrastFilter()
            }
        };

        var results = BarcodeReader.Read(stream, options);

        ViewBag.BarcodeResult = results.Any()
            ? string.Join("<br/>", results.Select(r => $"<strong>{r.BarcodeType}:</strong> {r.Text}"))
            : "No barcodes found in the image.";
    }

    return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
[RequestSizeLimit(10_000_000)] // 10MB limit
public async Task<IActionResult> ScanBarcode(IFormFile barcodeFile)
{
    var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif",
                                    ".tiff", ".bmp", ".pdf" };
    var extension = Path.GetExtension(barcodeFile.FileName).ToLowerInvariant();

    if (!allowedExtensions.Contains(extension))
    {
        ModelState.AddModelError("", "Invalid file type");
        return View();
    }

    if (barcodeFile != null && barcodeFile.Length > 0)
    {
        using var stream = new MemoryStream();
        await barcodeFile.CopyToAsync(stream);
        stream.Position = 0;

        var options = new BarcodeReaderOptions
        {
            Speed = ReadingSpeed.Balanced,
            ExpectMultipleBarcodes = true,
            ExpectBarcodeTypes = BarcodeEncoding.AllOneDimensional |
                                BarcodeEncoding.QRCode |
                                BarcodeEncoding.DataMatrix,
            ImageFilters = new ImageFilterCollection
            {
                new SharpenFilter(),
                new ContrastFilter()
            }
        };

        var results = BarcodeReader.Read(stream, options);

        ViewBag.BarcodeResult = results.Any()
            ? string.Join("<br/>", results.Select(r => $"<strong>{r.BarcodeType}:</strong> {r.Text}"))
            : "No barcodes found in the image.";
    }

    return View();
}
Imports Microsoft.AspNetCore.Mvc
Imports Microsoft.AspNetCore.Http
Imports System.IO
Imports System.Threading.Tasks
Imports ZXing

<HttpPost>
<ValidateAntiForgeryToken>
<RequestSizeLimit(10_000_000)> ' 10MB limit
Public Async Function ScanBarcode(barcodeFile As IFormFile) As Task(Of IActionResult)
    Dim allowedExtensions As String() = {".jpg", ".jpeg", ".png", ".gif", ".tiff", ".bmp", ".pdf"}
    Dim extension As String = Path.GetExtension(barcodeFile.FileName).ToLowerInvariant()

    If Not allowedExtensions.Contains(extension) Then
        ModelState.AddModelError("", "Invalid file type")
        Return View()
    End If

    If barcodeFile IsNot Nothing AndAlso barcodeFile.Length > 0 Then
        Using stream As New MemoryStream()
            Await barcodeFile.CopyToAsync(stream)
            stream.Position = 0

            Dim options As New BarcodeReaderOptions With {
                .Speed = ReadingSpeed.Balanced,
                .ExpectMultipleBarcodes = True,
                .ExpectBarcodeTypes = BarcodeEncoding.AllOneDimensional Or
                                      BarcodeEncoding.QRCode Or
                                      BarcodeEncoding.DataMatrix,
                .ImageFilters = New ImageFilterCollection From {
                    New SharpenFilter(),
                    New ContrastFilter()
                }
            }

            Dim results = BarcodeReader.Read(stream, options)

            ViewBag.BarcodeResult = If(results.Any(),
                String.Join("<br/>", results.Select(Function(r) $"<strong>{r.BarcodeType}:</strong> {r.Text}")),
                "No barcodes found in the image.")
        End Using
    End If

    Return View()
End Function
$vbLabelText   $csharpLabel

该实现会在处理之前验证文件类型,从内存流中读取条形码,并返回所有检测到的结果。 IronBarcode可处理各种图像格式,包括多页 TIFF、GIFPDF 文档,无需编写特定于格式的处理代码。

扫描的输入和输出是什么样子的

Code 128 条形码编码 URL 'https://ironsoftware.com/csharp/barcode/'; 显示机器可读的条形码,下方带有人类可读的文本,以便在 ASP.NET 条形码阅读器应用程序中进行准确扫描。

上面的示例显示了一个标准的 Code 128 条形码——这是运输和库存应用中常见的格式。 扫描完成后,结果屏幕会确认解码值以及置信度元数据:

! ASP.NET Core Web 应用程序界面显示条形码扫描成功结果,文件上传表单显示解码后的 Code128 条形码值和置信度评分元数据

IronBarcode返回上传图像中检测到的每个条形码的类型、解码值、置信度分数和位置数据。

如何构建用于条形码扫描的 REST API?

现代ASP.NET应用程序通常通过 REST API 公开条形码扫描功能,从而可以与移动应用程序、单页应用程序或第三方服务集成。 这种模式支持客户端摄像头捕获和服务器端处理。

条形码API的安全注意事项

在编写控制器之前,先规划安全层。 条形码数据可能包含任意内容,因此务必验证输入。 请遵循IronBarcode安全指南以获得全面保护:

-输入验证:在存储或处理条形码内容之前对其进行清理。 -速率限制:使用ASP.NET Core 内置的速率限制中间件来防止 API 滥用 -身份验证:使用 JWT 令牌或 API 密钥保护端点 -强制执行 HTTPS :所有条形码 API 流量必须通过 TLS 传输。

构建生产 API 控制器

[ApiController]
[Route("api/[controller]")]
public class BarcodeController : ControllerBase
{
    private readonly ILogger<BarcodeController> _logger;
    private readonly IMemoryCache _cache;

    public BarcodeController(ILogger<BarcodeController> logger, IMemoryCache cache)
    {
        _logger = logger;
        _cache = cache;
    }

    [HttpPost("scan")]
    [ProducesResponseType(typeof(BarcodeResponse), 200)]
    [ProducesResponseType(typeof(ErrorResponse), 400)]
    public async Task<IActionResult> ScanBarcode([FromBody] BarcodeRequest request)
    {
        try
        {
            if (string.IsNullOrEmpty(request.ImageBase64))
                return BadRequest(new ErrorResponse { Error = "Image data is required" });

            var cacheKey = $"barcode_{request.ImageBase64.GetHashCode()}";
            if (_cache.TryGetValue(cacheKey, out BarcodeResponse cachedResult))
                return Ok(cachedResult);

            byte[] imageBytes = Convert.FromBase64String(request.ImageBase64);

            if (imageBytes.Length > 10 * 1024 * 1024)
                return BadRequest(new ErrorResponse { Error = "Image size exceeds 10MB limit" });

            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Faster,
                ExpectMultipleBarcodes = request.ExpectMultiple ?? false,
                UseConfidenceThreshold = true,
                ConfidenceThreshold = 0.8
            };

            var results = await Task.Run(() => BarcodeReader.Read(imageBytes, options));

            var response = new BarcodeResponse
            {
                Success = true,
                Barcodes = results.Select(r => new BarcodeData
                {
                    Type = r.BarcodeType.ToString(),
                    Value = r.Text,
                    Confidence = r.Confidence,
                    Position = new BarcodePosition
                    {
                        X = r.Points.Select(p => p.X).Min(),
                        Y = r.Points.Select(p => p.Y).Min(),
                        Width = r.Width,
                        Height = r.Height
                    }
                }).ToList()
            };

            _cache.Set(cacheKey, response, TimeSpan.FromMinutes(5));
            return Ok(response);
        }
        catch (FormatException)
        {
            return BadRequest(new ErrorResponse { Error = "Invalid base64 image data" });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing barcode scan");
            return StatusCode(500, new ErrorResponse { Error = "Internal server error" });
        }
    }
}

public record BarcodeRequest(string ImageBase64, bool? ExpectMultiple);

public record BarcodeResponse
{
    public bool Success { get; init; }
    public List<BarcodeData> Barcodes { get; init; } = new();
}

public record BarcodeData
{
    public string Type { get; init; }
    public string Value { get; init; }
    public double Confidence { get; init; }
    public BarcodePosition Position { get; init; }
}

public record BarcodePosition(int X, int Y, int Width, int Height);

public record ErrorResponse
{
    public bool Success => false;
    public string Error { get; init; }
}
[ApiController]
[Route("api/[controller]")]
public class BarcodeController : ControllerBase
{
    private readonly ILogger<BarcodeController> _logger;
    private readonly IMemoryCache _cache;

    public BarcodeController(ILogger<BarcodeController> logger, IMemoryCache cache)
    {
        _logger = logger;
        _cache = cache;
    }

    [HttpPost("scan")]
    [ProducesResponseType(typeof(BarcodeResponse), 200)]
    [ProducesResponseType(typeof(ErrorResponse), 400)]
    public async Task<IActionResult> ScanBarcode([FromBody] BarcodeRequest request)
    {
        try
        {
            if (string.IsNullOrEmpty(request.ImageBase64))
                return BadRequest(new ErrorResponse { Error = "Image data is required" });

            var cacheKey = $"barcode_{request.ImageBase64.GetHashCode()}";
            if (_cache.TryGetValue(cacheKey, out BarcodeResponse cachedResult))
                return Ok(cachedResult);

            byte[] imageBytes = Convert.FromBase64String(request.ImageBase64);

            if (imageBytes.Length > 10 * 1024 * 1024)
                return BadRequest(new ErrorResponse { Error = "Image size exceeds 10MB limit" });

            var options = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.Faster,
                ExpectMultipleBarcodes = request.ExpectMultiple ?? false,
                UseConfidenceThreshold = true,
                ConfidenceThreshold = 0.8
            };

            var results = await Task.Run(() => BarcodeReader.Read(imageBytes, options));

            var response = new BarcodeResponse
            {
                Success = true,
                Barcodes = results.Select(r => new BarcodeData
                {
                    Type = r.BarcodeType.ToString(),
                    Value = r.Text,
                    Confidence = r.Confidence,
                    Position = new BarcodePosition
                    {
                        X = r.Points.Select(p => p.X).Min(),
                        Y = r.Points.Select(p => p.Y).Min(),
                        Width = r.Width,
                        Height = r.Height
                    }
                }).ToList()
            };

            _cache.Set(cacheKey, response, TimeSpan.FromMinutes(5));
            return Ok(response);
        }
        catch (FormatException)
        {
            return BadRequest(new ErrorResponse { Error = "Invalid base64 image data" });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing barcode scan");
            return StatusCode(500, new ErrorResponse { Error = "Internal server error" });
        }
    }
}

public record BarcodeRequest(string ImageBase64, bool? ExpectMultiple);

public record BarcodeResponse
{
    public bool Success { get; init; }
    public List<BarcodeData> Barcodes { get; init; } = new();
}

public record BarcodeData
{
    public string Type { get; init; }
    public string Value { get; init; }
    public double Confidence { get; init; }
    public BarcodePosition Position { get; init; }
}

public record BarcodePosition(int X, int Y, int Width, int Height);

public record ErrorResponse
{
    public bool Success => false;
    public string Error { get; init; }
}
Imports System
Imports Microsoft.AspNetCore.Mvc
Imports Microsoft.Extensions.Logging
Imports Microsoft.Extensions.Caching.Memory
Imports System.Threading.Tasks

<ApiController>
<Route("api/[controller]")>
Public Class BarcodeController
    Inherits ControllerBase

    Private ReadOnly _logger As ILogger(Of BarcodeController)
    Private ReadOnly _cache As IMemoryCache

    Public Sub New(logger As ILogger(Of BarcodeController), cache As IMemoryCache)
        _logger = logger
        _cache = cache
    End Sub

    <HttpPost("scan")>
    <ProducesResponseType(GetType(BarcodeResponse), 200)>
    <ProducesResponseType(GetType(ErrorResponse), 400)>
    Public Async Function ScanBarcode(<FromBody> request As BarcodeRequest) As Task(Of IActionResult)
        Try
            If String.IsNullOrEmpty(request.ImageBase64) Then
                Return BadRequest(New ErrorResponse With {.Error = "Image data is required"})
            End If

            Dim cacheKey = $"barcode_{request.ImageBase64.GetHashCode()}"
            Dim cachedResult As BarcodeResponse = Nothing
            If _cache.TryGetValue(cacheKey, cachedResult) Then
                Return Ok(cachedResult)
            End If

            Dim imageBytes As Byte() = Convert.FromBase64String(request.ImageBase64)

            If imageBytes.Length > 10 * 1024 * 1024 Then
                Return BadRequest(New ErrorResponse With {.Error = "Image size exceeds 10MB limit"})
            End If

            Dim options = New BarcodeReaderOptions With {
                .Speed = ReadingSpeed.Faster,
                .ExpectMultipleBarcodes = request.ExpectMultiple.GetValueOrDefault(False),
                .UseConfidenceThreshold = True,
                .ConfidenceThreshold = 0.8
            }

            Dim results = Await Task.Run(Function() BarcodeReader.Read(imageBytes, options))

            Dim response = New BarcodeResponse With {
                .Success = True,
                .Barcodes = results.Select(Function(r) New BarcodeData With {
                    .Type = r.BarcodeType.ToString(),
                    .Value = r.Text,
                    .Confidence = r.Confidence,
                    .Position = New BarcodePosition With {
                        .X = r.Points.Select(Function(p) p.X).Min(),
                        .Y = r.Points.Select(Function(p) p.Y).Min(),
                        .Width = r.Width,
                        .Height = r.Height
                    }
                }).ToList()
            }

            _cache.Set(cacheKey, response, TimeSpan.FromMinutes(5))
            Return Ok(response)
        Catch ex As FormatException
            Return BadRequest(New ErrorResponse With {.Error = "Invalid base64 image data"})
        Catch ex As Exception
            _logger.LogError(ex, "Error processing barcode scan")
            Return StatusCode(500, New ErrorResponse With {.Error = "Internal server error"})
        End Try
    End Function
End Class

Public Class BarcodeRequest
    Public Property ImageBase64 As String
    Public Property ExpectMultiple As Boolean?
End Class

Public Class BarcodeResponse
    Public Property Success As Boolean
    Public Property Barcodes As List(Of BarcodeData) = New List(Of BarcodeData)()
End Class

Public Class BarcodeData
    Public Property Type As String
    Public Property Value As String
    Public Property Confidence As Double
    Public Property Position As BarcodePosition
End Class

Public Class BarcodePosition
    Public Property X As Integer
    Public Property Y As Integer
    Public Property Width As Integer
    Public Property Height As Integer
End Class

Public Class ErrorResponse
    Public ReadOnly Property Success As Boolean
        Get
            Return False
        End Get
    End Property
    Public Property Error As String
End Class
$vbLabelText   $csharpLabel

此接口接受 base64 编码的图像——这是通过 HTTP 传输图像的标准格式。响应包含条形码类型、解码值、置信度评分和位置。 对于大批量处理场景,请查看批量条码处理读取速度优化选项。

API 如何处理多个条形码?

三种不同的条形码格式,分别标记为 ABC,展示了 IronBarcode 在生产环境中同时处理的 QR 码、Code128 码和 DataMatrix 码

IronBarcode一次调用即可处理单个图像中的多个条形码,并返回一个结果数组。 响应中的每个条目都包含位置数据,以便客户端应用程序可以在屏幕上突出显示检测到的条形码。

浏览器开发者工具的网络选项卡显示成功的 JSON API 响应,其中包含一个数组,该数组包含三个检测到的条形码以及完整的元数据,包括类型、值、置信度和位置坐标。

结构化的 JSON 响应为客户端应用程序提供了处理和显示条形码结果所需的一切,无需额外的查找。

如何处理具有挑战性的条形码图像?

现实世界中的条形码扫描经常会遇到不完美的图像——例如拍摄角度不当、光线不足或条形码部分损坏等情况。 IronBarcode通过其先进的图像处理能力机器学习置信度阈值来解决这些问题。

诊断常见扫描问题

在进行修正之前,请先确定您的问题属于哪一类。 生产中的大多数扫描失败可归为以下五类之一:图像质量问题(模糊、噪点、分辨率低)、几何问题(旋转、倾斜、透视变形)、损坏问题(标签撕裂、墨迹污损)、环境问题(眩光、阴影、照明不一致)以及误报检测(读取器找到不存在的条形码)。

了解类别有助于选择合适的滤镜组合和读取速度,而无需对每张图像进行不必要的处理。 对于大多数 Web 应用程序场景,以 ReadingSpeed.BalancedAutoRotate = true 开头的版本涵盖了大多数情况。 只有当第一次尝试没有返回任何结果时,才升级到 ExtremeDetail

下面的代码中的多遍方法实现了这种分层策略。 快速的第一遍扫描能够快速处理典型图像,在常见情况下保持较低的平均延迟。 只有当第一次审核失败时才会触发第二次审核,从而确保您只在真正需要时才支付额外的处理费用。 这种模式可以保证ASP.NET端点在正常负载下保持响应,同时还能可靠地处理棘手的极端情况。

条形码扫描常见问题及解决方案
问题 症状 解决方案
模糊图像 置信度低,读取错误。 应用SharpenFilter ,提高ExtremeDetail速度
旋转条形码 完全未检测到条形码 启用AutoRotate = true
条形码损坏 部分读取,错误值 启用错误纠正,使用RemoveFalsePositive
对比度差 检测结果不一致 应用ContrastFilterBrightnessFilter
性能太慢 上传延迟高 使用ReadingSpeed.Faster ,启用多线程

实现多遍图像处理

对于复杂图像,分层处理方法可以在不牺牲简单图像处理性能的前提下,获得最佳处理效果:

public class AdvancedBarcodeProcessor
{
    private readonly ILogger<AdvancedBarcodeProcessor> _logger;

    public async Task<List<ScannedBarcode>> ProcessChallengingImage(Stream imageStream)
    {
        // First pass -- fast, minimal processing
        var fastOptions = new BarcodeReaderOptions
        {
            Speed = ReadingSpeed.Balanced,
            ExpectMultipleBarcodes = true,
            AutoRotate = false,
            UseConfidenceThreshold = true,
            ConfidenceThreshold = 0.85
        };

        var results = BarcodeReader.Read(imageStream, fastOptions);

        if (!results.Any())
        {
            // Second pass -- aggressive image correction
            imageStream.Position = 0;

            var detailedOptions = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.ExtremeDetail,
                ExpectMultipleBarcodes = true,
                AutoRotate = true,
                RemoveFalsePositive = true,
                UseConfidenceThreshold = true,
                ConfidenceThreshold = 0.6,
                Multithreaded = true,
                ExpectBarcodeTypes = BarcodeEncoding.All,
                ImageFilters = new ImageFilterCollection
                {
                    new SharpenFilter(2.5f),
                    new ContrastFilter(2.0f),
                    new BrightnessFilter(1.2f),
                    new InvertFilter()
                }
            };

            results = BarcodeReader.Read(imageStream, detailedOptions);
            _logger.LogInformation("Second pass detected {Count} barcodes", results.Count());
        }

        return results.Select(r => new ScannedBarcode
        {
            Value = r.Text,
            BarcodeType = r.BarcodeType.ToString(),
            Confidence = r.Confidence,
            RotationAngle = r.RotationAngle,
            PageNumber = r.PageNumber
        }).ToList();
    }
}

public record ScannedBarcode
{
    public string Value { get; init; }
    public string BarcodeType { get; init; }
    public double Confidence { get; init; }
    public float RotationAngle { get; init; }
    public int PageNumber { get; init; }
}
public class AdvancedBarcodeProcessor
{
    private readonly ILogger<AdvancedBarcodeProcessor> _logger;

    public async Task<List<ScannedBarcode>> ProcessChallengingImage(Stream imageStream)
    {
        // First pass -- fast, minimal processing
        var fastOptions = new BarcodeReaderOptions
        {
            Speed = ReadingSpeed.Balanced,
            ExpectMultipleBarcodes = true,
            AutoRotate = false,
            UseConfidenceThreshold = true,
            ConfidenceThreshold = 0.85
        };

        var results = BarcodeReader.Read(imageStream, fastOptions);

        if (!results.Any())
        {
            // Second pass -- aggressive image correction
            imageStream.Position = 0;

            var detailedOptions = new BarcodeReaderOptions
            {
                Speed = ReadingSpeed.ExtremeDetail,
                ExpectMultipleBarcodes = true,
                AutoRotate = true,
                RemoveFalsePositive = true,
                UseConfidenceThreshold = true,
                ConfidenceThreshold = 0.6,
                Multithreaded = true,
                ExpectBarcodeTypes = BarcodeEncoding.All,
                ImageFilters = new ImageFilterCollection
                {
                    new SharpenFilter(2.5f),
                    new ContrastFilter(2.0f),
                    new BrightnessFilter(1.2f),
                    new InvertFilter()
                }
            };

            results = BarcodeReader.Read(imageStream, detailedOptions);
            _logger.LogInformation("Second pass detected {Count} barcodes", results.Count());
        }

        return results.Select(r => new ScannedBarcode
        {
            Value = r.Text,
            BarcodeType = r.BarcodeType.ToString(),
            Confidence = r.Confidence,
            RotationAngle = r.RotationAngle,
            PageNumber = r.PageNumber
        }).ToList();
    }
}

public record ScannedBarcode
{
    public string Value { get; init; }
    public string BarcodeType { get; init; }
    public double Confidence { get; init; }
    public float RotationAngle { get; init; }
    public int PageNumber { get; init; }
}
Imports System.IO
Imports System.Collections.Generic
Imports System.Linq
Imports System.Threading.Tasks

Public Class AdvancedBarcodeProcessor
    Private ReadOnly _logger As ILogger(Of AdvancedBarcodeProcessor)

    Public Async Function ProcessChallengingImage(imageStream As Stream) As Task(Of List(Of ScannedBarcode))
        ' First pass -- fast, minimal processing
        Dim fastOptions As New BarcodeReaderOptions With {
            .Speed = ReadingSpeed.Balanced,
            .ExpectMultipleBarcodes = True,
            .AutoRotate = False,
            .UseConfidenceThreshold = True,
            .ConfidenceThreshold = 0.85
        }

        Dim results = BarcodeReader.Read(imageStream, fastOptions)

        If Not results.Any() Then
            ' Second pass -- aggressive image correction
            imageStream.Position = 0

            Dim detailedOptions As New BarcodeReaderOptions With {
                .Speed = ReadingSpeed.ExtremeDetail,
                .ExpectMultipleBarcodes = True,
                .AutoRotate = True,
                .RemoveFalsePositive = True,
                .UseConfidenceThreshold = True,
                .ConfidenceThreshold = 0.6,
                .Multithreaded = True,
                .ExpectBarcodeTypes = BarcodeEncoding.All,
                .ImageFilters = New ImageFilterCollection From {
                    New SharpenFilter(2.5F),
                    New ContrastFilter(2.0F),
                    New BrightnessFilter(1.2F),
                    New InvertFilter()
                }
            }

            results = BarcodeReader.Read(imageStream, detailedOptions)
            _logger.LogInformation("Second pass detected {Count} barcodes", results.Count())
        End If

        Return results.Select(Function(r) New ScannedBarcode With {
            .Value = r.Text,
            .BarcodeType = r.BarcodeType.ToString(),
            .Confidence = r.Confidence,
            .RotationAngle = r.RotationAngle,
            .PageNumber = r.PageNumber
        }).ToList()
    End Function
End Class

Public Class ScannedBarcode
    Public Property Value As String
    Public Property BarcodeType As String
    Public Property Confidence As Double
    Public Property RotationAngle As Single
    Public Property PageNumber As Integer
End Class
$vbLabelText   $csharpLabel

BarcodeReaderOptions类可以对扫描的各个方面进行精细控制。 设置 AutoRotate 可处理以任何角度拍摄的图像,而图像滤镜可提高模糊或低对比度条形码的清晰度。 有关详细配置,请参阅条形码阅读器设置示例PDF 特定阅读器设置

处理 PDF 文件时,可以考虑在 PDF 文件上添加条形码,或者将条形码创建为 PDF 文档。 对于大批量处理,通过异步和多线程功能启用多线程可以显著提高吞吐量。

添加浏览器兼容性和回退策略

支持多种浏览器需要逐步增强。 Android 和桌面版 Chrome、Edge 和 Firefox 等现代浏览器支持 MediaDevices.getUserMedia() API 以访问摄像头。 iOS 版 Safari 从 11 版本开始支持此功能。 较旧的Enterprise浏览器、IE11 兼容模式以及某些受限的企业环境可能完全不支持摄像头访问,因此您的备用文件上传路径必须始终保持可用状态。

建议采用运行时特征检测而不是用户代理嗅探,然后相应地显示或隐藏摄像头界面。 首先提供具备摄像头功能的界面,然后优雅地回退到文件上传模式:

@* Razor view with progressive enhancement *@
<div class="barcode-scanner-container">
    @* Camera capture -- hidden until JavaScript confirms support *@
    <div id="cameraSection" class="d-none">
        <video id="videoPreview" class="w-100" autoplay></video>
        <button id="captureBtn" class="btn btn-primary mt-2">Capture and Scan</button>
    </div>

    @* File upload -- always available as fallback *@
    <div id="uploadSection">
        <form method="post" enctype="multipart/form-data"
              asp-action="ScanBarcode" asp-controller="Barcode">
            <div class="form-group">
                <label>Upload Barcode Image:</label>
                <input type="file" name="file" accept="image/*,.pdf"
                       class="form-control" required />
            </div>
            <button type="submit" class="btn btn-primary">Upload and Scan</button>
        </form>
    </div>
</div>
@* Razor view with progressive enhancement *@
<div class="barcode-scanner-container">
    @* Camera capture -- hidden until JavaScript confirms support *@
    <div id="cameraSection" class="d-none">
        <video id="videoPreview" class="w-100" autoplay></video>
        <button id="captureBtn" class="btn btn-primary mt-2">Capture and Scan</button>
    </div>

    @* File upload -- always available as fallback *@
    <div id="uploadSection">
        <form method="post" enctype="multipart/form-data"
              asp-action="ScanBarcode" asp-controller="Barcode">
            <div class="form-group">
                <label>Upload Barcode Image:</label>
                <input type="file" name="file" accept="image/*,.pdf"
                       class="form-control" required />
            </div>
            <button type="submit" class="btn btn-primary">Upload and Scan</button>
        </form>
    </div>
</div>
@* Razor view with progressive enhancement *@
<div class="barcode-scanner-container">
    @* Camera capture -- hidden until JavaScript confirms support *@
    <div id="cameraSection" class="d-none">
        <video id="videoPreview" class="w-100" autoplay></video>
        <button id="captureBtn" class="btn btn-primary mt-2">Capture and Scan</button>
    </div>

    @* File upload -- always available as fallback *@
    <div id="uploadSection">
        <form method="post" enctype="multipart/form-data"
              asp-action="ScanBarcode" asp-controller="Barcode">
            <div class="form-group">
                <label>Upload Barcode Image:</label>
                <input type="file" name="file" accept="image/*,.pdf"
                       class="form-control" required />
            </div>
            <button type="submit" class="btn btn-primary">Upload and Scan</button>
        </form>
    </div>
</div>
$vbLabelText   $csharpLabel

如果您偏爱基于组件的方法, Blazor集成可提供现代 Web 应用程序支持,且配置极少。 如需排查部署问题,请参阅运行时复制异常指南

下一步计划是什么?

在ASP.NET中使用IronBarcode进行条形码扫描非常简单。 您只需安装一个 NuGet 包,调用 BarcodeReader.Read(),即可获得 30 多种格式的可靠解码结果,包括其他库难以处理的具有挑战性的真实世界图像。

为了在此基础上继续发展,请探索以下资源:

条形码读取教程——涵盖所有扫描场景的详细指南 条形码生成——以编程方式创建条形码和二维码 -二维码生成器-- 二维码特有的功能和样式 图像校正——提高复杂图像扫描精度的技术 -异步和多线程——扩展条形码处理能力,以应对高流量应用 -跨平台兼容性——可部署在 Windows、Linux、Docker、Azure 和 AWS 上 -支持的条形码格式-- 可读和可写条形码格式的完整列表 -容错特性——在恶劣条件下可靠运行 API 参考-- 所有类和选项的完整文档 -许可选项——SaaS、OEM 和Enterprise许可,适用于生产部署

首先获取免费试用许可证,即可在您的ASP.NET应用程序中无限制地测试IronBarcode 。 试用版包含对所有功能的完整访问权限,包括多格式检测、图像校正以及本指南中所示的 REST API 模式——因此您可以在购买生产许可证之前,在自己的图像上评估性能。 对于需要设备端扫描的.NET MAUI移动应用,请参阅.NET MAUI条形码扫描器教程,该教程将相同的 API 扩展到 iOS 和 Android 目标。

常见问题解答

条形码扫描在 ASP.NET 应用程序中的主要用途是什么?

条形码扫描在 ASP.NET 应用程序中的主要用途是提升库存管理系统、处理活动门票和数字化纸质文件,从而提高效率并减少错误。

IronBarcode 如何在 ASP.NET 中实现条形码扫描?

IronBarcode 通过提供可靠且高效的组件简化了 ASP.NET 中的条形码扫描过程,这些组件可以轻松集成到 Web 应用程序中,使开发人员能够快速实现扫描功能。

IronBarcode 可以扫描哪些类型的条形码?

IronBarcode 支持扫描各种条形码格式,包括传统的线性条形码和现代的二维条形码,确保与多种应用兼容。

IronBarcode 可以处理文件处理中的条形码扫描吗?

是的,IronBarcode 非常适合文件处理工作流程,其中可以通过扫描嵌入的条形码来数字化和组织纸质文件。

IronBarcode 适合用于库存管理系统吗?

IronBarcode 是库存管理系统的理想选择,因为它可以通过扫描条形码实现高效的产品跟踪,从而简化操作并减少错误。

集成 IronBarcode 如何改善活动门票处理?

通过集成 IronBarcode,活动门票处理变得无缝,因为它允许快速扫描门票条形码,从而在活动中实现快速准确的入场管理。

在 ASP.NET 项目中使用 IronBarcode 有哪些优势?

在 ASP.NET 项目中使用 IronBarcode 提供了多种优势,包括易于集成、支持多种条形码格式以及增强的应用程序性能,从而为条形码扫描需求提供了一个强大的解决方案。

IronBarcode 需要广泛的编码知识才能实现吗?

不,IronBarcode 被设计为对开发人员友好,使得在 ASP.NET 应用程序中实现条形码扫描功能变得简单,即使具有最少的编码知识。

IronBarcode 可以用于移动 Web 应用程序吗?

是的,IronBarcode 可以集成到移动 Web 应用程序中,允许随时随地进行条形码扫描,增强 ASP.NET 项目的多功能性。

Jordi Bardia
软件工程师
Jordi 最擅长 Python、C# 和 C++,当他不在 Iron Software 利用这些技能时,他就在游戏编程。分享产品测试、产品开发和研究的责任,Jordi 在持续的产品改进中增加了巨大的价值。多样的经验使他面临挑战并保持投入,他表示这是在 Iron Software 工作的最喜欢的方面之一。Jordi 在佛罗里达州迈阿密长大,并在佛罗里达大学学习计算机科学和统计学。

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我