跳至页脚内容
视频

How to Generate Barcode Images in C# 适用于 .NET using IronBarcode

从Dynamsoft条形码阅读器迁移到IronBarcode

大多数从Dynamsoft条形码阅读器迁移到IronBarcode的开发者属于以下两类之一:选择Dynamsoft因为其声誉,然后发现以相机为中心的API与其文档处理使用场景不匹配的人,以及那些运行在气隙或Docker环境中而许可证服务器依赖性引起生产事故的人。

如果您属于第一组,则迁移将移除外部 PDF 渲染库、逐页渲染循环和错误代码许可模式。 如果您属于第二组,迁移将从您的Docker或VPC配置中移除InitLicense网络调用、离线许可证内容捆绑包和刷新周期以及出站网络策略。 无论哪种方式,迁移后代码库都会变短。

本指南坦诚地说明了您的损失:如果您的应用处理实时摄像头帧,Dynamsoft的捕获视觉管道是为这种工作负载量身定制的,IronBarcode不是合适的替代品。 本迁移指南适用于服务器端文件处理、文档工作流以及许可证服务器访问存在问题的环境。

步骤 1:交换NuGet包

dotnet remove package Dynamsoft.DotNet.BarcodeReader.Bundle
dotnet add package BarCode
dotnet remove package Dynamsoft.DotNet.BarcodeReader.Bundle
dotnet add package BarCode
SHELL

如果您的项目中还添加了专门用于 Dynamsoft 的 PDF 渲染库(最常见的是 PdfiumViewer),也可以将其删除:

# Remove if added only for Dynamsoft PDF support
dotnet remove package PdfiumViewer
dotnet remove package PdfiumViewer.Native.x86_64.v8-xfa
# Remove if added only for Dynamsoft PDF support
dotnet remove package PdfiumViewer
dotnet remove package PdfiumViewer.Native.x86_64.v8-xfa
SHELL

步骤 2:替换许可证初始化

这是最直接的简化之处。 Dynamsoft模式要求每次启动时都进行错误代码检查和异常处理:

之前 — Dynamsoft:

using Dynamsoft.License;
using Dynamsoft.Core;

// Must run before any barcode operations
int errorCode = LicenseManager.InitLicense("YOUR-DYNAMSOFT-KEY", out string errorMsg);
if (errorCode != (int)EnumErrorCode.EC_OK)
    throw new InvalidOperationException($"License validation failed [{errorCode}]: {errorMsg}");
using Dynamsoft.License;
using Dynamsoft.Core;

// Must run before any barcode operations
int errorCode = LicenseManager.InitLicense("YOUR-DYNAMSOFT-KEY", out string errorMsg);
if (errorCode != (int)EnumErrorCode.EC_OK)
    throw new InvalidOperationException($"License validation failed [{errorCode}]: {errorMsg}");
Imports Dynamsoft.License
Imports Dynamsoft.Core

' Must run before any barcode operations
Dim errorCode As Integer = LicenseManager.InitLicense("YOUR-DYNAMSOFT-KEY", errorMsg)
If errorCode <> CType(EnumErrorCode.EC_OK, Integer) Then
    Throw New InvalidOperationException($"License validation failed [{errorCode}]: {errorMsg}")
End If
$vbLabelText   $csharpLabel

之后IronBarcode:

// NuGet: dotnet add package BarCode
using IronBarCode;

// Local validation — no network call, no error code
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// NuGet: dotnet add package BarCode
using IronBarCode;

// Local validation — no network call, no error code
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
Imports IronBarCode

' Local validation — no network call, no error code
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

在ASP.NET Core应用中,将此添加到builder.Build()

IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_KEY")
    ?? "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_KEY")
    ?? "YOUR-LICENSE-KEY";
Imports IronBarCode

IronBarCode.License.LicenseKey = If(Environment.GetEnvironmentVariable("IRONBARCODE_KEY"), "YOUR-LICENSE-KEY")
$vbLabelText   $csharpLabel

在Docker或Kubernetes环境中,在您的部署清单中设置IRONBARCODE_KEY环境变量。不需要出站网络规则。

步骤 3:替换命名空间导入

在所有源文件中查找并替换:

grep -r "using Dynamsoft\." --include="*.cs" .
grep -r "using Dynamsoft\." --include="*.cs" .
SHELL

替换所有出现的项:

// Before
using Dynamsoft.CVR;
using Dynamsoft.DBR;
using Dynamsoft.License;
using Dynamsoft.Core;

// After
using IronBarCode;
// Before
using Dynamsoft.CVR;
using Dynamsoft.DBR;
using Dynamsoft.License;
using Dynamsoft.Core;

// After
using IronBarCode;
Imports IronBarCode
$vbLabelText   $csharpLabel

代码迁移示例

基本文件读取

最基本的操作——从图像文件中读取条形码。

之前 — Dynamsoft:

using Dynamsoft.CVR;
using Dynamsoft.DBR;

public string ReadBarcodeFromFile(CaptureVisionRouter router, string imagePath)
{
    CapturedResult result = router.Capture(imagePath, PresetTemplate.PT_READ_BARCODES);
    BarcodeResultItem[] items = result.GetDecodedBarcodesResult()?.GetItems();
    if (items == null || items.Length == 0)
        return null;

    return items[0].GetText();
}
using Dynamsoft.CVR;
using Dynamsoft.DBR;

public string ReadBarcodeFromFile(CaptureVisionRouter router, string imagePath)
{
    CapturedResult result = router.Capture(imagePath, PresetTemplate.PT_READ_BARCODES);
    BarcodeResultItem[] items = result.GetDecodedBarcodesResult()?.GetItems();
    if (items == null || items.Length == 0)
        return null;

    return items[0].GetText();
}
Imports Dynamsoft.CVR
Imports Dynamsoft.DBR

Public Function ReadBarcodeFromFile(router As CaptureVisionRouter, imagePath As String) As String
    Dim result As CapturedResult = router.Capture(imagePath, PresetTemplate.PT_READ_BARCODES)
    Dim items As BarcodeResultItem() = result.GetDecodedBarcodesResult()?.GetItems()
    If items Is Nothing OrElse items.Length = 0 Then
        Return Nothing
    End If

    Return items(0).GetText()
End Function
$vbLabelText   $csharpLabel

之后IronBarcode:

// NuGet: dotnet add package BarCode
using IronBarCode;

public string ReadBarcodeFromFile(string imagePath)
{
    var results = BarcodeReader.Read(imagePath);
    return results?.FirstOrDefault()?.Value;
}
// NuGet: dotnet add package BarCode
using IronBarCode;

public string ReadBarcodeFromFile(string imagePath)
{
    var results = BarcodeReader.Read(imagePath);
    return results?.FirstOrDefault()?.Value;
}
Imports IronBarCode

Public Function ReadBarcodeFromFile(imagePath As String) As String
    Dim results = BarcodeReader.Read(imagePath)
    Return results?.FirstOrDefault()?.Value
End Function
$vbLabelText   $csharpLabel

路由器实例消失了。 BarcodeReader.Read是静态的。 .Value。 使用LINQ对results的空检查更简洁。

读取多个条形码

之前 — Dynamsoft:

using Dynamsoft.CVR;
using Dynamsoft.DBR;

public List<string> ReadAllBarcodes(CaptureVisionRouter router, string imagePath)
{
    SimplifiedCaptureVisionSettings settings = router.GetSimplifiedSettings(
        PresetTemplate.PT_READ_BARCODES);
    settings.BarcodeSettings.ExpectedBarcodesCount = 0; // 0 = find all
    router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);

    CapturedResult result = router.Capture(imagePath, PresetTemplate.PT_READ_BARCODES);
    BarcodeResultItem[] items = result.GetDecodedBarcodesResult()?.GetItems();
    var values = new List<string>();

    if (items != null)
    {
        foreach (var item in items)
            values.Add(item.GetText());
    }

    return values;
}
using Dynamsoft.CVR;
using Dynamsoft.DBR;

public List<string> ReadAllBarcodes(CaptureVisionRouter router, string imagePath)
{
    SimplifiedCaptureVisionSettings settings = router.GetSimplifiedSettings(
        PresetTemplate.PT_READ_BARCODES);
    settings.BarcodeSettings.ExpectedBarcodesCount = 0; // 0 = find all
    router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);

    CapturedResult result = router.Capture(imagePath, PresetTemplate.PT_READ_BARCODES);
    BarcodeResultItem[] items = result.GetDecodedBarcodesResult()?.GetItems();
    var values = new List<string>();

    if (items != null)
    {
        foreach (var item in items)
            values.Add(item.GetText());
    }

    return values;
}
Imports Dynamsoft.CVR
Imports Dynamsoft.DBR

Public Function ReadAllBarcodes(router As CaptureVisionRouter, imagePath As String) As List(Of String)
    Dim settings As SimplifiedCaptureVisionSettings = router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES)
    settings.BarcodeSettings.ExpectedBarcodesCount = 0 ' 0 = find all
    router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings)

    Dim result As CapturedResult = router.Capture(imagePath, PresetTemplate.PT_READ_BARCODES)
    Dim items As BarcodeResultItem() = result.GetDecodedBarcodesResult()?.GetItems()
    Dim values As New List(Of String)()

    If items IsNot Nothing Then
        For Each item In items
            values.Add(item.GetText())
        Next
    End If

    Return values
End Function
$vbLabelText   $csharpLabel

之后IronBarcode:

using IronBarCode;

public List<string> ReadAllBarcodes(string imagePath)
{
    var options = new BarcodeReaderOptions
    {
        ExpectMultipleBarcodes = true,
        MaxParallelThreads = 4
    };

    return BarcodeReader.Read(imagePath, options)
        .Select(r => r.Value)
        .ToList();
}
using IronBarCode;

public List<string> ReadAllBarcodes(string imagePath)
{
    var options = new BarcodeReaderOptions
    {
        ExpectMultipleBarcodes = true,
        MaxParallelThreads = 4
    };

    return BarcodeReader.Read(imagePath, options)
        .Select(r => r.Value)
        .ToList();
}
Imports IronBarCode

Public Function ReadAllBarcodes(imagePath As String) As List(Of String)
    Dim options As New BarcodeReaderOptions With {
        .ExpectMultipleBarcodes = True,
        .MaxParallelThreads = 4
    }

    Return BarcodeReader.Read(imagePath, options) _
        .Select(Function(r) r.Value) _
        .ToList()
End Function
$vbLabelText   $csharpLabel

从字节(内存映像)读取

之前 — Dynamsoft:

using Dynamsoft.CVR;
using Dynamsoft.Core;
using Dynamsoft.DBR;

// Requires width, height, stride, and pixel format — low-level buffer API
public string ReadFromBuffer(CaptureVisionRouter router, byte[] rawPixels, int width, int height)
{
    var imageData = new ImageData
    {
        Bytes = rawPixels,
        Width = width,
        Height = height,
        Stride = width * 3, // assuming 24bpp RGB
        Format = EnumImagePixelFormat.IPF_RGB_888
    };

    CapturedResult result = router.Capture(imageData, PresetTemplate.PT_READ_BARCODES);
    return result.GetDecodedBarcodesResult()?.GetItems()?.FirstOrDefault()?.GetText();
}
using Dynamsoft.CVR;
using Dynamsoft.Core;
using Dynamsoft.DBR;

// Requires width, height, stride, and pixel format — low-level buffer API
public string ReadFromBuffer(CaptureVisionRouter router, byte[] rawPixels, int width, int height)
{
    var imageData = new ImageData
    {
        Bytes = rawPixels,
        Width = width,
        Height = height,
        Stride = width * 3, // assuming 24bpp RGB
        Format = EnumImagePixelFormat.IPF_RGB_888
    };

    CapturedResult result = router.Capture(imageData, PresetTemplate.PT_READ_BARCODES);
    return result.GetDecodedBarcodesResult()?.GetItems()?.FirstOrDefault()?.GetText();
}
Imports Dynamsoft.CVR
Imports Dynamsoft.Core
Imports Dynamsoft.DBR

' Requires width, height, stride, and pixel format — low-level buffer API
Public Function ReadFromBuffer(router As CaptureVisionRouter, rawPixels As Byte(), width As Integer, height As Integer) As String
    Dim imageData As New ImageData With {
        .Bytes = rawPixels,
        .Width = width,
        .Height = height,
        .Stride = width * 3, ' assuming 24bpp RGB
        .Format = EnumImagePixelFormat.IPF_RGB_888
    }

    Dim result As CapturedResult = router.Capture(imageData, PresetTemplate.PT_READ_BARCODES)
    Return result.GetDecodedBarcodesResult()?.GetItems()?.FirstOrDefault()?.GetText()
End Function
$vbLabelText   $csharpLabel

之后IronBarcode:

using IronBarCode;

// Pass PNG/JPEG/BMP bytes directly — no pixel format or stride calculation
public string ReadFromImageBytes(byte[] imageBytes)
{
    return BarcodeReader.Read(imageBytes)?.FirstOrDefault()?.Value;
}
using IronBarCode;

// Pass PNG/JPEG/BMP bytes directly — no pixel format or stride calculation
public string ReadFromImageBytes(byte[] imageBytes)
{
    return BarcodeReader.Read(imageBytes)?.FirstOrDefault()?.Value;
}
Imports IronBarCode

Public Function ReadFromImageBytes(imageBytes As Byte()) As String
    Return BarcodeReader.Read(imageBytes)?.FirstOrDefault()?.Value
End Function
$vbLabelText   $csharpLabel

如果您的应用程序之前已将图像字节转换为 Dynamsoft 的原始像素缓冲区,则您可以将原始编码图像字节(PNG、JPEG、BMP)直接传递给IronBarcode,而无需先解码为原始像素。

PDF条形码读取——移除渲染循环

这通常是迁移过程中代码量减少最多的部分。 移除整个 PdfiumViewer 渲染循环,并用单个调用代替。

之前 — Dynamsoft 与 PdfiumViewer:

// Requires: Dynamsoft.DotNet.BarcodeReader.Bundle + PdfiumViewer + PdfiumViewer.Native.*
using Dynamsoft.CVR;
using Dynamsoft.DBR;
using PdfiumViewer;
using System.Drawing.Imaging;

public List<string> ReadBarcodesFromPdf(CaptureVisionRouter router, string pdfPath)
{
    var allBarcodes = new List<string>();

    using (var pdfDoc = PdfDocument.Load(pdfPath))
    {
        for (int page = 0; page < pdfDoc.PageCount; page++)
        {
            using var image = pdfDoc.Render(page, 300, 300, true);
            using var ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);

            CapturedResult result = router.Capture(ms.ToArray(),
                PresetTemplate.PT_READ_BARCODES);
            var items = result.GetDecodedBarcodesResult()?.GetItems();
            if (items != null)
            {
                foreach (var item in items)
                    allBarcodes.Add(item.GetText());
            }
        }
    }

    return allBarcodes;
}
// Requires: Dynamsoft.DotNet.BarcodeReader.Bundle + PdfiumViewer + PdfiumViewer.Native.*
using Dynamsoft.CVR;
using Dynamsoft.DBR;
using PdfiumViewer;
using System.Drawing.Imaging;

public List<string> ReadBarcodesFromPdf(CaptureVisionRouter router, string pdfPath)
{
    var allBarcodes = new List<string>();

    using (var pdfDoc = PdfDocument.Load(pdfPath))
    {
        for (int page = 0; page < pdfDoc.PageCount; page++)
        {
            using var image = pdfDoc.Render(page, 300, 300, true);
            using var ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);

            CapturedResult result = router.Capture(ms.ToArray(),
                PresetTemplate.PT_READ_BARCODES);
            var items = result.GetDecodedBarcodesResult()?.GetItems();
            if (items != null)
            {
                foreach (var item in items)
                    allBarcodes.Add(item.GetText());
            }
        }
    }

    return allBarcodes;
}
Imports Dynamsoft.CVR
Imports Dynamsoft.DBR
Imports PdfiumViewer
Imports System.Drawing.Imaging

Public Function ReadBarcodesFromPdf(router As CaptureVisionRouter, pdfPath As String) As List(Of String)
    Dim allBarcodes As New List(Of String)()

    Using pdfDoc As PdfDocument = PdfDocument.Load(pdfPath)
        For page As Integer = 0 To pdfDoc.PageCount - 1
            Using image = pdfDoc.Render(page, 300, 300, True)
                Using ms As New MemoryStream()
                    image.Save(ms, ImageFormat.Png)

                    Dim result As CapturedResult = router.Capture(ms.ToArray(), PresetTemplate.PT_READ_BARCODES)
                    Dim items = result.GetDecodedBarcodesResult()?.GetItems()
                    If items IsNot Nothing Then
                        For Each item In items
                            allBarcodes.Add(item.GetText())
                        Next
                    End If
                End Using
            End Using
        Next
    End Using

    Return allBarcodes
End Function
$vbLabelText   $csharpLabel

之后IronBarcode:

using IronBarCode;

public List<string> ReadBarcodesFromPdf(string pdfPath)
{
    return BarcodeReader.Read(pdfPath)
        .Select(r => r.Value)
        .ToList();
}
using IronBarCode;

public List<string> ReadBarcodesFromPdf(string pdfPath)
{
    return BarcodeReader.Read(pdfPath)
        .Select(r => r.Value)
        .ToList();
}
Imports IronBarCode

Public Function ReadBarcodesFromPdf(pdfPath As String) As List(Of String)
    Return BarcodeReader.Read(pdfPath) _
        .Select(Function(r) r.Value) _
        .ToList()
End Function
$vbLabelText   $csharpLabel

页面循环、PdfDocument、300 DPI渲染步骤、MemoryStream以及每页捕获调用全部消失。 IronBarcode在内部处理 PDF 页面。

如果您需要读取带有选项的 PDF 文件(例如,用于读取密集或难以识别的条形码):

using IronBarCode;

public List<string> ReadBarcodesFromPdfAccurate(string pdfPath)
{
    var options = new BarcodeReaderOptions
    {
        Speed = ReadingSpeed.Balanced,
        ExpectMultipleBarcodes = true
    };

    return BarcodeReader.Read(pdfPath, options)
        .Select(r => r.Value)
        .ToList();
}
using IronBarCode;

public List<string> ReadBarcodesFromPdfAccurate(string pdfPath)
{
    var options = new BarcodeReaderOptions
    {
        Speed = ReadingSpeed.Balanced,
        ExpectMultipleBarcodes = true
    };

    return BarcodeReader.Read(pdfPath, options)
        .Select(r => r.Value)
        .ToList();
}
Imports IronBarCode

Public Function ReadBarcodesFromPdfAccurate(pdfPath As String) As List(Of String)
    Dim options As New BarcodeReaderOptions With {
        .Speed = ReadingSpeed.Balanced,
        .ExpectMultipleBarcodes = True
    }

    Return BarcodeReader.Read(pdfPath, options) _
        .Select(Function(r) r.Value) _
        .ToList()
End Function
$vbLabelText   $csharpLabel

离线/物理隔离部署

如果您的代码中包含离线许可模式,请将其完全删除:

之前 — Dynamsoft 离线许可证:

using Dynamsoft.License;
using Dynamsoft.Core;

// Dynamsoft offline: fetch license bundle on a connected machine, persist it,
// then replay it on the offline machine via InitLicenseFromLicenseContent.
int errorCode = LicenseManager.InitLicenseFromLicenseContent(
    licenseContent,
    out string errorMsg);

if (errorCode != (int)EnumErrorCode.EC_OK)
    throw new InvalidOperationException($"Offline license failed: {errorMsg}");
using Dynamsoft.License;
using Dynamsoft.Core;

// Dynamsoft offline: fetch license bundle on a connected machine, persist it,
// then replay it on the offline machine via InitLicenseFromLicenseContent.
int errorCode = LicenseManager.InitLicenseFromLicenseContent(
    licenseContent,
    out string errorMsg);

if (errorCode != (int)EnumErrorCode.EC_OK)
    throw new InvalidOperationException($"Offline license failed: {errorMsg}");
Imports Dynamsoft.License
Imports Dynamsoft.Core

' Dynamsoft offline: fetch license bundle on a connected machine, persist it,
' then replay it on the offline machine via InitLicenseFromLicenseContent.
Dim errorMsg As String
Dim errorCode As Integer = LicenseManager.InitLicenseFromLicenseContent(licenseContent, errorMsg)

If errorCode <> CType(EnumErrorCode.EC_OK, Integer) Then
    Throw New InvalidOperationException($"Offline license failed: {errorMsg}")
End If
$vbLabelText   $csharpLabel

之后IronBarcode:

// Remove all of the above. Replace with:
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// Remove all of the above. Replace with:
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

没有许可证内容包需要获取和刷新。 没有连接机器引导步骤。密钥在本地验证。

Docker 配置

如果您之前有网络出口规则或代理配置以允许出站HTTPS到Dynamsoft的许可证端点:

# Before: Docker or Kubernetes egress policy
# Required: Allow outbound HTTPS to Dynamsoft licence endpoints

# After: Remove that egress rule.
# IronBarcode does not require outbound network access for license validation.

# Set license via environment variable
env:
  - name: IRONBARCODE_KEY
    valueFrom:
      secretKeyRef:
        name: ironbarcode-license
        key: key
# Before: Docker or Kubernetes egress policy
# Required: Allow outbound HTTPS to Dynamsoft licence endpoints

# After: Remove that egress rule.
# IronBarcode does not require outbound network access for license validation.

# Set license via environment variable
env:
  - name: IRONBARCODE_KEY
    valueFrom:
      secretKeyRef:
        name: ironbarcode-license
        key: key
YAML

实例管理清理

Dynamsoft使用一个基于CaptureVisionRouter构建的实例API。 如果您的代码在服务类、字段初始化程序或DI注册中创建路由器实例,这些全部消失。

之前——Dynamsoft实例管理:

using Dynamsoft.CVR;
using Dynamsoft.DBR;
using Dynamsoft.License;
using Dynamsoft.Core;

public class BarcodeService : IDisposable
{
    private readonly CaptureVisionRouter _router;

    public BarcodeService()
    {
        int errorCode = LicenseManager.InitLicense("KEY", out string errorMsg);
        if (errorCode != (int)EnumErrorCode.EC_OK)
            throw new InvalidOperationException(errorMsg);

        _router = new CaptureVisionRouter();

        var settings = _router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES);
        settings.BarcodeSettings.ExpectedBarcodesCount = 0;
        _router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);
    }

    public string[] ReadFile(string path)
    {
        CapturedResult result = _router.Capture(path, PresetTemplate.PT_READ_BARCODES);
        var items = result.GetDecodedBarcodesResult()?.GetItems();
        return items?.Select(i => i.GetText()).ToArray() ?? Array.Empty<string>();
    }

    public void Dispose()
    {
        _router?.Dispose();
    }
}
using Dynamsoft.CVR;
using Dynamsoft.DBR;
using Dynamsoft.License;
using Dynamsoft.Core;

public class BarcodeService : IDisposable
{
    private readonly CaptureVisionRouter _router;

    public BarcodeService()
    {
        int errorCode = LicenseManager.InitLicense("KEY", out string errorMsg);
        if (errorCode != (int)EnumErrorCode.EC_OK)
            throw new InvalidOperationException(errorMsg);

        _router = new CaptureVisionRouter();

        var settings = _router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES);
        settings.BarcodeSettings.ExpectedBarcodesCount = 0;
        _router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);
    }

    public string[] ReadFile(string path)
    {
        CapturedResult result = _router.Capture(path, PresetTemplate.PT_READ_BARCODES);
        var items = result.GetDecodedBarcodesResult()?.GetItems();
        return items?.Select(i => i.GetText()).ToArray() ?? Array.Empty<string>();
    }

    public void Dispose()
    {
        _router?.Dispose();
    }
}
Imports Dynamsoft.CVR
Imports Dynamsoft.DBR
Imports Dynamsoft.License
Imports Dynamsoft.Core

Public Class BarcodeService
    Implements IDisposable

    Private ReadOnly _router As CaptureVisionRouter

    Public Sub New()
        Dim errorCode As Integer = LicenseManager.InitLicense("KEY", errorMsg:=Nothing)
        If errorCode <> CType(EnumErrorCode.EC_OK, Integer) Then
            Throw New InvalidOperationException(errorMsg)
        End If

        _router = New CaptureVisionRouter()

        Dim settings = _router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES)
        settings.BarcodeSettings.ExpectedBarcodesCount = 0
        _router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings)
    End Sub

    Public Function ReadFile(path As String) As String()
        Dim result As CapturedResult = _router.Capture(path, PresetTemplate.PT_READ_BARCODES)
        Dim items = result.GetDecodedBarcodesResult()?.GetItems()
        Return If(items?.Select(Function(i) i.GetText()).ToArray(), Array.Empty(Of String)())
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        _router?.Dispose()
    End Sub
End Class
$vbLabelText   $csharpLabel

之后IronBarcode静态API:

// NuGet: dotnet add package BarCode
using IronBarCode;

public class BarcodeService
{
    // No constructor initialization — license set once at app startup
    // No Dispose — no instance to clean up

    public string[] ReadFile(string path)
    {
        var options = new BarcodeReaderOptions { ExpectMultipleBarcodes = true };
        return BarcodeReader.Read(path, options)
            .Select(r => r.Value)
            .ToArray();
    }
}
// NuGet: dotnet add package BarCode
using IronBarCode;

public class BarcodeService
{
    // No constructor initialization — license set once at app startup
    // No Dispose — no instance to clean up

    public string[] ReadFile(string path)
    {
        var options = new BarcodeReaderOptions { ExpectMultipleBarcodes = true };
        return BarcodeReader.Read(path, options)
            .Select(r => r.Value)
            .ToArray();
    }
}
Imports IronBarCode

Public Class BarcodeService
    ' No constructor initialization — license set once at app startup
    ' No Dispose — no instance to clean up

    Public Function ReadFile(path As String) As String()
        Dim options As New BarcodeReaderOptions With {.ExpectMultipleBarcodes = True}
        Return BarcodeReader.Read(path, options) _
            .Select(Function(r) r.Value) _
            .ToArray()
    End Function
End Class
$vbLabelText   $csharpLabel

该类失去了它的构造函数,它的_router字段。 如果此服务在DI中注册为singleton或scoped service来管理路由器生命周期,该注册可以简化或服务可以成为一组静态方法。

阅读速度与超时时间的关系

Dynamsoft使用一个以毫秒为单位的Timeout,针对摄像头帧率进行了优化。 IronBarcode使用一个ReadingSpeed枚举:

Dynamsoft 设置 IronBarcode等效产品
settings.Timeout = 100 (摄像头管线) Speed = ReadingSpeed.Faster
低超时时间(优先考虑速度) Speed = ReadingSpeed.Balanced
更高的超时时间(优先考虑准确性) Speed = ReadingSpeed.Detailed
最高精度,无时间压力 Speed = ReadingSpeed.ExtremeDetail

对于大多数文档处理工作流中,吞吐量比小于100毫秒的响应时间更重要,ReadingSpeed.Balanced是正确的默认设置:

var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true,
    MaxParallelThreads = 4
};
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true,
    MaxParallelThreads = 4
};
Dim options As New BarcodeReaderOptions With {
    .Speed = ReadingSpeed.Balanced,
    .ExpectMultipleBarcodes = True,
    .MaxParallelThreads = 4
}
$vbLabelText   $csharpLabel

常见迁移问题

BarcodeResultItem.GetText() vs result.Value

访问器从方法改为属性:

// Before
string value = item.GetText();

// After
string value = result.Value;
// Before
string value = item.GetText();

// After
string value = result.Value;
' Before
Dim value As String = item.GetText()

' After
Dim value As String = result.Value
$vbLabelText   $csharpLabel

BarcodeResultItem.GetFormatString() vs result.Format

Dynamsoft通过GetFormatString()以字符串形式返回格式。 IronBarcode通过result.Format上公开它:

// Before
if (item.GetFormatString() == "QR_CODE")
    Console.WriteLine("Found QR code");

// After
if (result.Format == BarcodeEncoding.QRCode)
    Console.WriteLine("Found QR code");

// For logging without enum comparison — .ToString() works on both
Console.WriteLine($"Format: {result.Format}");
// Before
if (item.GetFormatString() == "QR_CODE")
    Console.WriteLine("Found QR code");

// After
if (result.Format == BarcodeEncoding.QRCode)
    Console.WriteLine("Found QR code");

// For logging without enum comparison — .ToString() works on both
Console.WriteLine($"Format: {result.Format}");
' Before
If item.GetFormatString() = "QR_CODE" Then
    Console.WriteLine("Found QR code")
End If

' After
If result.Format = BarcodeEncoding.QRCode Then
    Console.WriteLine("Found QR code")
End If

' For logging without enum comparison — .ToString() works on both
Console.WriteLine($"Format: {result.Format}")
$vbLabelText   $csharpLabel

空结果与空集合

当未找到条形码时,Dynamsoft的null。 IronBarcode返回一个空集合。 更新空值检查:

// Before: null check required
CapturedResult result = router.Capture(path, PresetTemplate.PT_READ_BARCODES);
var items = result.GetDecodedBarcodesResult()?.GetItems();
if (items != null && items.Length > 0)
    Process(items[0].GetText());

// After: null-safe but also correct to check Count
var results = BarcodeReader.Read(path);
if (results.Any())
    Process(results.First().Value);
// Before: null check required
CapturedResult result = router.Capture(path, PresetTemplate.PT_READ_BARCODES);
var items = result.GetDecodedBarcodesResult()?.GetItems();
if (items != null && items.Length > 0)
    Process(items[0].GetText());

// After: null-safe but also correct to check Count
var results = BarcodeReader.Read(path);
if (results.Any())
    Process(results.First().Value);
Imports System.Linq

' Before: null check required
Dim result As CapturedResult = router.Capture(path, PresetTemplate.PT_READ_BARCODES)
Dim items = result.GetDecodedBarcodesResult()?.GetItems()
If items IsNot Nothing AndAlso items.Length > 0 Then
    Process(items(0).GetText())
End If

' After: null-safe but also correct to check Count
Dim results = BarcodeReader.Read(path)
If results.Any() Then
    Process(results.First().Value)
End If
$vbLabelText   $csharpLabel

SimplifiedCaptureVisionSettings to BarcodeReaderOptions

GetSimplifiedSettings / Read

// Before
var settings = router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES);
settings.BarcodeSettings.ExpectedBarcodesCount = 0;
settings.Timeout = 500;
router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);
var result = router.Capture(path, PresetTemplate.PT_READ_BARCODES);

// After
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true
};
var results = BarcodeReader.Read(path, options);
// Before
var settings = router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES);
settings.BarcodeSettings.ExpectedBarcodesCount = 0;
settings.Timeout = 500;
router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);
var result = router.Capture(path, PresetTemplate.PT_READ_BARCODES);

// After
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true
};
var results = BarcodeReader.Read(path, options);
' Before
Dim settings = router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES)
settings.BarcodeSettings.ExpectedBarcodesCount = 0
settings.Timeout = 500
router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings)
Dim result = router.Capture(path, PresetTemplate.PT_READ_BARCODES)

' After
Dim options As New BarcodeReaderOptions With {
    .Speed = ReadingSpeed.Balanced,
    .ExpectMultipleBarcodes = True
}
Dim results = BarcodeReader.Read(path, options)
$vbLabelText   $csharpLabel

迁移清单

运行以下搜索,查找所有需要更新的 Dynamsoft 参考资料:

grep -r "using Dynamsoft\." --include="*.cs" .
grep -r "LicenseManager.InitLicense\|EnumErrorCode\|EC_OK" --include="*.cs" .
grep -r "new CaptureVisionRouter\|router\.Capture\|PresetTemplate" --include="*.cs" .
grep -r "BarcodeResultItem\|GetDecodedBarcodesResult\|GetFormatString" --include="*.cs" .
grep -r "GetSimplifiedSettings\|UpdateSettings\|SimplifiedCaptureVisionSettings" --include="*.cs" .
grep -r "router\.Dispose\|InitLicenseFromLicenseContent" --include="*.cs" .
grep -r "using Dynamsoft\." --include="*.cs" .
grep -r "LicenseManager.InitLicense\|EnumErrorCode\|EC_OK" --include="*.cs" .
grep -r "new CaptureVisionRouter\|router\.Capture\|PresetTemplate" --include="*.cs" .
grep -r "BarcodeResultItem\|GetDecodedBarcodesResult\|GetFormatString" --include="*.cs" .
grep -r "GetSimplifiedSettings\|UpdateSettings\|SimplifiedCaptureVisionSettings" --include="*.cs" .
grep -r "router\.Dispose\|InitLicenseFromLicenseContent" --include="*.cs" .
SHELL

逐场比赛进行分析:

  • using Dynamsoft.*using IronBarCode
  • LicenseManager.InitLicense(key, out errorMsg) + 错误检查 → IronBarCode.License.LicenseKey = "key"
  • new CaptureVisionRouter() → 移除(静态API,无实例)
  • router.Capture(path, PresetTemplate.PT_READ_BARCODES)BarcodeReader.Read(path)
  • router.Capture(imageData, ...) (原始像素缓冲) → BarcodeReader.Read(imageBytes)
  • 每页PDF渲染循环 + router.Capture(pageBytes, ...)BarcodeReader.Read(pdfPath)
  • BarcodeResultItem.GetText()result.Value
  • BarcodeResultItem.GetFormatString()result.Format
  • GetSimplifiedSettings(...) + UpdateSettings(...)new BarcodeReaderOptions { ... }
  • router.Dispose() → 移除
  • LicenseManager.InitLicenseFromLicenseContent(...) → 完全移除
  • 如果添加 PdfiumViewer NuGet包仅仅是为了支持 Dynamsoft PDF 处理,则将其移除。
  • 移除Dynamsoft许可端点的Docker/Kubernetes网络出口规则
  • 在部署配置中设置IRONBARCODE_KEY环境变量

常见问题解答

我为什么要从 Dynamsoft 条码阅读器迁移到 IronBarcode?

常见原因包括简化许可(消除 SDK + 运行时密钥的复杂性)、消除吞吐量限制、获得原生 PDF 支持、改进 Docker/CI/CD 部署以及减少生产代码中的 API 样板代码。

如何用 IronBarcode 替换 Dynamsoft API 调用?

用 `IronBarCode.License.LicenseKey = "key"` 替换实例创建和许可相关的样板代码。用 `BarcodeReader.Read(path)` 替换读取器调用,用 `BarcodeWriter.CreateBarcode(data, encoding)` 替换写入器调用。静态方法无需实例管理。

从 Dynamsoft 条码阅读器迁移到 IronBarcode 时,需要修改多少代码?

大多数迁移都能减少代码行数。许可样板代码、实例构造函数和显式格式配置都被移除。核心读/写操作映射到更简洁的 IronBarcode 等效代码,并生成更清晰的结果对象。

迁移过程中是否需要同时安装 Dynamsoft Barcode Reader 和 IronBarcode?

不。大多数迁移都是直接替换,而不是并行操作。一次迁移一个服务类,替换 NuGet 引用,并更新实例化和 API 调用模式,然后再迁移下一个类。

IronBarcode 的 NuGet 包名称是什么?

该软件包名为“IronBarCode”(B 和 C 大写)。使用“Install-Package IronBarCode”或“dotnet add package IronBarCode”进行安装。代码中的 using 指令为“using IronBarCode;”。

与 Dynamsoft 条码阅读器相比,IronBarcode 如何简化 Docker 部署?

IronBarcode 是一个 NuGet 包,不包含任何外部 SDK 文件或已挂载的许可证配置。在 Docker 环境中,设置 IRONBARCODE_LICENSE_KEY 环境变量后,该包会在启动时自动处理许可证验证。

从 Dynamsoft 迁移后,IronBarcode 是否能自动检测所有条形码格式?

是的。IronBarcode 可以自动检测所有支持格式的条码符号,无需显式枚举 BarcodeTypes。如果已知条码格式且性能至关重要,BarcodeReaderOptions 允许缩小搜索范围以进行优化。

IronBarcode 能否在不使用单独库的情况下读取 PDF 中的条形码?

是的。`BarcodeReader.Read("document.pdf")` 可以直接处理 PDF 文件。结果包括每个条形码的页码、格式、值和置信度。无需外部 PDF 渲染步骤。

IronBarcode如何处理并行条码处理?

IronBarcode 的静态方法是无状态且线程安全的。可以直接对文件列表使用 Parallel.ForEach,无需进行线程级实例管理。BarcodeReaderOptions.MaxParallelThreads 控制内部线程预算。

从 Dynamsoft 条码阅读器迁移到 IronBarcode 时,哪些结果属性会发生变化?

常见重命名:BarcodeValue 变为 Value,BarcodeType 变为 Format。IronBarcode 结果还会添加 Confidence 和 PageNumber。解决方案范围内的查找替换功能会处理现有结果处理代码中的重命名。

如何在 CI/CD 流水线中设置 IronBarcode 许可?

将 IRONBARCODE_LICENSE_KEY 存储为管道密钥,并在应用程序启动代码中赋值 IronBarCode.License.LicenseKey。一个密钥即可覆盖所有环境,包括开发、测试、预发布和生产环境。

IronBarcode是否支持生成自定义样式的二维码?

是的。QRCodeWriter.CreateQrCode() 支持通过 ChangeBarCodeColor() 自定义颜色、通过 AddBrandLogo() 嵌入徽标、可配置纠错级别以及多种输出格式,包括 PNG、JPG、PDF 和流媒体。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

钢铁支援团队

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