跳至页脚内容
视频

如何用 C# | IronPDF 编写 Unicode 和国际语言条形码

从ZXing.Net迁移到IronBarcode

本指南涵盖了从 ZXing .NET到IronBarcode的完整迁移过程,适用于读取和生成条形码的.NET应用程序。 涉及到移除ZXing.Net的核心包和绑定包,消除PdfiumViewer中的变通方法,并将每个有状态的BarcodeReader实例化替换为IronBarcode的静态API。 每个部分都包含从 ZXing .NET集成中最常见的模式中提取的修改前后的代码。

为什么要从 ZXing .NET迁移?

十多年来,ZXing .NET作为一款免费的 Apache 2.0 条形码库,一直为.NET社区提供优质服务。 然而,随着应用程序规模或复杂性的增长,一些架构限制会转化为运营成本。

线程安全所有权:ZXing.Net的BarcodeReader是一个有状态的对象。 该库自身的文档明确指出,实例不能在线程间共享。 实际上,这意味着每个并发处理路径——每个处理并发请求的控制器操作、并行批处理中的每个任务——都必须分配、配置和丢弃自己的读取器。 随着请求量的增加,这种分配模式会产生可衡量的内存压力。 这个ThreadLocal<BarcodeReader>替代方案减少了分配频率,但引入了自身的处置复杂性。 在这两种情况下,并发情况下的正确性都是调用者的问题,而不是库提供的保证。

格式规范风险:ZXing.Net需要在每次解码操作前填充reader.Options.PossibleFormats。 在该列表中不存在格式的条码返回空——没有异常、没有警告、没有表明条码存在但未识别的迹象。 对于从外部合作伙伴接收文档的应用程序,这种静默丢失行为是一个可靠性风险:误发的订单、遗漏的患者签到记录或从未写入的审计条目都可能源于为先前要求配置的格式列表且从未更新。

PDF 处理缺陷: ZXing .NET仅读取位图。 当源文档是 PDF 文件(例如发票、装运清单、合规证书)时,调用者必须集成一个单独的 PDF 渲染库(最常见的是 PdfiumViewer),实现页面枚举循环,配置 DPI,管理临时文件,并在成功和失败路径中处理清理工作。 每个集成需要 30 到 50 行基础架构代码,其唯一目的是将 ZXing .NET无法读取的内容(PDF)转换为它可以读取的内容(位图)。 该基础设施有其自身的依赖关系、自身的部署要求和自身的故障模式。

平台绑定碎片化: ZXing.Net 的图像加载功能分散在特定于平台的绑定包中。 Windows绑定使用System.Drawing.Bitmap; 跨平台绑定使用不同泛型类型参数与using指令。在Windows上开始并后来在Linux上容器化的项目必须更改其NuGet引用和图像加载代码。 同一操作的两条代码路径会增加出错的面积,并增加扫描层未来更改的阻力。

基本问题

ZXing .NET架构最清晰的例证就是单线程调用和并发调用之间的差距。 在 ZXing .NET中,并发处理需要为每个并行操作创建一个完整的读取器对象:

// ZXing.Net: full reader instantiation and configuration on every parallel task
Parallel.ForEach(files, file =>
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    };

    using var bitmap = new Bitmap(file);
    var result = reader.Decode(bitmap);
    if (result != null)
        processed[file] = result.Text;
});
// ZXing.Net: full reader instantiation and configuration on every parallel task
Parallel.ForEach(files, file =>
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    };

    using var bitmap = new Bitmap(file);
    var result = reader.Decode(bitmap);
    if (result != null)
        processed[file] = result.Text;
});
Imports ZXing
Imports System.Drawing
Imports System.Threading.Tasks

Parallel.ForEach(files, Sub(file)
    Dim reader As New BarcodeReader()
    reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    }

    Using bitmap As New Bitmap(file)
        Dim result = reader.Decode(bitmap)
        If result IsNot Nothing Then
            processed(file) = result.Text
        End If
    End Using
End Sub)
$vbLabelText   $csharpLabel

IronBarcode会彻底移除该对象。 无论是在一个线程上运行还是在一百个线程上运行,静态调用都是一样的:

// IronBarcode: static call, same code for single-threaded and concurrent use
Parallel.ForEach(files, file =>
{
    var result = BarcodeReader.Read(file).FirstOrDefault();
    if (result != null)
        processed[file] = result.Value;
});
// IronBarcode: static call, same code for single-threaded and concurrent use
Parallel.ForEach(files, file =>
{
    var result = BarcodeReader.Read(file).FirstOrDefault();
    if (result != null)
        processed[file] = result.Value;
});
Imports IronBarCode
Imports System.Threading.Tasks

Parallel.ForEach(files, Sub(file)
    Dim result = BarcodeReader.Read(file).FirstOrDefault()
    If result IsNot Nothing Then
        processed(file) = result.Value
    End If
End Sub)
$vbLabelText   $csharpLabel

IronBarcode与 ZXing .NET:功能对比

特征 ZXing.Net IronBarcode
执照 Apache 2.0(免费) 商业翻译
线程安全 非线程安全——每个线程都需要一个新的实例。 线程安全的静态 API
格式检测 手动 — 需要PossibleFormats列表 自动 — 50 多种格式
PDF阅读 否——需要 PdfiumViewer 或类似软件 原生应用 — 单方法调用
平台支持 每个平台使用单独的绑定包 单一软件包,适用于所有平台
每张图片包含多个条形码 是 — DecodeMultiple 是的—默认行为
条形码生成 返回Bitmap,需要手动保存 带有内置输出的流畅 API
支持二维码徽标
二维码颜色控制
条形码损坏恢复 TryHarder标志 基于机器学习的图像校正
Docker 额外依赖项 可能需要libgdiplus None
商业服务水平协议支持
需要NuGet包 2–3(核心 + 绑定 + 可选 ImageSharp) 1

快速入门

步骤 1:移除 ZXing .NET程序包

从项目中移除所有 ZXing .NET及相关软件包:

dotnet remove package ZXing.Net
dotnet remove package ZXing.Net.Bindings.Windows.Compatibility
dotnet remove package ZXing.Net.Bindings.ImageSharp
dotnet remove package PdfiumViewer
dotnet remove package ZXing.Net
dotnet remove package ZXing.Net.Bindings.Windows.Compatibility
dotnet remove package ZXing.Net.Bindings.ImageSharp
dotnet remove package PdfiumViewer
SHELL

如果将原生 PdfiumViewer 二进制文件作为单独的软件包安装:

dotnet remove package PdfiumViewer.Native.x64.v8-xfa
dotnet remove package PdfiumViewer.Native.x64.v8-xfa
SHELL

如果Dockerfile包含apt-get install -y libgdiplus - 为了通过Linux上的Windows绑定支持System.Drawing而添加 - 在迁移后可以移除该行。

步骤 2:安装IronBarcode

dotnet add package IronBarcode
dotnet add package IronBarcode
SHELL

无需额外的绑定包或平台特定依赖项。 同一个NuGet包可以在 Windows、Linux、macOS 和 Docker 容器中运行。 有关部署详情,请参阅IronBarcode Docker 和 Linux 设置指南,其中涵盖了确切的 Dockerfile 模式。

步骤 3:更新命名空间并初始化许可证

从所有使用条形码操作的文件中移除所有与 ZXing 相关的命名空间:

// Remove all of these:
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using ZXing.ImageSharp;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using PdfiumViewer;

// Add this single import:
using IronBarCode;
// Remove all of these:
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using ZXing.ImageSharp;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using PdfiumViewer;

// Add this single import:
using IronBarCode;
Imports IronBarCode
$vbLabelText   $csharpLabel

在应用程序启动时,在进行任何条形码操作之前,添加许可证初始化:

// Program.cs or Startup.cs — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
// Program.cs or Startup.cs — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";
' Program.vb or Startup.vb — initialise once at startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

许可证密钥是一个可以从环境变量、appsettings.json或密钥管理器中加载的纯字符串。 没有要查找的文件,也没有要配置的路径。

代码迁移示例

从图像中读取单个条形码

本示例取代了最常见的 ZXing .NET使用模式:实例化读取器、配置格式列表、加载位图和解码。

ZXing .NET方法:

using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;

public string ReadSingleBarcode(string imagePath)
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    };

    using var bitmap = new Bitmap(imagePath);
    var result = reader.Decode(bitmap);

    return result?.Text ?? string.Empty;
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;

public string ReadSingleBarcode(string imagePath)
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    };

    using var bitmap = new Bitmap(imagePath);
    var result = reader.Decode(bitmap);

    return result?.Text ?? string.Empty;
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Drawing

Public Function ReadSingleBarcode(imagePath As String) As String
    Dim reader = New BarcodeReader()
    reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.EAN_13
    }

    Using bitmap As New Bitmap(imagePath)
        Dim result = reader.Decode(bitmap)
        Return If(result?.Text, String.Empty)
    End Using
End Function
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

public string ReadSingleBarcode(string imagePath)
{
    var result = BarcodeReader.Read(imagePath).FirstOrDefault();
    return result?.Value ?? string.Empty;
}
using IronBarCode;

public string ReadSingleBarcode(string imagePath)
{
    var result = BarcodeReader.Read(imagePath).FirstOrDefault();
    return result?.Value ?? string.Empty;
}
Imports IronBarCode

Public Function ReadSingleBarcode(imagePath As String) As String
    Dim result = BarcodeReader.Read(imagePath).FirstOrDefault()
    Return If(result?.Value, String.Empty)
End Function
$vbLabelText   $csharpLabel

格式列表、using块都被移除。 IronBarcode直接接受文件路径,并自动检测所有支持的格式。 以前返回解码字符串的属性在ZXing.Net中是result.Text; 在IronBarcode中是result.Value

从图像中读取所有条形码

这个示例替换了DecodeMultiple,在ZXing.Net中需要一个详尽的格式列表以避免无声漏失。

ZXing .NET方法:

using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;

public List<string> ReadAllBarcodes(string imagePath)
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.CODE_39,
        BarcodeFormat.EAN_13,
        BarcodeFormat.EAN_8,
        BarcodeFormat.UPC_A,
        BarcodeFormat.DATA_MATRIX,
        BarcodeFormat.PDF_417
    };
    reader.Options.TryHarder = true;

    using var bitmap = new Bitmap(imagePath);
    var results = reader.DecodeMultiple(bitmap);

    return results?.Select(r => r.Text).ToList() ?? new List<string>();
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Drawing;

public List<string> ReadAllBarcodes(string imagePath)
{
    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.CODE_39,
        BarcodeFormat.EAN_13,
        BarcodeFormat.EAN_8,
        BarcodeFormat.UPC_A,
        BarcodeFormat.DATA_MATRIX,
        BarcodeFormat.PDF_417
    };
    reader.Options.TryHarder = true;

    using var bitmap = new Bitmap(imagePath);
    var results = reader.DecodeMultiple(bitmap);

    return results?.Select(r => r.Text).ToList() ?? new List<string>();
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Drawing

Public Function ReadAllBarcodes(imagePath As String) As List(Of String)
    Dim reader = New BarcodeReader()
    reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.CODE_39,
        BarcodeFormat.EAN_13,
        BarcodeFormat.EAN_8,
        BarcodeFormat.UPC_A,
        BarcodeFormat.DATA_MATRIX,
        BarcodeFormat.PDF_417
    }
    reader.Options.TryHarder = True

    Using bitmap As New Bitmap(imagePath)
        Dim results = reader.DecodeMultiple(bitmap)
        Return If(results?.Select(Function(r) r.Text).ToList(), New List(Of String)())
    End Using
End Function
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

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

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

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

BarcodeReader.Read始终返回一个集合,并且从不返回null,消除了对结果的null保护。 要调整准确性与速度的平衡,请参阅读取速度选项指南,该指南涵盖了ReadingSpeed枚举,而不缩小格式范围。

并发批处理

这个例子最直接地展示了线程安全性的差异。 ZXing .NET每次并行操作都需要一个新的读取器; 无论并发级别如何, IronBarcode都使用相同的静态调用。

ZXing .NET方法:

using ZXing;
using ZXing.Windows.Compatibility;
using System.Collections.Concurrent;
using System.Drawing;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
    var output = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(filePaths, new ParallelOptions { MaxDegreeOfParallelism = 4 }, file =>
    {
        // ZXing.Net is not thread-safe — a new reader is required per parallel operation
        var reader = new BarcodeReader();
        reader.Options.PossibleFormats = new List<BarcodeFormat>
        {
            BarcodeFormat.QR_CODE,
            BarcodeFormat.CODE_128
        };

        using var bitmap = new Bitmap(file);
        var result = reader.Decode(bitmap);
        if (result != null)
            output[file] = result.Text;
    });

    return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
using ZXing;
using ZXing.Windows.Compatibility;
using System.Collections.Concurrent;
using System.Drawing;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
    var output = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(filePaths, new ParallelOptions { MaxDegreeOfParallelism = 4 }, file =>
    {
        // ZXing.Net is not thread-safe — a new reader is required per parallel operation
        var reader = new BarcodeReader();
        reader.Options.PossibleFormats = new List<BarcodeFormat>
        {
            BarcodeFormat.QR_CODE,
            BarcodeFormat.CODE_128
        };

        using var bitmap = new Bitmap(file);
        var result = reader.Decode(bitmap);
        if (result != null)
            output[file] = result.Text;
    });

    return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports System.Collections.Concurrent
Imports System.Drawing

Public Function ProcessBatch(filePaths As IEnumerable(Of String)) As Dictionary(Of String, String)
    Dim output = New ConcurrentDictionary(Of String, String)()

    Parallel.ForEach(filePaths, New ParallelOptions With {.MaxDegreeOfParallelism = 4}, Sub(file)
        ' ZXing.Net is not thread-safe — a new reader is required per parallel operation
        Dim reader = New BarcodeReader()
        reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
            BarcodeFormat.QR_CODE,
            BarcodeFormat.CODE_128
        }

        Using bitmap As New Bitmap(file)
            Dim result = reader.Decode(bitmap)
            If result IsNot Nothing Then
                output(file) = result.Text
            End If
        End Using
    End Sub)

    Return output.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
End Function
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;
using System.Collections.Concurrent;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
    var output = new ConcurrentDictionary<string, string>();
    var options = new BarcodeReaderOptions { MaxParallelThreads = 4 };

    Parallel.ForEach(filePaths, file =>
    {
        var result = BarcodeReader.Read(file, options).FirstOrDefault();
        if (result != null)
            output[file] = result.Value;
    });

    return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
using IronBarCode;
using System.Collections.Concurrent;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> filePaths)
{
    var output = new ConcurrentDictionary<string, string>();
    var options = new BarcodeReaderOptions { MaxParallelThreads = 4 };

    Parallel.ForEach(filePaths, file =>
    {
        var result = BarcodeReader.Read(file, options).FirstOrDefault();
        if (result != null)
            output[file] = result.Value;
    });

    return output.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
Imports IronBarCode
Imports System.Collections.Concurrent

Public Function ProcessBatch(filePaths As IEnumerable(Of String)) As Dictionary(Of String, String)
    Dim output = New ConcurrentDictionary(Of String, String)()
    Dim options = New BarcodeReaderOptions With {.MaxParallelThreads = 4}

    Parallel.ForEach(filePaths, Sub(file)
        Dim result = BarcodeReader.Read(file, options).FirstOrDefault()
        If result IsNot Nothing Then
            output(file) = result.Value
        End If
    End Sub)

    Return output.ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
End Function
$vbLabelText   $csharpLabel

没有需要保护或隔离的读取器实例。 有关异步管道模式和线程数配置,请参阅异步和多线程条形码读取指南

从PDF文件中提取条形码

此示例替换PdfiumViewer渲染循环。如果现有集成使用Ghostscript或iText而不是PdfiumViewer,之前的代码块在细节上看起来不同,但在结构上是相同的:一个页面枚举循环将位图提供给ZXing.Net。

ZXing .NET方法:

using ZXing;
using ZXing.Windows.Compatibility;
using PdfiumViewer;
using System.Drawing;
using System.Drawing.Imaging;

public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
    var collected = new List<string>();

    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.PDF_417
    };

    using var document = PdfDocument.Load(pdfPath);
    for (int page = 0; page < document.PageCount; page++)
    {
        string temp = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png");
        try
        {
            using var rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi);
            rendered.Save(temp, ImageFormat.Png);

            using var bmp = new Bitmap(temp);
            var decoded = reader.DecodeMultiple(bmp);
            if (decoded != null)
                collected.AddRange(decoded.Select(d => d.Text));
        }
        finally
        {
            if (File.Exists(temp))
                File.Delete(temp);
        }
    }

    return collected;
}
using ZXing;
using ZXing.Windows.Compatibility;
using PdfiumViewer;
using System.Drawing;
using System.Drawing.Imaging;

public List<string> ExtractBarcodesFromPdf(string pdfPath)
{
    var collected = new List<string>();

    var reader = new BarcodeReader();
    reader.Options.PossibleFormats = new List<BarcodeFormat>
    {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.PDF_417
    };

    using var document = PdfDocument.Load(pdfPath);
    for (int page = 0; page < document.PageCount; page++)
    {
        string temp = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png");
        try
        {
            using var rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi);
            rendered.Save(temp, ImageFormat.Png);

            using var bmp = new Bitmap(temp);
            var decoded = reader.DecodeMultiple(bmp);
            if (decoded != null)
                collected.AddRange(decoded.Select(d => d.Text));
        }
        finally
        {
            if (File.Exists(temp))
                File.Delete(temp);
        }
    }

    return collected;
}
Imports ZXing
Imports ZXing.Windows.Compatibility
Imports PdfiumViewer
Imports System.Drawing
Imports System.Drawing.Imaging

Public Function ExtractBarcodesFromPdf(pdfPath As String) As List(Of String)
    Dim collected As New List(Of String)()

    Dim reader As New BarcodeReader()
    reader.Options.PossibleFormats = New List(Of BarcodeFormat) From {
        BarcodeFormat.QR_CODE,
        BarcodeFormat.CODE_128,
        BarcodeFormat.PDF_417
    }

    Using document = PdfDocument.Load(pdfPath)
        For page As Integer = 0 To document.PageCount - 1
            Dim temp As String = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.png")
            Try
                Using rendered = document.Render(page, 200, 200, PdfRenderFlags.CorrectFromDpi)
                    rendered.Save(temp, ImageFormat.Png)

                    Using bmp As New Bitmap(temp)
                        Dim decoded = reader.DecodeMultiple(bmp)
                        If decoded IsNot Nothing Then
                            collected.AddRange(decoded.Select(Function(d) d.Text))
                        End If
                    End Using
                End Using
            Finally
                If File.Exists(temp) Then
                    File.Delete(temp)
                End If
            End Try
        Next
    End Using

    Return collected
End Function
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

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

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

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

PdfiumViewer 依赖项、页面渲染循环、DPI 配置、临时文件创建和清理块均已移除。 IronBarcode可以直接从 PDF 文件中读取条形码,并自动处理所有页面。

生成条形码

ZXing.Net写入器返回一个System.Drawing.Imaging来保存。 IronBarcode返回一个带有内置输出方法的GeneratedBarcode

ZXing .NET方法:

using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using System.Drawing;
using System.Drawing.Imaging;

public void WriteCode128(string content, string outputPath)
{
    var writer = new BarcodeWriter
    {
        Format = BarcodeFormat.CODE_128,
        Options = new EncodingOptions
        {
            Width = 400,
            Height = 120,
            Margin = 10
        }
    };

    using var bitmap = writer.Write(content);
    bitmap.Save(outputPath, ImageFormat.Png);
}
using ZXing;
using ZXing.Common;
using ZXing.Windows.Compatibility;
using System.Drawing;
using System.Drawing.Imaging;

public void WriteCode128(string content, string outputPath)
{
    var writer = new BarcodeWriter
    {
        Format = BarcodeFormat.CODE_128,
        Options = new EncodingOptions
        {
            Width = 400,
            Height = 120,
            Margin = 10
        }
    };

    using var bitmap = writer.Write(content);
    bitmap.Save(outputPath, ImageFormat.Png);
}
Imports ZXing
Imports ZXing.Common
Imports ZXing.Windows.Compatibility
Imports System.Drawing
Imports System.Drawing.Imaging

Public Sub WriteCode128(content As String, outputPath As String)
    Dim writer = New BarcodeWriter With {
        .Format = BarcodeFormat.CODE_128,
        .Options = New EncodingOptions With {
            .Width = 400,
            .Height = 120,
            .Margin = 10
        }
    }

    Using bitmap = writer.Write(content)
        bitmap.Save(outputPath, ImageFormat.Png)
    End Using
End Sub
$vbLabelText   $csharpLabel

IronBarcode方法:

using IronBarCode;

public void WriteCode128(string content, string outputPath)
{
    BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128)
        .ResizeTo(400, 120)
        .SaveAsPng(outputPath);
}
using IronBarCode;

public void WriteCode128(string content, string outputPath)
{
    BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128)
        .ResizeTo(400, 120)
        .SaveAsPng(outputPath);
}
Imports IronBarCode

Public Sub WriteCode128(content As String, outputPath As String)
    BarcodeWriter.CreateBarcode(content, BarcodeEncoding.Code128) _
        .ResizeTo(400, 120) _
        .SaveAsPng(outputPath)
End Sub
$vbLabelText   $csharpLabel

如果需要二进制输出而不是保存到文件,可以在返回的MemoryStream管道。

ZXing .NET API 到IronBarcode映射参考

ZXing.Net IronBarcode 备注
new BarcodeReader() 静态 — 无实例 BarcodeReader.Read(...)是一个静态调用
reader.Options.PossibleFormats = new List<BarcodeFormat> { ... } 不需要 自动检测涵盖所有 50 多种格式
reader.Options.TryHarder = true Speed = ReadingSpeed.Balanced 通过BarcodeReaderOptions进行精度调整
reader.Decode(bitmap) BarcodeReader.Read(imagePath).FirstOrDefault() 传递文件路径 — 无需构建Bitmap
reader.DecodeMultiple(bitmap) BarcodeReader.Read(imagePath) 始终返回集合; never null
result.Text result.Value 物业已更名
result.BarcodeFormat result.Format 物业已更名
BarcodeFormat.QR_CODE BarcodeEncoding.QRCode 枚举命名规则变更
BarcodeFormat.CODE_128 BarcodeEncoding.Code128 枚举命名规则变更
BarcodeFormat.EAN_13 BarcodeEncoding.EAN13 枚举命名规则变更
BarcodeFormat.DATA_MATRIX BarcodeEncoding.DataMatrix 枚举命名规则变更
BarcodeFormat.PDF_417 BarcodeEncoding.PDF417 枚举命名规则变更
new BarcodeWriter { Format = ..., Options = new EncodingOptions { ... }|BarcodeWriter.CreateBarcode(data, encoding)` 静态工厂,无选项对象
Bitmap .SaveAsPng(path) / .ToPngBinaryData() 内置输出在GeneratedBarcode
EncodingOptions { Width, Height } .ResizeTo(width, height) 流畅尺寸测量法
不支持 PDF BarcodeReader.Read("file.pdf") 原生支持 PDF,所有页面

常见迁移问题和解决方案

问题 1:条形码读取器实例化模式

ZXing.Net:调用者创建result.Text

解决方法:完全移除实例化。 将整个模式替换为静态调用:

// Before: reader creation + format config + bitmap + decode + result.Text
// After:
var result = BarcodeReader.Read(imagePath).FirstOrDefault();
var value = result?.Value ?? string.Empty;
// Before: reader creation + format config + bitmap + decode + result.Text
// After:
var result = BarcodeReader.Read(imagePath).FirstOrDefault();
var value = result?.Value ?? string.Empty;
' Before: reader creation + format config + bitmap + decode + result.Text
' After:
Dim result = BarcodeReader.Read(imagePath).FirstOrDefault()
Dim value = If(result?.Value, String.Empty)
$vbLabelText   $csharpLabel

在代码库中搜索new BarcodeReader()以找到每个实例。 每个代码都被删除了,而不是重构了。

问题 2:移除 PossibleFormats 块

ZXing .NET:每个解码调用之前都会有 reader.Options.PossibleFormats = new List { ... }`赋值。 这些清单通常很长,而且是针对特定项目的。

解决方案:完整删除每个PossibleFormats赋值块。 IronBarcode可自动检测格式; 不接受也不要求任何格式的列表。 如果BarcodeReaderOptions对象。

问题 3:绑定包清理

ZXing.Net:使用System.Drawing.Bitmap作为输入类型。 使用SixLabors.ImageSharp.Image<Rgba32>。 移除结合包后,两种模式都会失效。

解决方案:移除两个绑定包并替换所有图像加载代码。 IronBarcode的Uri — 无需构建Image<t>。 其余仅为using System.Drawing;导入也可以删除。

问题 4:将 result.Text 转换为 result.Value

ZXing.Net:解码的条码值通过result.Text访问。 条码格式通过result.BarcodeFormat访问。

解决方案:在整个代码库中将result.Format。 两个更改都是简单的属性重命名,没有行为上的差异。

ZXing .NET迁移检查清单

迁移前任务

在进行任何更改之前,请审核代码库,找出所有对 ZXing .NET 的引用:

grep -r "using ZXing" --include="*.cs" .
grep -r "new BarcodeReader" --include="*.cs" .
grep -r "PossibleFormats" --include="*.cs" .
grep -r "BarcodeFormat\." --include="*.cs" .
grep -r "reader\.Decode\|reader\.DecodeMultiple" --include="*.cs" .
grep -r "result\.Text\|result\.BarcodeFormat" --include="*.cs" .
grep -r "new BarcodeWriter\|writer\.Write\|EncodingOptions" --include="*.cs" .
grep -r "PdfiumViewer\|PdfDocument\.Load" --include="*.cs" .
grep -r "using System\.Drawing" --include="*.cs" .
grep -r "using ZXing" --include="*.cs" .
grep -r "new BarcodeReader" --include="*.cs" .
grep -r "PossibleFormats" --include="*.cs" .
grep -r "BarcodeFormat\." --include="*.cs" .
grep -r "reader\.Decode\|reader\.DecodeMultiple" --include="*.cs" .
grep -r "result\.Text\|result\.BarcodeFormat" --include="*.cs" .
grep -r "new BarcodeWriter\|writer\.Write\|EncodingOptions" --include="*.cs" .
grep -r "PdfiumViewer\|PdfDocument\.Load" --include="*.cs" .
grep -r "using System\.Drawing" --include="*.cs" .
SHELL

记录哪些文件引用ZXing绑定包(Windows对比ImageSharp)以及System.Drawing.Bitmap仅用于ZXing输入的地方。 检查存在的Dockerfile中libgdiplus的安装。

代码更新任务

  1. 移除PdfiumViewer NuGet包
  2. 安装IronBarcode NuGet包
  3. IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";添加到应用程序启动
  4. using SixLabors.ImageSharp</em>导入
  5. 移除每个new BarcodeReader()实例化
  6. 删除每个reader.Options.PossibleFormats = ...
  7. BarcodeReader.Read(imagePath).FirstOrDefault()
  8. BarcodeReader.Read(imagePath)
  9. result.Value
  10. result.Format
  11. 更新BarcodeEncoding.X等效项
  12. 替换 new BarcodeWriter { Format = ..., Options = new EncodingOptions { ... }withBarcodeWriter.CreateBarcode(data, encoding).ResizeTo(w, h)`
  13. writer.Write(data) + .ToPngBinaryData()
  14. 移除所有用于ZXing.Net位图加载的using System.Drawing;导入
  15. 移除所有作为 PDF 变通方案实现的 PdfiumViewer 页面渲染循环。
  16. 从Dockerfile中移除System.Drawing而添加的

迁移后测试

  • 验证应用程序之前配置的每种条形码格式是否都能被成功检测到。
  • 测试包含以前被排除在PossibleFormats列表之外的条码格式的图像,以确认自动检测可以将其拾取
  • 在负载下运行并发处理路径,并确认不存在竞态条件或空结果。
  • 如果应用程序通过 PdfiumViewer 处理 PDF 文件,请提供相同的 PDF 输入文件并确认条形码值是否匹配。
  • 确认生成的条形码(Code 128、QR码等)输出格式和尺寸正确。
  • 在Linux或Docker部署中,确认图像读取和PDF读取在没有libgdiplus的情况下正常工作
  • 运行完整的测试Suite,并将输出结果与迁移前的基线进行比较。

迁移到IronBarcode的主要优势

消除线程安全负担:IronBarcode的静态 API 完全消除了每个线程的实例模式。 没有需要实例化的读取器,没有每个线程需要配置的格式列表,也没有需要管理的ThreadLocal池。 同一个调用在单线程和高并发环境中都是正确的,并发正确性由库提供,而不是委托给每个调用者。

自动格式检测:移除PossibleFormats列表消除了当文档包含开发过程中未预期的条码格式时导致无声漏失失败的类别。 处理来自外部合作伙伴的文档或在不断发展的条形码标准下运行的应用程序,不再需要维护格式列表即可保持可靠性。

原生 PDF 处理: PdfiumViewer 渲染循环(包括页面枚举、DPI 配置、临时文件生命周期和清理代码)被完全移除。 以前需要两个库(ZXing .NET和 PDF 渲染器)才能处理 PDF 条形码的应用程序现在只需一个库即可。 减少已部署的依赖项,简化了构建和部署过程。

单一跨平台软件包:消除了 Windows 和 Linux 部署之间绑定软件包的区别。 相同的BarcodeReader.Read(path)调用在所有目标平台上编译并表现一致,消除了在图像加载代码中使用平台条件的需要,并简化了跨平台开发和容器化工作流程。

减少基础设施代码:迁移最重要的结果是移除了周围的基础设施——位图加载块、格式列表、PdfiumViewer 渲染循环、ThreadLocal 池——这些基础设施存在于 ZXing .NET集成中,并非为了执行条形码工作,而是为了满足库的架构要求。 迁移后保留下来的只有条形码逻辑本身。 有关检测率和扫描场景的更多背景信息,请参阅ZXing .NET与IronBarcode扫描器对比分析。

请注意Ghostscript, PDFium, ZXing.NET, iText均为其各自所有者的注册商标。 本网站与Artifex Software、Chromium Project、Google、ZXing.NET或iText Group无任何关联、认可或赞助。所有产品名称、徽标和品牌均为其各自所有者的财产。 比较仅供参考,反映撰写时公开可用的信息。

常见问题解答

我为什么要从 ZXing.Net 迁移到 IronBarcode?

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

如何用 IronBarcode 替换 ZXing.Net API 调用?

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

从 ZXing.Net 迁移到 IronBarcode 时,代码需要做多少改动?

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

迁移过程中是否需要同时保留 ZXing.Net 和 IronBarcode?

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

IronBarcode 的 NuGet 包名称是什么?

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

与 ZXing.Net 相比,IronBarcode 如何简化 Docker 部署?

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

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

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

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

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

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

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

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