ZXing.Net 0.16.8.0 条码识别实战:从解码链路到性能调优

简介:ZXing.Net.0.16.8.0 是面向 C# 与 Unity 开发者的开源条码处理库,基于 Zebra Crossing 项目,可在 .NET 框架与 Unity 引擎中实现 QR 码、Aztec、Code 128、EAN 等多种条码的读取与生成。开发者只需调用少量 API 即可为桌面应用、移动端或游戏加入扫码功能,例如让玩家扫描屏幕条码获取游戏内物品信息。压缩包共 132 个文件,约 18.27MB,以 dll 动态库、pdb 调试符号、xml 文档注释为主,另含 pri、winmd、cmd 脚本及 COPYING、THANKS 等说明文件,覆盖 net4.0、net4.6、net5.0、sl4、sl5、wp8.0、ce2.0 等多个平台版本,便于按目标框架挑选依赖。目前已有 923 人学习下载,适合需要跨平台条码识别能力的中高级 C# 与 Unity 开发者参考,可帮助快速完成库的选型、导入与兼容性适配。

1. 从一次扫码翻车说起:ZXing.Net 0.16.8.0 到底能解决什么

去年帮一个做仓储盘点的团队看问题,他们的 Unity 项目在 PC 编辑器里扫码识别率接近百分之百,打包到 Android 真机后,同一张二维码十次里能失败六七次。排查了两天,最后发现是摄像头采集的帧格式和识别库之间的色彩空间没对齐,跟算法本身没关系。那次之后我养成了一个习惯:凡是涉及条码识别的项目,先把底层库的版本、依赖和平台差异摸清楚,再谈业务逻辑。ZXing.Net 0.16.8.0 就是这样一个值得先摸清楚的底层库——它是 ZXing(Zebra Crossing)的 .NET 移植版本,支持 QR Code、Data Matrix、Code 128、EAN-13 等主流一维和二维条码的生成与解码,可以跑在 .NET Framework、.NET Core、.NET Standard 以及 Unity 的 C# 运行时里。如果你正在用 Unity 做扫码登录、库存管理、票务核验,或者需要在服务端批量生成条码图片,这个包基本是绕不开的选项。它适合两类人:一类是刚接触条码识别、想找一个能直接跑通的 C# 方案的新手;另一类是已经用过其他库、但被平台兼容性或识别率折腾过的熟手。接下来我会把它的核心用法、参数调优和几个容易翻车的地方拆开讲。

2. 核心解码链路:从图像到文本的完整实现

2.1 为什么选 ZXing.Net 而不是自己写解析

条码识别看起来简单——找到黑白模块、按规则翻译成字符——但真正落地时会遇到一堆工程问题:图像有透视畸变怎么办、光照不均导致二值化阈值失效怎么办、多个条码同时出现在画面里怎么定位、不同码制的纠错等级怎么处理。ZXing 内部把这些都封装成了可配置的 Pipeline,包括灰度化、二值化、条码区域检测、网格采样、纠错解码几个阶段。自己从零实现一套能稳定跑的,保守估计要投入几个月,而且很难覆盖所有码制。ZXing.Net 0.16.8.0 在这个基础上做了 .NET 侧的适配,把 Bitmap 和 Unity 的 Color32 数组之间的转换、多线程解码、结果回调都准备好了。常见做法是直接引用它的核心库,然后在自己的采集层做帧格式转换,把图像喂给 BarcodeReader 就行。

2.2 最小可运行示例:解码一张本地图片

先看最基础的用法,从一张 PNG 图片里读出二维码内容。这段代码在 .NET Core 控制台项目和 Unity 的 Editor 脚本里都能跑。

using ZXing; using System.Drawing; // .NET Core 需要额外引用 System.Drawing.Common // 创建解码器,指定可能出现的码制 var reader = new BarcodeReader { // 只开启 QR Code,减少误识别 Options = new ZXing.Common.DecodingOptions { PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }, TryHarder = true, // 对模糊图像更努力地尝试 TryInverted = true // 同时尝试反色图像 } }; // 加载图片并解码 using var bitmap = new Bitmap("qrcode.png"); var result = reader.Decode(bitmap); if (result != null) { Console.WriteLine($"格式: {result.BarcodeFormat}"); Console.WriteLine($"内容: {result.Text}"); // 二维码四个角点,可用于定位或绘制 foreach (var point in result.ResultPoints) { Console.WriteLine($"角点: {point.X}, {point.Y}"); } } else { Console.WriteLine("未识别到条码"); }

这段代码的关键在DecodingOptions的三个参数。PossibleFormats限定码制是最容易被忽略的优化点——如果不限制,解码器会依次尝试所有支持的格式,耗时可能翻好几倍,而且容易把纹理误判成条码。TryHarder开启后,解码器会在第一次失败后尝试更复杂的二值化策略和旋转角度,代价是耗时增加,适合对识别率要求高、对延迟不敏感的场景。TryInverted处理白底黑码和黑底白码两种情况,有些工业场景的标签是反色印刷的,不开这个参数就会漏掉。

2.3 Unity 环境下的图像采集与解码适配

Unity 里没有 System.Drawing,图像数据通常是WebCamTexture或Color32[]数组。ZXing.Net 提供了Color32LuminanceSource来直接接收 Unity 的像素数据,省去转 Bitmap 的开销。

using UnityEngine; using ZXing; using System.Collections.Generic; public class QRScanner : MonoBehaviour { private WebCamTexture camTexture; private BarcodeReader reader; private float scanInterval = 0.2f; // 每 200ms 解码一次,避免每帧都跑 private float timer; void Start() { // 初始化摄像头 camTexture = new WebCamTexture(640, 480, 30); camTexture.Play(); // 配置解码器 reader = new BarcodeReader { Options = new ZXing.Common.DecodingOptions { PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }, TryHarder = true } }; } void Update() { timer += Time.deltaTime; if (timer < scanInterval || !camTexture.isPlaying) return; timer = 0; // 获取当前帧像素 Color32[] pixels = camTexture.GetPixels32(); int width = camTexture.width; int height = camTexture.height; // 直接传入 Color32 数组,内部会做灰度化 var source = new Color32LuminanceSource(pixels, width, height); var result = reader.Decode(source); if (result != null) { Debug.Log($"识别成功: {result.Text}"); // 触发业务逻辑,比如打开链接、提交表单 } } void OnDestroy() { if (camTexture != null) camTexture.Stop(); } }

这里有几个参数需要根据实际设备调整。scanInterval控制解码频率,移动端每帧解码会迅速吃满 CPU 导致发热降频,200ms 一次是识别速度和功耗的折中。摄像头分辨率 640x480 对二维码识别通常够用,再高会增加像素拷贝和灰度化的耗时。Color32LuminanceSource内部用的是标准灰度公式0.299R + 0.587G + 0.114B,如果你的场景光照偏色严重,可以考虑先做一次白平衡再传入。

2.4 生成条码:编码参数与输出格式

除了解码,ZXing.Net 也能生成条码。服务端批量出码、Unity 里动态渲染二维码都用得上。

using ZXing; using ZXing.QrCode; using ZXing.Common; // 配置二维码生成参数 var writer = new BarcodeWriterPixelData { Format = BarcodeFormat.QR_CODE, Options = new QrCodeEncodingOptions { Height = 256, Width = 256, Margin = 2, // 静默区宽度,单位是模块数 ErrorCorrection = ZXing.QrCode.Internal.ErrorCorrectionLevel.H, CharacterSet = "UTF-8" // 支持中文内容 } }; // 生成像素数据 var pixelData = writer.Write("https://example.com/order/12345"); // pixelData.Pixels 是 BGRA 格式的字节数组,可以直接创建 Texture2D

ErrorCorrection设成 H 级别意味着二维码有 30% 的纠错能力,适合印刷后可能磨损或部分遮挡的场景,代价是同样内容需要更多模块,码会变密。Margin是静默区,很多生成库默认给 0,导致扫码器找不到边界,这是个高频翻车点。CharacterSet不设 UTF-8 的话,中文内容会乱码,这个在 0.16.x 版本里需要显式指定。

3. 参数调优与性能边界:让识别率从 70% 到 95%

3.1 二值化策略的选择逻辑

ZXing 内部默认用 HybridBinarizer,它把图像分成 8x8 的块,每块单独计算阈值,适合光照不均匀的场景。但在某些情况下,GlobalHistogramBinarizer 反而更稳——比如图像整体对比度高、没有明显阴影的时候。切换方式是在 DecodingOptions 里设置:

var options = new ZXing.Common.DecodingOptions { PossibleFormats = new List<BarcodeFormat> { BarcodeFormat.QR_CODE }, TryHarder = true }; // 通过 BarcodeReader 的 Binarizer 属性切换 reader.Binarizer = new ZXing.Common.GlobalHistogramBinarizer(source);

我一般会先跑一遍默认的 Hybrid,如果识别率不理想,再换 Global 对比。工业视觉场景里,如果打光可控,Global 往往更快更准;移动端手持扫描,Hybrid 适应性更好。

3.2 图像预处理:裁剪、缩放与锐化

ZXing 对输入图像的尺寸有隐式要求。如果图像太大,解码耗时会线性增长;太小则条码模块模糊,采样失败。经验值是二维码在图像中占据的面积不低于 10%,每个模块至少 3 个像素。在 Unity 里可以在传入前做一次中心裁剪:

// 假设原始图像 1280x720,裁剪中心 640x480 区域 int cropW = 640, cropH = 480; int startX = (width - cropW) / 2; int startY = (height - cropH) / 2; Color32[] cropped = new Color32[cropW * cropH]; for (int y = 0; y < cropH; y++) { for (int x = 0; x < cropW; x++) { cropped[y * cropW + x] = pixels[(startY + y) * width + (startX + x)]; } } var source = new Color32LuminanceSource(cropped, cropW, cropH);

裁剪减少了解码器需要扫描的像素量,同时把条码区域放大到画面中心,对焦也更准。如果条码本身很小,可以先做一次双线性插值放大再传入,但放大倍数不要超过 2 倍,否则插值带来的模糊反而会降低识别率。

3.3 多码制共存时的优先级与冲突

一个画面里同时出现 QR Code 和 Code 128 时,如果 PossibleFormats 里两个都开着,解码器会按内部顺序尝试,先命中的返回。这可能导致你想读 QR 却读到了旁边的条形码。解决办法有两种:一是根据业务场景只开需要的格式;二是用DecodeMultiple方法拿到所有结果,再按格式筛选。

var results = reader.DecodeMultiple(source); foreach (var r in results) { if (r.BarcodeFormat == BarcodeFormat.QR_CODE) { // 处理二维码 } }

DecodeMultiple在 0.16.8.0 里已经支持,但性能比单码解码低不少,只在确实需要多码同读时用。

3.4 线程模型:别在主线程里跑解码

Unity 的 Update 里直接调 Decode 会阻塞渲染。移动端上一帧解码耗时可能到 50-100ms,直接导致掉帧。常见做法是丢到 ThreadPool 或 Task 里跑,主线程只负责采集和渲染结果。

private bool isDecoding = false; void Update() { if (isDecoding || timer < scanInterval) return; timer = 0; isDecoding = true; Color32[] pixels = camTexture.GetPixels32(); int w = camTexture.width, h = camTexture.height; System.Threading.Tasks.Task.Run(() => { var source = new Color32LuminanceSource(pixels, w, h); var result = reader.Decode(source); // 回到主线程更新 UI UnityMainThreadDispatcher.Enqueue(() => { if (result != null) Debug.Log(result.Text); isDecoding = false; }); }); }

注意Color32LuminanceSource构造时不会拷贝数组,如果后台线程解码的同时主线程在写 pixels,会有数据竞争。稳妥的做法是在 Task 里先做一次数组拷贝,或者用双缓冲交替采集。

4. 避坑与排查:那些文档里不会写的翻车现场

4.1 现象:PC 上正常,打包到移动端就识别失败

原因:Unity 的 WebCamTexture 在不同平台上返回的像素格式可能不同。PC 上通常是 RGB24,Android 上可能是 YV12 或 NV21,直接 GetPixels32 拿到的数据在部分设备上颜色通道顺序是反的,导致灰度化后黑白颠倒。

解决:在 Start 里检查camTexture.graphicsFormat,如果不是 RGB24,先用WebCamTexture.GetPixels32拿到数据后手动做一次通道交换。或者更稳妥的做法是先用camTexture.GetPixels32()渲染到 RenderTexture,再从 RenderTexture 读取标准 RGB 数据。

4.2 现象:识别率突然下降,之前能扫的码现在扫不出来

原因:ZXing.Net 0.16.8.0 默认的AutoRotate是关闭的。如果摄像头画面旋转了 90 度(比如手机横屏拿但应用锁竖屏),条码在图像里是侧着的,解码器找不到定位图案。

解决:在 DecodingOptions 里设AutoRotate = true,或者自己在传入前把图像旋转到正确方向。AutoRotate 会尝试 0/90/180/270 四个角度,耗时增加约 30%,但能覆盖绝大多数方向问题。

4.3 现象:生成的中文二维码扫出来是乱码

原因:QrCodeEncodingOptions.CharacterSet默认不是 UTF-8,在 0.16.x 里如果不显式设置,中文内容会按 ISO-8859-1 编码写入,扫码端按 UTF-8 解析就乱了。

解决:生成时强制指定CharacterSet = "UTF-8"。另外注意,部分老款扫码 App 对 UTF-8 的支持也不完善,如果目标用户环境不可控,可以考虑把中文内容先做 Base64 编码再写入,扫码后自行解码。

4.4 现象:TryHarder 开了之后 CPU 占用飙升,手机发烫

原因:TryHarder 会在首次解码失败后尝试多种二值化策略和旋转角度,每次尝试都是一次完整的图像扫描。如果画面里根本没有条码,每帧都在做无用功。

解决:加一个前置判断——先用简单的边缘检测或方差计算判断画面里是否有足够的黑白对比区域,没有就直接跳过解码。或者降低解码频率,从每 200ms 一次改成每 500ms 一次,配合 UI 上的扫描框引导用户对准。

4.5 现象:NuGet 安装后编译报错,找不到 ZXing.Common.DecodingOptions

原因:ZXing.Net 0.16.8.0 的 NuGet 包分了多个目标框架版本,Unity 项目如果用的是 .NET Standard 2.0 兼容模式,可能引用到了不包含完整 API 的程序集。

解决:确认 Unity 的 Api Compatibility Level 设为 .NET Standard 2.0 或 .NET 4.x,然后在 NuGet 里安装ZXing.Net主包,不要只装ZXing.Net.Bindings之类的子包。如果用的是 Unity Package Manager,需要手动把 dll 放到 Plugins 目录下,并确保平台设置里勾选了对应的 CPU 架构。

5. 进阶技巧:用自定义 LuminanceSource 接管灰度化

ZXing 默认的灰度化公式对大多数场景够用,但在红外摄像头、低照度或高对比度工业光源下,标准公式可能把条码区域和背景压成同一灰度。这时候可以继承LuminanceSource自己实现灰度映射。

using ZXing; public class CustomLuminanceSource : LuminanceSource { private byte[] luminances; public CustomLuminanceSource(Color32[] pixels, int width, int height) : base(width, height) { luminances = new byte[width * height]; for (int i = 0; i < pixels.Length; i++) { // 自定义权重:增强绿色通道,适合某些工业相机 int gray = (pixels[i].r * 2 + pixels[i].g * 5 + pixels[i].b * 1) / 8; luminances[i] = (byte)Mathf.Clamp(gray, 0, 255); } } public override byte[] GetRow(int y, byte[] row) { int offset = y * Width; if (row == null || row.Length < Width) row = new byte[Width]; for (int x = 0; x < Width; x++) row[x] = luminances[offset + x]; return row; } public override byte[] Matrix => luminances; }

这个自定义 Source 把绿色通道权重提高到 5/8,因为多数图像传感器对绿光最敏感,信噪比最高。在低照度环境下,这样加权后条码边缘的梯度更明显,二值化时更容易分离出黑白模块。代价是红色和蓝色信息被压缩,如果条码是红色印刷在白色背景上,反而可能识别不了——所以这个方案适合黑白或深色码,不适合彩色码。

另一个进阶用法是结合BarcodeReader.ResultPointCallback做实时定位反馈。在解码过程中,ZXing 会回调找到的定位点坐标,可以用这些点在 UI 上画扫描框,让用户知道有没有对准。

reader.Options.ResultPointCallback = new ResultPointCallback((point) => { // point 是解码过程中找到的定位点 Debug.Log($"定位点: {point.X}, {point.Y}"); });

这个回调在每次尝试解码时都会触发,可以用来做扫描引导动画。注意回调是在解码线程里执行的,更新 UI 需要切回主线程。

从那以后我每次集成条码库,都会先写一个最小测试场景:固定一张标准测试图,跑通解码,再逐步加摄像头采集、多线程、平台适配。这样出问题时能快速定位是库的问题还是采集层的问题。希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

AI率过高怎么办?九款降AI率工具与避坑指南

AI率过高怎么办?九款降AI率工具与避坑指南

上个月帮一位在外地项目上常驻的在职朋友看论文。他发来一张截图&#xff0c;检测系统提示“疑似AI生成内容占比接近四成”&#xff0c;导师在批注里连续写了好几遍——这几段请你按自己的话重写。他挺委屈&#xff1a;内容确实是自己对着调研材料一点一点整理出来的&#xff0…

2026/10/19 23:26:19 阅读更多 →
开源代码评审工作流:本地化、可审计、可定制的LLM实践方案

开源代码评审工作流:本地化、可审计、可定制的LLM实践方案

1. 项目概述&#xff1a;这不是一个“工具”&#xff0c;而是一套可落地的开源代码评审工作流“open-code-review”这个名字乍一听像某个新发布的 CLI 工具&#xff0c;或者某家大厂刚开源的 AI 代码审查平台。但实际翻遍 GitHub、Hugging Face 和主流技术社区&#xff0c;你会…

2026/10/19 23:26:19 阅读更多 →
基于YOLO11的无人机检测识别系统设计与实现

基于YOLO11的无人机检测识别系统设计与实现

一提到毕设做深度学习目标检测&#xff0c;十个里有八个都在刷COCO、VOC数据集&#xff0c;真正能落到现实问题上的反而不多。但“空域安全无人机检测识别”这个方向不一样&#xff0c;它直接对准了一个真实且刚需的场景——机场周边、重要场馆、活动安保都需要防范低空慢速小目…

2026/10/19 23:23:08 阅读更多 →

最新新闻

DeskcommCRM实战:轻量级客户管理与销售跟进全流程落地指南

DeskcommCRM实战:轻量级客户管理与销售跟进全流程落地指南

1. 项目概述&#xff1a;DeskcommCRM 到底是什么&#xff0c;以及为什么值得关注这两年市面上叫 CRM 的产品多得数不过来&#xff0c;但绝大多数都陷入了一个怪圈&#xff1a;功能越做越重&#xff0c;权限越加越细&#xff0c;你要是只为了管好手头几百个客户&#xff0c;得先…

2026/10/19 23:47:06 阅读更多 →
以沟通为核心的轻量级CRM系统设计与实践

以沟通为核心的轻量级CRM系统设计与实践

一个叫 DeskcommCRM 的项目&#xff0c;听起来有点像某个内部系统的代号&#xff0c;但实际上它代表了一类特别值得聊的东西&#xff1a;以“沟通”为核心的客户关系管理工具。我一开始接触这个项目名的时候&#xff0c;第一反应是“Deskcomm”可能是 Desk Communication 的缩写…

2026/10/19 23:47:06 阅读更多 →
从线程池失控到全局限流:高并发系统稳定性实战指南

从线程池失控到全局限流:高并发系统稳定性实战指南

1. 并发失控的第一现场&#xff1a;线程池是怎么被击穿的先说一个我实际排查过的案例场景。某公司核心交易链路的订单服务&#xff0c;平时性能表现很稳定&#xff0c;高峰期单机支撑上千QPS没有任何压力。但一次大促活动中&#xff0c;下游的库存服务因为数据库连接池被打满&a…

2026/10/19 23:39:50 阅读更多 →
STC单片机范例程序实战指南:从点灯到多外设工程搭建

STC单片机范例程序实战指南:从点灯到多外设工程搭建

简介&#xff1a;这是一份面向嵌入式初学者与单片机开发者的STC单片机C语言范例程序合集&#xff0c;围绕ADC采样、串口通信、EEPROM读写、ISP在系统编程、时钟中断、端口测试及优化编程思想等核心功能展开&#xff0c;适合用于课程实验、自学练手与项目参考。资源包共612个文件…

2026/10/19 23:39:50 阅读更多 →
Kafka全链路性能调优:吞吐量与延迟的实战权衡

Kafka全链路性能调优:吞吐量与延迟的实战权衡

前阵子业务告警群里又炸了——消费延迟从平时的几百毫秒一路飙到分钟级&#xff0c;P99 延迟曲线在监控面板上直接拉成一条陡坡。接手这套 Kafka 系统两年&#xff0c;类似的戏码每隔一阵就重演一次。与其每次都临时救火&#xff0c;不如把全链路参数优化这件事系统捋一遍。这篇…

2026/10/19 23:37:47 阅读更多 →
ZXing.Net 0.16.8.0 条码识别实战:从解码链路到性能调优

ZXing.Net 0.16.8.0 条码识别实战:从解码链路到性能调优

简介&#xff1a;ZXing.Net.0.16.8.0 是面向 C# 与 Unity 开发者的开源条码处理库&#xff0c;基于 Zebra Crossing 项目&#xff0c;可在 .NET 框架与 Unity 引擎中实现 QR 码、Aztec、Code 128、EAN 等多种条码的读取与生成。开发者只需调用少量 API 即可为桌面应用、移动端或…

2026/10/19 23:37:47 阅读更多 →

日新闻

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →