跳至页脚内容
视频

How to Customize and Add Logos to QR Codes in C#

从Accusoft BarcodeXpress迁移到 IronBarcode

这次迁移的大部分工作都是删除。 两键许可系统 — SetSolutionKeySetOEMLicenseKey 用于运行时 — 完全消失。 实际的条码操作(读取图像、将条码写入文件)转换为更短的IronBarcode等效操作。 如果您的代码库中有一个包裹BarcodeXpress的BarcodeService类,那么许可代码通常占据了很大一部分。 迁移后,那个类将缩小。

为什么要从Accusoft BarcodeXpress迁移?

从 BarcodeXpress 迁移的团队报告了以下触发因素:

评估模式阻碍准确的基准测试:没有有效的 OEM/运行时密钥,BarcodeXpress 会用字面字符串" UNLICENSED accusoft.com " 标记解码结果,并将同样的标记应用于生成的2D条码。 在真实文档上进行预购买准确性检测会产生这种水印输出,因此您无法验证库在购买之前能否正确读取您的实际扫描类型。

两键许可增加操作开销:BarcodeXpress将SDK许可证(SetSolutionName + SetOEMLicenseKey)分离。 CI/CD 流水线、Docker 容器和容器编排器都需要将这两个关键系统作为单独的密钥进行管理。 缺失或无效的运行时密钥会退回到带水印的输出而不是报错,这会创建一个故障模式,如果断言仅检测非空结果则能通过自动测试。

任何生产部署至少需要五个运行时许可证:即使是单服务器部署也需要购买至少五个运行时许可证。 无论实际使用量如何,运行一台生产服务器和一台测试服务器的团队至少需要支付十个运行时许可证费用。

标准版每分钟处理速度上限为 40 页:标准版将处理速度限制为每分钟 40 页。 按这个速度,处理 10 万份文件大约需要 41 个小时。 要解除上限,需要升级到Professional版,这除了已经购买的运行时许可证之外,还需要支付更高的每个开发人员席位费用。

不支持原生 PDF:必须先使用单独的库将 PDF 文件渲染成图像,BarcodeXpress 才能读取它们。 这种外部依赖关系增加了第二个许可成本、转换步骤,以及保存渲染页面图像带来的额外内存压力。

线程安全需要实例隔离:BarcodeXpress的reader对象是有状态的,并且不适合并发访问。 并行批处理要求每个线程都有一个完全初始化的BarcodeXpress实例,并且在每个线程上下文中重复完整的两层许可证初始化。

基本问题

BarcodeXpress在读取任何条码之前需要多步初始化、位图加载和BarcodeType[]配置。

using var bitmap = new Bitmap(imagePath);
var barcodeXpress = new BarcodeXpress(".");
barcodeXpress.Licensing.SetSolutionName("AcmeCorp");
barcodeXpress.Licensing.SetSolutionKey(1, 2, 3, 4);
barcodeXpress.Licensing.SetOEMLicenseKey("2.0.OEMLicenseStringFromAccusoft...");

barcodeXpress.reader.BarcodeTypes = new[]
{
    BarcodeType.Code128Barcode,
    BarcodeType.DataMatrixBarcode,
    BarcodeType.QRCodeBarcode
};

Result[] results = barcodeXpress.reader.Analyze(bitmap);
var value = results.FirstOrDefault()?.BarcodeValue;
using var bitmap = new Bitmap(imagePath);
var barcodeXpress = new BarcodeXpress(".");
barcodeXpress.Licensing.SetSolutionName("AcmeCorp");
barcodeXpress.Licensing.SetSolutionKey(1, 2, 3, 4);
barcodeXpress.Licensing.SetOEMLicenseKey("2.0.OEMLicenseStringFromAccusoft...");

barcodeXpress.reader.BarcodeTypes = new[]
{
    BarcodeType.Code128Barcode,
    BarcodeType.DataMatrixBarcode,
    BarcodeType.QRCodeBarcode
};

Result[] results = barcodeXpress.reader.Analyze(bitmap);
var value = results.FirstOrDefault()?.BarcodeValue;
Imports System.Drawing
Imports Accusoft.BarcodeXpressSdk

Using bitmap As New Bitmap(imagePath)
    Dim barcodeXpress = New BarcodeXpress(".")
    barcodeXpress.Licensing.SetSolutionName("AcmeCorp")
    barcodeXpress.Licensing.SetSolutionKey(1, 2, 3, 4)
    barcodeXpress.Licensing.SetOEMLicenseKey("2.0.OEMLicenseStringFromAccusoft...")

    barcodeXpress.Reader.BarcodeTypes = New BarcodeType() {
        BarcodeType.Code128Barcode,
        BarcodeType.DataMatrixBarcode,
        BarcodeType.QRCodeBarcode
    }

    Dim results As Result() = barcodeXpress.Reader.Analyze(bitmap)
    Dim value = results.FirstOrDefault()?.BarcodeValue
End Using
$vbLabelText   $csharpLabel

IronBarcode将整个代码块替换为一个静态调用:

var value = BarcodeReader.Read(imagePath).First().Value;
var value = BarcodeReader.Read(imagePath).First().Value;
Dim value = BarcodeReader.Read(imagePath).First().Value
$vbLabelText   $csharpLabel

IronBarcode与 Accusoft BarcodeXpress:功能对比

特征 Accusoft BarcodeXpress IronBarcode
许可模式 SDK 密钥 + OEM/运行时密钥(单独购买) 单永久钥匙
最低运行时许可 5(即使只有一台服务器) 无运行时许可概念
评估模式 解码值和生成的 2D 条码标记有 " UNLICENSED accusoft.com " 返回全部值; 仅在生成的输出上添加水印
吞吐量限制 40 PPM(标准版) 任何级别均无限制
格式自动检测 手动 — 必须将BarcodeTypes 所有支持的格式均自动运行
PDF 支持 需要外部库呈现页面到 Bitmaps 原生 — BarcodeReader.Read("doc.pdf")
API 风格 基于实例; Bitmap 输入; 属性/方法配置 静态工厂方法,流畅 API
线程安全 每个线程一个实例是必需的。 无状态静态方法 — 线程安全
Docker 许可证配置 许可证文件挂载点或许可证服务器 单个环境变量
CI/CD 密钥 SDK 密钥对 + OEM/运行时密钥 一个秘密
.NET Framework / .NET Core 单独的包:Accusoft.BarcodeXpress.NetAccusoft.BarcodeXpress.NetCore 单一IronBarcode包(.NET Framework 4.6.2+、.NET Core 3.1+、.NET 5–8)
Linux/macOS 是 (通过 .NetCore 包) 是的——Windows x64/x86、Linux x64、macOS x64/ARM
带有徽标的二维码 需要手动 GDI+ 叠加 AddBrandLogo("logo.png") 内置的
定价切入点 $1,960+ SDK + 最少5个运行时许可证 749 美元永久版(Lite,1 位开发者)
永久许可 非标准配置——请联系销售 是的,所有级别

快速入门:Accusoft BarcodeXpress 到IronBarcode 的迁移

步骤 1:替换 NuGet 软件包

dotnet remove package Accusoft.BarcodeXpress.NetCore
dotnet add package IronBarcode
dotnet remove package Accusoft.BarcodeXpress.NetCore
dotnet add package IronBarcode
SHELL

步骤 2:更新命名空间

// Remove
using Accusoft.BarcodeXpressSdk;

// Add
using IronBarCode;
// Remove
using Accusoft.BarcodeXpressSdk;

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

步骤 3:初始化许可证

在应用程序启动时在Startup.cs或依赖注入配置中添加许可初始化一次:

// Add once at application startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add once at application startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add once at application startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

在生产环境中,从环境变量或密钥管理器中读取密钥:

IronBarCode.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE")
    ?? throw new InvalidOperationException("IronBarcode license key not configured");
IronBarCode.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE")
    ?? throw new InvalidOperationException("IronBarcode license key not configured");
Imports IronBarCode
Imports System

License.LicenseKey = If(Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE"), Throw New InvalidOperationException("IronBarcode license key not configured"))
$vbLabelText   $csharpLabel

无需SetOEMLicenseKey,无需每服务器运行时激活。 这就是完整的许可证设置。

代码迁移示例

许可证初始化

BarcodeXpress 方法:

using Accusoft.BarcodeXpressSdk;

public class BarcodeService
{
    private readonly BarcodeXpress _barcodeXpress;

    public BarcodeService()
    {
        // Constructor takes the path containing the Barcode Xpress runtime files.
        _barcodeXpress = new BarcodeXpress(".");

        // SDK license
        _barcodeXpress.Licensing.SetSolutionName("AcmeCorp");
        _barcodeXpress.Licensing.SetSolutionKey(1, 2, 3, 4);

        // OEM/runtime license — separate purchase, minimum 5 licenses required.
        // Without this call, decoded values and generated 2D barcodes are
        // stamped with " UNLICENSED accusoft.com ".
        _barcodeXpress.Licensing.SetOEMLicenseKey(
            "2.0.OEMLicenseStringFromAccusoft...");
    }
}
using Accusoft.BarcodeXpressSdk;

public class BarcodeService
{
    private readonly BarcodeXpress _barcodeXpress;

    public BarcodeService()
    {
        // Constructor takes the path containing the Barcode Xpress runtime files.
        _barcodeXpress = new BarcodeXpress(".");

        // SDK license
        _barcodeXpress.Licensing.SetSolutionName("AcmeCorp");
        _barcodeXpress.Licensing.SetSolutionKey(1, 2, 3, 4);

        // OEM/runtime license — separate purchase, minimum 5 licenses required.
        // Without this call, decoded values and generated 2D barcodes are
        // stamped with " UNLICENSED accusoft.com ".
        _barcodeXpress.Licensing.SetOEMLicenseKey(
            "2.0.OEMLicenseStringFromAccusoft...");
    }
}
Imports Accusoft.BarcodeXpressSdk

Public Class BarcodeService
    Private ReadOnly _barcodeXpress As BarcodeXpress

    Public Sub New()
        ' Constructor takes the path containing the Barcode Xpress runtime files.
        _barcodeXpress = New BarcodeXpress(".")

        ' SDK license
        _barcodeXpress.Licensing.SetSolutionName("AcmeCorp")
        _barcodeXpress.Licensing.SetSolutionKey(1, 2, 3, 4)

        ' OEM/runtime license — separate purchase, minimum 5 licenses required.
        ' Without this call, decoded values and generated 2D barcodes are
        ' stamped with " UNLICENSED accusoft.com ".
        _barcodeXpress.Licensing.SetOEMLicenseKey("2.0.OEMLicenseStringFromAccusoft...")
    End Sub
End Class
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

// In Program.cs
IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE");

// BarcodeService no longer needs a constructor or any license management
public class BarcodeService
{
    // Ready to use — no initialization needed
}
using IronBarCode;

// In Program.cs
IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE");

// BarcodeService no longer needs a constructor or any license management
public class BarcodeService
{
    // Ready to use — no initialization needed
}
Imports IronBarCode

' In Program.vb
IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE")

' BarcodeService no longer needs a constructor or any license management
Public Class BarcodeService
    ' Ready to use — no initialization needed
End Class
$vbLabelText   $csharpLabel

BarcodeXpress 构造函数仅用于管理两种许可证密钥系统和运行时路径。 IronBarcode在应用程序启动时用一行替换它。BarcodeService类根本不需要构造函数。

条形码读取

BarcodeXpress 方法:

using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public string ReadFirstBarcode(string imagePath)
{
    // Analyze takes a System.Drawing.Bitmap; the SDK does not read PDFs directly.
    using var bitmap = new Bitmap(imagePath);

    _barcodeXpress.reader.BarcodeTypes = new[]
    {
        BarcodeType.Code128Barcode,
        BarcodeType.DataMatrixBarcode,
        BarcodeType.QRCodeBarcode
    };

    Result[] results = _barcodeXpress.reader.Analyze(bitmap);

    return results.FirstOrDefault()?.BarcodeValue;
}
using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public string ReadFirstBarcode(string imagePath)
{
    // Analyze takes a System.Drawing.Bitmap; the SDK does not read PDFs directly.
    using var bitmap = new Bitmap(imagePath);

    _barcodeXpress.reader.BarcodeTypes = new[]
    {
        BarcodeType.Code128Barcode,
        BarcodeType.DataMatrixBarcode,
        BarcodeType.QRCodeBarcode
    };

    Result[] results = _barcodeXpress.reader.Analyze(bitmap);

    return results.FirstOrDefault()?.BarcodeValue;
}
Imports System.Drawing
Imports Accusoft.BarcodeXpressSdk

Public Function ReadFirstBarcode(imagePath As String) As String
    ' Analyze takes a System.Drawing.Bitmap; the SDK does not read PDFs directly.
    Using bitmap As New Bitmap(imagePath)
        _barcodeXpress.reader.BarcodeTypes = New BarcodeType() {
            BarcodeType.Code128Barcode,
            BarcodeType.DataMatrixBarcode,
            BarcodeType.QRCodeBarcode
        }

        Dim results As Result() = _barcodeXpress.reader.Analyze(bitmap)

        Return results.FirstOrDefault()?.BarcodeValue
    End Using
End Function
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

public string ReadFirstBarcode(string imagePath)
{
    var results = BarcodeReader.Read(imagePath);
    return results.First().Value;
}
using IronBarCode;

public string ReadFirstBarcode(string imagePath)
{
    var results = BarcodeReader.Read(imagePath);
    return results.First().Value;
}
Imports IronBarCode

Public Function ReadFirstBarcode(imagePath As String) As String
    Dim results = BarcodeReader.Read(imagePath)
    Return results.First().Value
End Function
$vbLabelText   $csharpLabel

new Bitmap(...)加载步骤都消失了。IronBarcode自动检测所有支持符号之间的格式并直接接受文件路径。 如果供应商从 Code 128 切换到 DataMatrix, IronBarcode无需任何代码更改即可继续工作。 结果属性名称也改变:BarcodeValue 变为 BarcodeType 变为 Format。 解决方案范围内的查找和替换功能可以处理这两种重命名操作。

从一张图像中读取多个条形码

BarcodeXpress 方法:

using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public IReadOnlyList<string> ReadAllBarcodes(string imagePath)
{
    using var bitmap = new Bitmap(imagePath);
    _barcodeXpress.reader.BarcodeTypes = new[]
    {
        BarcodeType.Code128Barcode,
        BarcodeType.QRCodeBarcode
    };

    Result[] results = _barcodeXpress.reader.Analyze(bitmap);
    return results.Select(r => r.BarcodeValue).ToList();
}
using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public IReadOnlyList<string> ReadAllBarcodes(string imagePath)
{
    using var bitmap = new Bitmap(imagePath);
    _barcodeXpress.reader.BarcodeTypes = new[]
    {
        BarcodeType.Code128Barcode,
        BarcodeType.QRCodeBarcode
    };

    Result[] results = _barcodeXpress.reader.Analyze(bitmap);
    return results.Select(r => r.BarcodeValue).ToList();
}
Imports System.Drawing
Imports Accusoft.BarcodeXpressSdk

Public Function ReadAllBarcodes(imagePath As String) As IReadOnlyList(Of String)
    Using bitmap As New Bitmap(imagePath)
        _barcodeXpress.reader.BarcodeTypes = New BarcodeType() {
            BarcodeType.Code128Barcode,
            BarcodeType.QRCodeBarcode
        }

        Dim results As Result() = _barcodeXpress.reader.Analyze(bitmap)
        Return results.Select(Function(r) r.BarcodeValue).ToList()
    End Using
End Function
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

public IReadOnlyList<string> ReadAllBarcodes(string imagePath)
{
    var options = new BarcodeReaderOptions { ExpectMultipleBarcodes = true };
    var results = BarcodeReader.Read(imagePath, options);
    return results.Select(r => r.Value).ToList();
}
using IronBarCode;

public IReadOnlyList<string> ReadAllBarcodes(string imagePath)
{
    var options = new BarcodeReaderOptions { ExpectMultipleBarcodes = true };
    var results = BarcodeReader.Read(imagePath, options);
    return results.Select(r => r.Value).ToList();
}
Imports IronBarCode

Public Function ReadAllBarcodes(imagePath As String) As IReadOnlyList(Of String)
    Dim options As New BarcodeReaderOptions With {.ExpectMultipleBarcodes = True}
    Dim results = BarcodeReader.Read(imagePath, options)
    Return results.Select(Function(r) r.Value).ToList()
End Function
$vbLabelText   $csharpLabel

ExpectMultipleBarcodes 告诉IronBarcode在第一次匹配后继续扫描,这对于包含多个不同区域代码的文档很有用。 有关读取选项的更多详细信息,请参阅IronBarcode读取文档

批量处理

BarcodeXpress是基于实例的,其reader对象是有状态的,因此并行批处理需要每个线程一个实例,并且对每个线程重复完整的两层许可证初始化。 IronBarcode的静态方法是无状态的,因此Parallel.ForEach不需要实例管理。

BarcodeXpress 方法:

using System.Collections.Generic;
using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> imagePaths)
{
    var results = new Dictionary<string, string>();

    foreach (var path in imagePaths)
    {
        using var bitmap = new Bitmap(path);
        _barcodeXpress.reader.BarcodeTypes = new[]
        {
            BarcodeType.Code128Barcode,
            BarcodeType.QRCodeBarcode
        };

        Result[] barcodes = _barcodeXpress.reader.Analyze(bitmap);
        if (barcodes.Length > 0)
            results[path] = barcodes[0].BarcodeValue;
    }

    return results;
}
using System.Collections.Generic;
using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> imagePaths)
{
    var results = new Dictionary<string, string>();

    foreach (var path in imagePaths)
    {
        using var bitmap = new Bitmap(path);
        _barcodeXpress.reader.BarcodeTypes = new[]
        {
            BarcodeType.Code128Barcode,
            BarcodeType.QRCodeBarcode
        };

        Result[] barcodes = _barcodeXpress.reader.Analyze(bitmap);
        if (barcodes.Length > 0)
            results[path] = barcodes[0].BarcodeValue;
    }

    return results;
}
Imports System.Collections.Generic
Imports System.Drawing
Imports Accusoft.BarcodeXpressSdk

Public Function ProcessBatch(imagePaths As IEnumerable(Of String)) As Dictionary(Of String, String)
    Dim results As New Dictionary(Of String, String)()

    For Each path In imagePaths
        Using bitmap As New Bitmap(path)
            _barcodeXpress.reader.BarcodeTypes = New BarcodeType() {
                BarcodeType.Code128Barcode,
                BarcodeType.QRCodeBarcode
            }

            Dim barcodes As Result() = _barcodeXpress.reader.Analyze(bitmap)
            If barcodes.Length > 0 Then
                results(path) = barcodes(0).BarcodeValue
            End If
        End Using
    Next

    Return results
End Function
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public Dictionary<string, string> ProcessBatch(string[] imagePaths)
{
    var results = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(imagePaths, file =>
    {
        var r = BarcodeReader.Read(file);
        var first = r.FirstOrDefault();
        if (first != null)
            results[file] = first.Value;
    });

    return new Dictionary<string, string>(results);
}
using IronBarCode;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public Dictionary<string, string> ProcessBatch(string[] imagePaths)
{
    var results = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(imagePaths, file =>
    {
        var r = BarcodeReader.Read(file);
        var first = r.FirstOrDefault();
        if (first != null)
            results[file] = first.Value;
    });

    return new Dictionary<string, string>(results);
}
Imports IronBarCode
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Public Function ProcessBatch(imagePaths As String()) As Dictionary(Of String, String)
    Dim results = New ConcurrentDictionary(Of String, String)()

    Parallel.ForEach(imagePaths, Sub(file)
        Dim r = BarcodeReader.Read(file)
        Dim first = r.FirstOrDefault()
        If first IsNot Nothing Then
            results(file) = first.Value
        End If
    End Sub)

    Return New Dictionary(Of String, String)(results)
End Function
$vbLabelText   $csharpLabel

如果 BarcodeXpress 标准版每分钟 40 页的上限导致您添加了速率限制处理代码(例如,在每 40 页之间休眠、跟踪每分钟计数器或添加延迟),请完全删除该代码。IronBarcode的吞吐量没有上限。

添加 PDF 支持

BarcodeXpress 无法直接从 PDF 文件中读取条形码。 典型的解决方法是添加一个单独的 PDF 渲染库,将每一页渲染成内存中的图像,然后将这些图像逐一传递给条形码阅读器。

BarcodeXpress 方法:

// Requires a separate PDF library (not shown — varies by team choice)
// Pattern: render each PDF page to a Bitmap, then pass it to Analyze.
foreach (Bitmap pageBitmap in pdfRenderer.RenderPages("document.pdf"))
{
    using (pageBitmap)
    {
        _barcodeXpress.reader.BarcodeTypes = Enum.GetValues(typeof(BarcodeType));
        Result[] barcodes = _barcodeXpress.reader.Analyze(pageBitmap);
        // ... collect results
    }
}
// Requires a separate PDF library (not shown — varies by team choice)
// Pattern: render each PDF page to a Bitmap, then pass it to Analyze.
foreach (Bitmap pageBitmap in pdfRenderer.RenderPages("document.pdf"))
{
    using (pageBitmap)
    {
        _barcodeXpress.reader.BarcodeTypes = Enum.GetValues(typeof(BarcodeType));
        Result[] barcodes = _barcodeXpress.reader.Analyze(pageBitmap);
        // ... collect results
    }
}
Imports System
Imports System.Drawing

' Requires a separate PDF library (not shown — varies by team choice)
' Pattern: render each PDF page to a Bitmap, then pass it to Analyze.
For Each pageBitmap As Bitmap In pdfRenderer.RenderPages("document.pdf")
    Using pageBitmap
        _barcodeXpress.reader.BarcodeTypes = [Enum].GetValues(GetType(BarcodeType))
        Dim barcodes As Result() = _barcodeXpress.reader.Analyze(pageBitmap)
        ' ... collect results
    End Using
Next
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

// One call — no rendering step, no external dependency
var results = BarcodeReader.Read("document.pdf");

foreach (var barcode in results)
{
    Console.WriteLine($"Page {barcode.PageNumber}: [{barcode.Format}] {barcode.Value}");
}
using IronBarCode;

// One call — no rendering step, no external dependency
var results = BarcodeReader.Read("document.pdf");

foreach (var barcode in results)
{
    Console.WriteLine($"Page {barcode.PageNumber}: [{barcode.Format}] {barcode.Value}");
}
Imports IronBarCode

' One call — no rendering step, no external dependency
Dim results = BarcodeReader.Read("document.pdf")

For Each barcode In results
    Console.WriteLine($"Page {barcode.PageNumber}: [{barcode.Format}] {barcode.Value}")
Next
$vbLabelText   $csharpLabel

如果itext7或任何其他PDF库仅为支持BarcodeXpress读取工作流而添加,则在迁移后可以删除它。 查看 IronBarcode PDF 阅读指南以获取附加选项,包括页面范围选择。

条形码生成

BarcodeXpress 方法:

using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public void GenerateBarcode(string data, string outputPath)
{
    _barcodeXpress.writer.BarcodeType = BarcodeType.Code128Barcode;
    _barcodeXpress.writer.BarcodeValue = data;

    // CreateBitmap returns a System.Drawing.Bitmap; persist via Bitmap.Save.
    using Bitmap bitmap = _barcodeXpress.writer.CreateBitmap();
    bitmap.Save(outputPath);
}
using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public void GenerateBarcode(string data, string outputPath)
{
    _barcodeXpress.writer.BarcodeType = BarcodeType.Code128Barcode;
    _barcodeXpress.writer.BarcodeValue = data;

    // CreateBitmap returns a System.Drawing.Bitmap; persist via Bitmap.Save.
    using Bitmap bitmap = _barcodeXpress.writer.CreateBitmap();
    bitmap.Save(outputPath);
}
Imports System.Drawing
Imports Accusoft.BarcodeXpressSdk

Public Sub GenerateBarcode(data As String, outputPath As String)
    _barcodeXpress.writer.BarcodeType = BarcodeType.Code128Barcode
    _barcodeXpress.writer.BarcodeValue = data

    ' CreateBitmap returns a System.Drawing.Bitmap; persist via Bitmap.Save.
    Using bitmap As Bitmap = _barcodeXpress.writer.CreateBitmap()
        bitmap.Save(outputPath)
    End Using
End Sub
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

public void GenerateBarcode(string data, string outputPath)
{
    BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
        .ResizeTo(400, 100)
        .SaveAsPng(outputPath);
}
using IronBarCode;

public void GenerateBarcode(string data, string outputPath)
{
    BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
        .ResizeTo(400, 100)
        .SaveAsPng(outputPath);
}
Imports IronBarCode

Public Sub GenerateBarcode(data As String, outputPath As String)
    BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128) _
        .ResizeTo(400, 100) _
        .SaveAsPng(outputPath)
End Sub
$vbLabelText   $csharpLabel

流畅链取代了属性赋值、Bitmap.Save步骤。要获取作为二进制数据的条码以存储在数据库中或从API返回:

byte[] pngBytes = BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
    .ToPngBinaryData();
byte[] pngBytes = BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
    .ToPngBinaryData();
Dim pngBytes As Byte() = BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128).ToPngBinaryData()
$vbLabelText   $csharpLabel

二维码生成

BarcodeXpress 方法:

_barcodeXpress.writer.BarcodeType = BarcodeType.QRCodeBarcode;
_barcodeXpress.writer.BarcodeValue = data;

using Bitmap bitmap = _barcodeXpress.writer.CreateBitmap();
bitmap.Save("qr.png");
// Logo overlay required manual GDI+ drawing on the returned Bitmap
_barcodeXpress.writer.BarcodeType = BarcodeType.QRCodeBarcode;
_barcodeXpress.writer.BarcodeValue = data;

using Bitmap bitmap = _barcodeXpress.writer.CreateBitmap();
bitmap.Save("qr.png");
// Logo overlay required manual GDI+ drawing on the returned Bitmap
Imports System.Drawing

_barcodeXpress.writer.BarcodeType = BarcodeType.QRCodeBarcode
_barcodeXpress.writer.BarcodeValue = data

Using bitmap As Bitmap = _barcodeXpress.writer.CreateBitmap()
    bitmap.Save("qr.png")
    ' Logo overlay required manual GDI+ drawing on the returned Bitmap
End Using
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;
using IronSoftware.Drawing;

// Simple QR
QRCodeWriter.CreateQrCode("https://example.com", 500)
    .SaveAsPng("qr.png");

// With branded logo
QRCodeWriter.CreateQrCode("https://example.com", 500)
    .AddBrandLogo("logo.png")
    .SaveAsPng("qr-branded.png");

// With high error correction (for logo overlays)
QRCodeWriter.CreateQrCode(
    "https://example.com",
    500,
    QRCodeWriter.QrErrorCorrectionLevel.Highest)
    .AddBrandLogo("logo.png")
    .SaveAsPng("qr-branded-high-ecc.png");

// Colored QR code
QRCodeWriter.CreateQrCode("https://example.com", 300)
    .ChangeBarCodeColor(Color.DarkBlue)
    .SaveAsPng("qr-colored.png");
using IronBarCode;
using IronSoftware.Drawing;

// Simple QR
QRCodeWriter.CreateQrCode("https://example.com", 500)
    .SaveAsPng("qr.png");

// With branded logo
QRCodeWriter.CreateQrCode("https://example.com", 500)
    .AddBrandLogo("logo.png")
    .SaveAsPng("qr-branded.png");

// With high error correction (for logo overlays)
QRCodeWriter.CreateQrCode(
    "https://example.com",
    500,
    QRCodeWriter.QrErrorCorrectionLevel.Highest)
    .AddBrandLogo("logo.png")
    .SaveAsPng("qr-branded-high-ecc.png");

// Colored QR code
QRCodeWriter.CreateQrCode("https://example.com", 300)
    .ChangeBarCodeColor(Color.DarkBlue)
    .SaveAsPng("qr-colored.png");
Imports IronBarCode
Imports IronSoftware.Drawing

' Simple QR
QRCodeWriter.CreateQrCode("https://example.com", 500) _
    .SaveAsPng("qr.png")

' With branded logo
QRCodeWriter.CreateQrCode("https://example.com", 500) _
    .AddBrandLogo("logo.png") _
    .SaveAsPng("qr-branded.png")

' With high error correction (for logo overlays)
QRCodeWriter.CreateQrCode( _
    "https://example.com", _
    500, _
    QRCodeWriter.QrErrorCorrectionLevel.Highest) _
    .AddBrandLogo("logo.png") _
    .SaveAsPng("qr-branded-high-ecc.png")

' Colored QR code
QRCodeWriter.CreateQrCode("https://example.com", 300) _
    .ChangeBarCodeColor(Color.DarkBlue) _
    .SaveAsPng("qr-colored.png")
$vbLabelText   $csharpLabel

流畅的 API 内置了徽标嵌入、纠错级别和颜色自定义功能。 BarcodeXpress 的这些功能在初始文件写入后需要手动进行 GDI+ 绘图。 有关更多 QR 代码选项,请参阅 QR 代码生成指南

Accusoft BarcodeXpressAPI 到IronBarcode映射参考

Accusoft BarcodeXpress IronBarcode
new BarcodeXpress(".") 静态方法——无需实例
Licensing.SetSolutionName("...") IronBarCode.License.LicenseKey = "key"
Licensing.SetSolutionKey(a, b, c, d) (removed — not needed)
Licensing.SetOEMLicenseKey(string) (removed — no OEM/runtime key concept)
new Bitmap(path) + reader.Analyze(bitmap) BarcodeReader.Read(path)
reader.BarcodeTypes = new[] { BarcodeType.Code128Barcode, ... } (removed — auto-detection handles all formats)
result.BarcodeValue result.Value
result.BarcodeType result.Format
writer.BarcodeType = BarcodeType.Code128Barcode BarcodeWriter.CreateBarcode("data", BarcodeEncoding.Code128)
writer.BarcodeValue = "data" (first argument to CreateBarcode)
writer.CreateBitmap() + bitmap.Save(path) .SaveAsPng(path)
writer.BarcodeType = BarcodeType.QRCodeBarcode QRCodeWriter.CreateQrCode(data, size)
40 ppm 标准限值 任何层级均无吞吐量限制

常见迁移问题和解决方案

问题 1:属性名称编译错误

BarcodeXpress:结果对象公开BarcodeValueBarcodeType,在IronBarcode中不存在。

解决方案:在构建之前,对整个解决方案运行查找和替换操作:

grep -r "\.BarcodeValue" --include="*.cs" .
grep -r "\.BarcodeType" --include="*.cs" .
grep -r "\.BarcodeValue" --include="*.cs" .
grep -r "\.BarcodeType" --include="*.cs" .
SHELL

在所有找到的文件中用result.BarcodeType

问题2:孤立的许可证配置调用

BarcodeXpress: SetSolutionKeySetOEMLicenseKey 的调用 — 加上检测到解码输出中的" UNLICENSED accusoft.com "水印的任何自定义断言 — 广泛存在于许多代码库中,作为防止水印输出故障模式的防御措施。

解决方案: 定位并删除所有此类调用位置 —— IronBarcode中没有等效的状态。 许可证密钥要么有效要么无效,如果无效,则试用限制统一适用,而不是单独降低解码值:

grep -r "SetOEMLicenseKey" --include="*.cs" .
grep -r "SetSolutionName" --include="*.cs" .
grep -r "SetSolutionKey" --include="*.cs" .
grep -r "UNLICENSED accusoft" --include="*.cs" .
grep -r "SetOEMLicenseKey" --include="*.cs" .
grep -r "SetSolutionName" --include="*.cs" .
grep -r "SetSolutionKey" --include="*.cs" .
grep -r "UNLICENSED accusoft" --include="*.cs" .
SHELL

所有这些呼叫站点都可以删除。

问题 3:Docker 许可证文件挂载到环境变量

BarcodeXpress: Docker 部署通常使用COPY或卷装指令将BarcodeXpress许可证配置文件安装到容器中的已知路径。

解决方案:删除配置文件副本,并替换为环境变量:

# Remove this
COPY accusoft-license.lic /app/license/

# Add this
ENV IRONBARCODE_LICENSE=YOUR-LICENSE-KEY

应用程序启动时:

IronBarCode.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE");
IronBarCode.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE");
Imports System

IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE")
$vbLabelText   $csharpLabel

在 Kubernetes 中,许可证密钥会成为 pod 规范中的一个秘密引用:

env:
  - name: IRONBARCODE_LICENSE
    valueFrom:
      secretKeyRef:
        name: ironbarcode-secrets
        key: license-key
env:
  - name: IRONBARCODE_LICENSE
    valueFrom:
      secretKeyRef:
        name: ironbarcode-secrets
        key: license-key
YAML

问题 4:速率限制处理代码

BarcodeXpress:在标准版 40-PPM 上限下处理大批量文件的团队通常会添加代码,以便在处理文档组之间进行休眠、跟踪每分钟计数器或引入延迟,以保持在限制范围内。

解决方案:移除所有限速代码。 定位方法:

grep -r "40\|PPM\|pagesPerMinute\|minuteStart" --include="*.cs" .
grep -r "40\|PPM\|pagesPerMinute\|minuteStart" --include="*.cs" .
SHELL

IronBarcode没有吞吐量上限——您可以根据自身基础设施支持的速率进行处理。

问题 5:线程安全——实例池移除

BarcodeXpress: 支持并发处理的代码库通常维护一个ThreadLocal<BarcodeXpress>模式来隔离每个线程的有状态读取器。

解决方案:完全移除连接池逻辑。 IronBarcode的BarcodeWriter.CreateBarcode是无状态的静态方法。 来自任意数量线程的并发调用不会相互干扰。

Accusoft BarcodeXpress迁移清单

迁移前任务

在进行任何代码更改之前,请审核代码库,以确定所有 BarcodeXpress 的使用情况:

grep -r "BarcodeXpress" --include="*.cs" .
grep -r "Accusoft" --include="*.cs" .
grep -r "SetSolutionName" --include="*.cs" .
grep -r "SetSolutionKey" --include="*.cs" .
grep -r "SetOEMLicenseKey" --include="*.cs" .
grep -r "reader\.Analyze" --include="*.cs" .
grep -r "writer\.CreateBitmap" --include="*.cs" .
grep -r "\.BarcodeValue" --include="*.cs" .
grep -r "\.BarcodeType" --include="*.cs" .
grep -r "BarcodeType\." --include="*.cs" .
grep -r "BarcodeXpress" --include="*.cs" .
grep -r "Accusoft" --include="*.cs" .
grep -r "SetSolutionName" --include="*.cs" .
grep -r "SetSolutionKey" --include="*.cs" .
grep -r "SetOEMLicenseKey" --include="*.cs" .
grep -r "reader\.Analyze" --include="*.cs" .
grep -r "writer\.CreateBitmap" --include="*.cs" .
grep -r "\.BarcodeValue" --include="*.cs" .
grep -r "\.BarcodeType" --include="*.cs" .
grep -r "BarcodeType\." --include="*.cs" .
SHELL
  • 记录在BarcodeTypes赋值中明确列出的条码格式 — 这些都会在IronBarcode中自动检测。
  • 找出所有可以移除的速率限制处理代码
  • 找出所有仅为支持 BarcodeXpress 读取而添加的 PDF 渲染库——这些库也可以移除。
  • 获取您的IronBarcode许可证密钥并将其添加到您的密钥管理器中。

代码更新任务

  1. 从所有Accusoft.BarcodeXpress.NetCore
  2. 向所有需要条码功能的IronBarcode
  3. 在所有文件中用using Accusoft.BarcodeXpressSdk;
  4. 在应用程序启动时添加IronBarCode.License.LicenseKey = ...
  5. 删除所有BarcodeXpress构造函数调用和实例字段
  6. 删除所有SetOEMLicenseKey调用
  7. 删除任何扫描解码输出中" UNLICENSED accusoft.com "水印的自定义断言
  8. new Bitmap(path) + BarcodeReader.Read(path)
  9. 删除所有reader.BarcodeTypes = ...赋值
  10. result.BarcodeValue
  11. result.BarcodeType
  12. writer.CreateBitmap() + bitmap.Save(path)
  13. 移除速率限制节流代码
  14. 如果存在,请移除 PDF 渲染中间代码。
  15. 删除实例池或BarcodeXpress实例的ThreadLocal模式
  16. 从 Dockerfile 和 docker-compose 文件中移除许可证文件挂载
  17. IRONBARCODE_LICENSE环境变量添加到Docker和容器配置中
  18. 更新 Kubernetes 密钥和 Pod 规范
  19. 更新CI/CD管道密钥 — 删除ACCUSOFT_RUNTIME_KEY; 添加IRONBARCODE_LICENSE

迁移后测试

  • 构建解决方案——修复重命名属性后遗留的任何编译错误
  • 对所有条形码读取操作运行单元测试
  • 对所有条形码生成操作运行单元测试
  • 如适用,请使用 PDF 输入进行测试
  • 运行批量处理测试以确认不存在吞吐量限制行为
  • 部署到测试环境并验证许可证密钥是否能从环境变量中正确解析。

迁移到IronBarcode的主要优势

消除两键许可证复杂性:SetOEMLicenseKey设置完全消失。 一个密钥覆盖从开发到生产的每个环境,并且试用模式返回完整的解码值(而不是在每个值上加盖"UNLICENSED accusoft.com"),因此可以在实际文档上进行预购基准测试。

无最低运行时许可证购买要求: BarcodeXpress 要求任何生产部署至少需要五个运行时许可证。 IronBarcode没有运行时许可概念——一个永久密钥即可覆盖其级别内的任何数量的生产部署。

吞吐量无上限:标准版 40-PPM 的上限以及任何为保持在上限内而编写的速率限制代码都可以移除。IronBarcode的处理速度取决于底层硬件和网络支持,在任何定价层级上都没有软件限制的处理速度上限。

原生PDF读取:BarcodeReader.Read("document.pdf")直接处理PDF文件,返回带有页码、格式、值和置信度分数的每页结果。 任何仅为支持 BarcodeXpress 而添加的 PDF 渲染库都可以移除,从而减少依赖项和许可成本。

无状态线程安全:BarcodeWriter.CreateBarcode是无状态的静态方法。 实例池、ThreadLocal模式和每线程初始化块都可以删除。 使用Parallel.ForEach的并发处理不需要结构更改,仅需移除线程的变通办法。

简化容器部署: Docker 和 Kubernetes 部署使用单个环境变量进行许可证配置。 许可证文件分发、许可证服务器基础设施和配置文件挂载全部取消。

常见问题解答

我为什么要从 Accusoft BarcodeXpress 迁移到 IronBarcode?

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

如何用 IronBarcode 替换 Accusoft BarcodeXpress API 调用?

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

从 Accusoft BarcodeXpress 迁移到 IronBarcode 时,需要进行多少代码更改?

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

迁移过程中是否需要同时保留 Accusoft BarcodeXpress 和 IronBarcode 这两个软件?

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

IronBarcode 的 NuGet 包名称是什么?

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

与 Accusoft BarcodeXpress 相比,IronBarcode 如何简化 Docker 部署?

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

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

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

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

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

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

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

从 Accusoft BarcodeXpress 迁移到 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 小时在线。
聊天
电子邮件
打电话给我