news 2026/10/29 21:26:35

C#结合Zxing.dll实现高效二维码生成与解析实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#结合Zxing.dll实现高效二维码生成与解析实战

1. 为什么选择 ZXing.Net 来玩转 C# 二维码?

如果你正在用 C# 开发一个需要二维码功能的项目,比如一个会员卡系统、一个产品追溯应用,或者一个简单的扫码登录模块,你可能会在网上搜到好几种方案。有人推荐用 QRCoder,有人用 MessagingToolkit,但我自己折腾了这么多年,发现ZXing.Net这个库,对于大多数 C# 开发者来说,真的是一个“万金油”式的选择。

ZXing 本身是一个开源的、多语言的条形码/二维码处理库,它的 Java 版本非常有名。而 ZXing.Net 就是它的 .NET 移植版本。我选择它,主要看中三点:第一是功能全,生成和解析都支持,而且支持的码制非常多,从常见的 QR Code 到各种一维码如 Code 128、EAN-13 都能搞定。第二是社区活跃,遇到问题容易找到解决方案,毕竟背靠 Google 的开源项目。第三是轻量易用,一个 DLL 文件引用进来,几行核心代码就能跑起来,对新手非常友好。

你可能也见过一些纯 C# 实现的二维码库,它们可能更轻量。但 ZXing.Net 的优势在于其解码算法的鲁棒性。我实测过,对于一些拍摄角度有点倾斜、光线不太均匀或者边缘有点磨损的二维码图片,ZXing.Net 的解码成功率往往更高。这对于实际应用场景来说太重要了,毕竟用户拍出来的照片不可能张张都完美。

所以,无论你是想快速给产品信息页加个二维码,还是做一个复杂的扫码支付功能,从 ZXing.Net 入手,都能让你事半功倍。接下来,我就带你从零开始,一步步搞定它的集成、生成和解析,还会分享几个我实际项目中踩过的“坑”和优化技巧。

2. 5分钟快速上手:创建你的第一个二维码

理论说再多,不如动手试一下。我们先来一个最快的“Hello World”级别的二维码生成。这个过程非常简单,保证你五分钟内能看到效果。

2.1 准备你的开发环境

首先,你需要一个 C# 开发环境,我强烈推荐使用Visual Studio,社区版就完全够用。创建一个新的项目,类型选择“控制台应用”、“Windows 窗体应用”或者“WPF 应用”都可以,看你的需求。我这里以 Windows 窗体应用为例,因为有个界面看着更直观。

项目创建好后,我们怎么把 ZXing.Net 库引进来呢?现在最方便的方法就是使用NuGet 包管理器。在 Visual Studio 里,右键点击你的项目,选择“管理 NuGet 程序包”。在打开的浏览标签页里,搜索“ZXing.Net”。你会看到好几个相关的包,我们选择那个由 micjahn 维护的、下载量最高的ZXing.Net包进行安装。NuGet 会自动帮你处理好依赖,比手动去下载 DLL 再添加引用要省心得多。

安装完成后,你会在项目的“引用”里看到ZXing和ZXing.Net等相关引用。准备工作就算完成了,是不是很简单?

2.2 编写核心生成代码

现在,我们拖一个 Button 和一个 PictureBox 控件到窗体上。双击按钮,进入点击事件,开始写代码。生成二维码的核心对象是BarcodeWriter。我来写一个最基础的版本:

using ZXing; using ZXing.Common; using System.Drawing; private void btnGenerate_Click(object sender, EventArgs e) { // 1. 创建一个二维码写入器 BarcodeWriter writer = new BarcodeWriter(); // 2. 指定编码格式为 QR_CODE (二维码) writer.Format = BarcodeFormat.QR_CODE; // 3. 配置编码参数 EncodingOptions options = new EncodingOptions { Width = 300, // 图片宽度 Height = 300, // 图片高度 Margin = 1 // 二维码周围的空白边距 }; writer.Options = options; // 4. 将文本内容编码为二维码位图 Bitmap qrCodeBitmap = writer.Write("https://www.yourwebsite.com"); // 5. 显示在PictureBox中 pictureBox1.Image = qrCodeBitmap; // 6. (可选)保存到文件 qrCodeBitmap.Save(@"D:\MyFirstQRCode.png", System.Drawing.Imaging.ImageFormat.Png); }

把上面的代码复制进去,运行程序,点击按钮。如果一切顺利,你的 PictureBox 里就会显示一个黑白相间的二维码,用手机扫一下,就能跳转到指定的网址。这就是最基本的生成流程。writer.Write方法接受一个字符串,你可以把任何想编码的信息放进去,比如一段文本、一个联系方式(BEGIN:VCARD...)或者一个 Wi-Fi 配置(WIFI:S:SSID;T:WPA;P:Password;;)。

2.3 理解关键参数:大小、边距与容错

你可能已经注意到了代码里的Width、Height和Margin。这几个参数直接影响了二维码的外观和可读性。

宽度和高度决定了二维码图像的像素尺寸。并不是越大越好,你需要根据显示设备的物理尺寸和分辨率来权衡。比如在手机屏幕上显示,200x200 像素可能就够了,但如果要印刷在海报上,可能需要 1000x1000 甚至更高,以确保远距离也能扫描。

边距这个参数非常关键,它指的是二维码黑白区域外的一圈空白区域。我强烈建议你永远不要把它设为 0。很多扫码软件(尤其是微信)依赖这个空白区域来定位二维码。如果没有边距,当二维码紧贴着图片边缘时,很可能导致扫描失败。通常设置为 1 到 4 个模块(模块是二维码里的小黑点/白点单位)是比较安全的。

还有一个更重要的隐藏参数叫容错级别,它决定了二维码在部分污损或遮挡后依然能被正确识别的能力。ZXing.Net 支持四个级别:

  • L (Low): 约 7% 的码字可恢复。
  • M (Medium): 约 15% 的码字可恢复。
  • Q (Quartile): 约 25% 的码字可恢复。
  • H (High): 约 30% 的码字可恢复。

容错级别越高,二维码能承载的有效信息量就越少(因为有一部分空间用于存储冗余校验数据),生成的图案也会更复杂。但它的抗损能力更强。怎么设置呢?我们需要用到Hints字典:

writer.Options = new QrCodeEncodingOptions { Width = 300, Height = 300, Margin = 1, CharacterSet = "UTF-8" // 确保支持中文等字符 }; // 设置容错级别为 H writer.Options.Hints.Add(EncodeHintType.ERROR_CORRECTION, ZXing.QrCode.Internal.ErrorCorrectionLevel.H);

对于大多数应用,比如网址链接,使用M级别就足够了,它在容量和可靠性之间取得了很好的平衡。如果你的二维码可能会印在易磨损的表面,或者你打算在二维码中间放一个 Logo,那么建议使用H级别。

3. 进阶玩法:打造更专业的二维码

掌握了基础生成后,我们来看看如何让二维码变得更美观、更实用。毕竟一个黑白的方块有点太“技术宅”了,我们可以让它更好地融入产品设计。

3.1 自定义颜色与添加Logo

默认的黑白二维码虽然经典,但有时我们需要让它更符合品牌色调。BarcodeWriter可以通过设置Renderer属性来改变颜色:

private Bitmap GenerateColorfulQRCode(string content, Color darkColor, Color lightColor) { BarcodeWriter writer = new BarcodeWriter(); writer.Format = BarcodeFormat.QR_CODE; QrCodeEncodingOptions options = new QrCodeEncodingOptions { Width = 300, Height = 300, Margin = 2, CharacterSet = "UTF-8", ErrorCorrection = ZXing.QrCode.Internal.ErrorCorrectionLevel.H // 准备加Logo,用高容错 }; writer.Options = options; // 关键:使用 BitmapRenderer 并指定前景色和背景色 // 前景色对应二维码中的深色模块(通常是黑点),背景色对应浅色模块(通常是白点) writer.Renderer = new BitmapRenderer { Foreground = darkColor, // 例如 Color.FromArgb(0, 102, 204) 一种蓝色 Background = lightColor // 例如 Color.LightYellow }; return writer.Write(content); }

调用GenerateColorfulQRCode("Hello", Color.Blue, Color.LightGray),你就能得到一个蓝灰配色的二维码。这里有个坑要注意:颜色对比度一定要足够高。如果前景色和背景色太接近(比如深灰和浅灰),扫码相机可能无法区分,导致识别失败。最好用在线工具检查一下对比度。

接下来是更常见的需求:在二维码中央加入 Logo。这不仅能提升品牌辨识度,还能测试一下高容错级别是否真的有效。思路是先生成普通的二维码位图,然后在上面画一个 Logo 图片。

private Bitmap GenerateQRCodeWithLogo(string content, string logoPath) { // 1. 先生成基础二维码 BarcodeWriter writer = new BarcodeWriter(); writer.Format = BarcodeFormat.QR_CODE; writer.Options = new QrCodeEncodingOptions { Width = 400, // 做大一点,给Logo留空间 Height = 400, Margin = 1, CharacterSet = "UTF-8", ErrorCorrection = ZXing.QrCode.Internal.ErrorCorrectionLevel.H // 必须用高容错! }; Bitmap qrBitmap = writer.Write(content); // 2. 加载Logo图片 Bitmap logoBitmap = new Bitmap(logoPath); // 3. 计算Logo该画多大、画在哪(通常放在正中央) // Logo尺寸建议不超过二维码整体面积的15%-20% int logoSize = Math.Min(qrBitmap.Width, qrBitmap.Height) / 5; // 将Logo缩放到合适大小 Bitmap scaledLogo = new Bitmap(logoBitmap, new Size(logoSize, logoSize)); // 4. 计算绘制起点,使其居中 int pointX = (qrBitmap.Width - scaledLogo.Width) / 2; int pointY = (qrBitmap.Height - scaledLogo.Height) / 2; // 5. 创建一个Graphics对象,在二维码上绘制Logo using (Graphics g = Graphics.FromImage(qrBitmap)) { // 可选:给Logo加一个白色背景框,提高识别率 int padding = 3; g.FillRectangle(Brushes.White, pointX - padding, pointY - padding, scaledLogo.Width + 2 * padding, scaledLogo.Height + 2 * padding); g.DrawImage(scaledLogo, new Point(pointX, pointY)); } logoBitmap.Dispose(); scaledLogo.Dispose(); return qrBitmap; }

重要提示:添加 Logo 会遮挡部分二维码信息,因此前面生成二维码时必须使用较高的容错级别(推荐 H)。同时,Logo 不能太大,不能遮挡定位图形(就是二维码三个角上的“回”字形方块),否则会严重影响识别。

3.2 生成其他类型的条形码

ZXing.Net 的强大之处在于它不只生成 QR Code。如果你需要生成商品上的 EAN-13 码、仓库管理用的 Code 128 码,它都能轻松应对。只需要改变BarcodeWriter的Format属性。

private void GenerateBarcode(string code, BarcodeFormat format) { BarcodeWriter writer = new BarcodeWriter(); writer.Format = format; // 这里传入不同的格式 // 不同格式的条码对参数要求可能不同 EncodingOptions options = new EncodingOptions { Width = 300, Height = 100, // 一维码通常比较矮 Margin = 10, PureBarcode = true // 对于一维码,是否在下方显示数字文本 }; writer.Options = options; Bitmap barcodeBitmap = writer.Write(code); pictureBox1.Image = barcodeBitmap; }

你可以这样调用:

  • GenerateBarcode("690123456789", BarcodeFormat.EAN_13)生成一个 EAN-13 商品条码。
  • GenerateBarcode("ABC-123", BarcodeFormat.CODE_128)生成一个 Code 128 码。

需要注意的是,不同格式的条码对输入字符串有校验规则。比如 EAN-13 必须是 12 或 13 位数字(最后一位是校验位,库可能会自动计算)。如果传入非法字符,Write方法可能会抛出异常,所以在生产环境中要做好异常处理。

3.3 性能优化与大批量生成

如果你的应用需要动态、实时地生成大量二维码(比如为每一张电子票生成一个唯一的码),性能就需要考虑一下了。我遇到过在循环里频繁创建BarcodeWriter实例导致内存上涨的情况。

一个有效的优化方法是复用对象。如果生成参数(尺寸、边距、颜色等)固定,你可以将BarcodeWriter实例作为类的成员变量,只初始化一次。

public class QRCodeService { private readonly BarcodeWriter _barcodeWriter; public QRCodeService() { _barcodeWriter = new BarcodeWriter { Format = BarcodeFormat.QR_CODE, Options = new QrCodeEncodingOptions { Width = 250, Height = 250, Margin = 1, CharacterSet = "UTF-8" } }; // 如果颜色固定,也可以在这里设置 Renderer } public Bitmap GenerateQRCode(string content) { // 直接使用已初始化的 writer return _barcodeWriter.Write(content); } }

另外,对于 Web 应用,你可能会将生成的二维码以字节流形式直接输出到 HTTP 响应,而不是先保存成文件。这时可以使用MemoryStream:

public byte[] GenerateQRCodeBytes(string content) { using (var ms = new MemoryStream()) { Bitmap qrBitmap = _barcodeWriter.Write(content); qrBitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png); return ms.ToArray(); } } // 在 ASP.NET Core Controller 中可以这样用 // return File(qrBytes, "image/png");

4. 从图片到信息:二维码解析实战

生成二维码只是故事的一半。另一个核心功能是解析,也就是我们常说的“扫码”。用 ZXing.Net 实现解码,甚至比生成还要简单。

4.1 基础解码:读取二维码内容

解析的核心对象是BarcodeReader。假设我们有一个PictureBox控件显示了一张包含二维码的图片,我们要读取其中的信息:

using ZXing; using System.Drawing; private string DecodeQRCodeFromPictureBox() { if (pictureBox1.Image == null) { return "图片为空"; } // 1. 创建解码器 BarcodeReader reader = new BarcodeReader(); // 2. 设置解码选项(可选,但推荐) // 明确告诉解码器我们期望的是UTF-8编码的文本,可以提高中文等字符的识别正确率 reader.Options.CharacterSet = "UTF-8"; // 3. 执行解码 Result result = reader.Decode((Bitmap)pictureBox1.Image); // 4. 处理结果 if (result != null) { string decodedText = result.Text; BarcodeFormat format = result.BarcodeFormat; // 还可以知道扫到的是什么格式的码 return $"识别成功!\n格式:{format}\n内容:{decodedText}"; } else { return "未识别到二维码"; } }

这段代码已经可以处理很多情况了。reader.Decode方法会尝试分析图片,找出其中的条码或二维码,并返回一个Result对象。如果图片中没有码,或者图片质量太差无法识别,result就会是null。

4.2 处理复杂场景:模糊、倾斜与多码识别

在实际应用中,用户上传的图片可能来自手机拍摄,质量参差不齐。可能会模糊、有噪点、倾斜,甚至一张图里有多个二维码。ZXing.Net 提供了一些选项来应对这些挑战。

对于模糊或低对比度的图片,可以尝试调整解码器的尝试次数和尝试寻找的条码类型:

reader.Options.TryHarder = true; // 花费更多时间尝试解码 reader.Options.PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }; // 如果明确知道是二维码,只找这一种,可以加快速度

对于倾斜的二维码,BarcodeReader本身具备一定的自动校正能力。但如果倾斜非常严重,你可能需要先对图片进行预处理,比如旋转、透视变换,然后再交给 ZXing 解码。这涉及到更复杂的图像处理,通常可以结合System.Drawing的Graphics类来实现旋转。

一张图里有多个二维码怎么办?BarcodeReader有一个DecodeMultiple方法:

private List<string> DecodeMultipleQRCode(Bitmap sourceImage) { BarcodeReader reader = new BarcodeReader(); reader.Options.CharacterSet = "UTF-8"; // 关键:使用 DecodeMultiple 方法 Result[] results = reader.DecodeMultiple(sourceImage); List<string> decodedTexts = new List<string>(); if (results != null && results.Length > 0) { foreach (var result in results) { decodedTexts.Add(result.Text); } } return decodedTexts; // 返回所有识别到的内容列表 }

这个方法会返回一个Result数组。但要注意,处理多码图片对性能有影响,且并非所有复杂场景都能完美识别。

4.3 从摄像头实时解码

让程序从摄像头实时读取二维码,会大大提升用户体验,比如用于扫码登录、商品盘点等。这个功能稍微复杂一点,需要用到AForge.NET或OpenCVSharp等库来捕获摄像头帧,然后将每一帧图像传递给BarcodeReader进行解码。

这里给出一个简化的逻辑框架:

  1. 初始化摄像头,获取视频流。
  2. 在定时器或独立线程中,从摄像头获取当前帧(Bitmap)。
  3. 将当前帧的 Bitmap 传递给BarcodeReader.Decode方法。
  4. 如果解码成功,获取结果并处理(例如显示内容、触发事件、播放提示音)。
  5. 优化:为了性能,可以降低解码频率(比如每秒只解码5次),或者只对图像中心区域进行解码(假设二维码在画面中央)。
// 伪代码,展示核心循环逻辑 private void CameraDecodingLoop() { BarcodeReader reader = new BarcodeReader(); while (_isCameraRunning) { Bitmap frame = _camera.GetCurrentFrame(); // 假设这个方法能获取当前摄像头画面 if (frame != null) { Result result = reader.Decode(frame); if (result != null) { // 成功解码,更新UI(注意跨线程调用) Invoke(new Action(() => { textBoxResult.Text = result.Text; })); // 可以在这里 break 跳出循环,或者继续扫描 } frame.Dispose(); // 重要!及时释放资源 } Thread.Sleep(200); // 暂停200毫秒,降低CPU占用 } }

实时解码的关键在于平衡识别速度和CPU占用。如果每一帧都全分辨率解码,CPU 可能会吃不消。常见的优化手段包括:降低采样帧率、缩小解码区域、在后台线程进行解码操作。

5. 实战经验:我踩过的那些“坑”与解决方案

最后,分享几个我在项目里真实遇到过的坑和解决办法,希望能帮你少走弯路。

坑1:中文内容乱码这个问题很常见。生成时,如果你不指定字符集,默认的编码可能不支持中文,导致扫出来的内容是乱码。解决方案:无论在生成还是解析时,都显式设置字符集为 UTF-8。

// 生成时 writer.Options.Hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8"); // 或使用 QrCodeEncodingOptions writer.Options = new QrCodeEncodingOptions { CharacterSet = "UTF-8" }; // 解析时 reader.Options.CharacterSet = "UTF-8";

坑2:生成的二维码扫不出来除了前面提到的边距(Margin)问题,还有几个可能:

  • 尺寸太小:像素尺寸太小,手机摄像头难以捕捉足够的细节。尝试增大Width和Height。
  • 颜色对比度不足:如前所述,前景色和背景色太接近。
  • 容错级别太低,但信息太长:你编码的内容太长了,超过了当前尺寸和容错级别下的容量上限。要么缩短内容,要么增大二维码尺寸,要么提高容错级别。

坑3:解析速度慢,特别是大图直接对一张几兆像素的图片进行全局解码,速度肯定快不了。解决方案:

  • 先缩放:将图片缩放到一个合理的尺寸(例如最长边不超过 1024 像素)再进行解码。
  • 指定区域:如果你知道二维码大概在图片的什么位置,可以使用reader.Decode的重载方法,指定一个Rectangle区域,只解码那一部分。
    Rectangle scanArea = new Rectangle(100, 100, 300, 300); // 假设二维码在 (100,100) 开始的300x300区域内 Result result = reader.Decode(bitmap, scanArea);

坑4:在 Web 服务(如 ASP.NET Core)中处理并发如果在高并发的 Web API 中频繁创建和销毁BarcodeWriter/BarcodeReader实例,可能会对性能有影响。解决方案:考虑使用依赖注入,将其注册为单例(Singleton)或作用域(Scoped)服务。因为这两个对象本身是线程安全的(根据官方文档和常见用法,在只读配置下可视为线程安全),可以安全地复用。

// 在 Startup.cs 或 Program.cs 中 services.AddSingleton<BarcodeWriter>(provider => new BarcodeWriter { Format = BarcodeFormat.QR_CODE, Options = new QrCodeEncodingOptions { ... } }); services.AddSingleton<BarcodeReader>(provider => new BarcodeReader { Options = new DecodingOptions { CharacterSet = "UTF-8" } });

坑5:处理带Logo的二维码解析失败有时用户上传的带Logo二维码,你的程序识别不了,但微信却能扫出来。解决方案:除了确保生成时用了高容错(H),在解析时也可以尝试开启TryHarder选项。更关键的是,检查 Logo 是否遮挡了三个定位角(Finder Pattern)。定位角是解码器最先寻找的特征,一旦被严重遮挡,解码算法可能根本无法定位到二维码。

把这些点都注意到,你的 C# 二维码应用基本上就能应对绝大多数业务场景了。ZXing.Net 这个库虽然上手简单,但提供的功能和可调整的参数非常丰富,足以支撑起专业级的应用。剩下的,就是根据你的具体业务需求,去设计和优化用户体验了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 20:16:58

ComfyUI可视化工作流集成BERT文本分割节点实战

ComfyUI可视化工作流集成BERT文本分割节点实战 你是不是也遇到过这样的场景&#xff1f;手头有一大堆文档、报告或者长篇文章&#xff0c;需要快速把它们拆分成有逻辑的段落或句子&#xff0c;以便后续进行摘要生成、情感分析或者信息提取。手动处理&#xff1f;效率太低。写脚…

作者头像 李华
网站建设 2026/10/17 11:05:16

大麦自动化抢票工具全攻略:从入门到精通的Python实现指南

大麦自动化抢票工具全攻略&#xff1a;从入门到精通的Python实现指南 【免费下载链接】DamaiHelper 大麦网演唱会演出抢票脚本。 项目地址: https://gitcode.com/gh_mirrors/dama/DamaiHelper 基础认知&#xff1a;自动化抢票工具原理与环境校验 大麦自动化抢票工具是基…

作者头像 李华
网站建设 2026/10/17 14:04:35

从零开始:SD-Trainer与Dreambooth的个性化模型训练指南

1. 为什么你需要一个自己的AI绘画模型&#xff1f; 你是不是也经常在网上看到别人用AI画出的各种惊艳图片&#xff0c;有特定的人物、独特的画风&#xff0c;甚至是你家宠物的专属艺术照&#xff1f;心里痒痒的&#xff0c;也想自己动手做一个&#xff0c;但一看到“模型训练”…

作者头像 李华
网站建设 2026/10/16 15:42:47

掌握3大核心能力:QtScrcpy跨设备控制完全指南

掌握3大核心能力&#xff1a;QtScrcpy跨设备控制完全指南 【免费下载链接】QtScrcpy QtScrcpy 可以通过 USB / 网络连接Android设备&#xff0c;并进行显示和控制。无需root权限。 项目地址: https://gitcode.com/GitHub_Trending/qt/QtScrcpy QtScrcpy是一款开源跨平台…

作者头像 李华
网站建设 2026/10/6 4:23:37

Krita AI Diffusion插件:从模型部署到故障解决的全流程指南

Krita AI Diffusion插件&#xff1a;从模型部署到故障解决的全流程指南 【免费下载链接】krita-ai-diffusion Streamlined interface for generating images with AI in Krita. Inpaint and outpaint with optional text prompt, no tweaking required. 项目地址: https://gi…

作者头像 李华
网站建设 2026/10/23 8:43:23

Qwen3模型Dify平台集成指南:快速构建AI应用工作流

Qwen3模型Dify平台集成指南&#xff1a;快速构建AI应用工作流 你是不是也遇到过这样的场景&#xff1a;手头有一个很棒的AI模型&#xff0c;比如Qwen3&#xff0c;但不知道怎么把它变成一个能给别人用的、有完整流程的应用&#xff1f;自己从头写API、做界面、处理逻辑&#x…

作者头像 李华