c-lodop打印 html后,条码不能识别问题排查

342 阅读6分钟

目前有一个需求,就是将外卖订单绘制成 html页面,再通过 c-lodop 打印出来,外卖小票大概是如下的样子。其中外卖小票的底部有一个条码,尝试了 3 种方案,前两种方案中,这个条码是基于 JsBarcode 将 订单编号转为的条码。第三种方案,是采用 c-lodop 来生成的条码。 刚开始听不到扫码枪“滴”的声音。经过自己的排查,最终听到了“滴”的声音。

image.png

问题描述

目前,在实现这需求的过程中,遇到一个问题 ,打印出来的小票,扫码枪识别不了底部的条码。

场景 1:通过 c-lodop + 电脑自带的打印, 打印出来的pdf. 底部的条码,手机是可以扫描识别的,但是扫码枪识别不了。

场景 2:通过 c-lodop + 真是打印机,打印出来的纸质小票。 底部的条码,手机和扫码枪都识别不了。

JsBarcode 绘制条码的代码如下

function _barCodeFoo(tid){
        const $svg = $(`<svg  id="ele_${tid}"/>`)
        $svg.JsBarcode(tid, {
            format: 'CODE128',
            width: 3, // 条的宽度,建议 1~3
            // height: 120, // 条码高度,建议 >= 50,太低可能影响扫描
            displayValue:  true, // 显示数字
            margin: 0,
        });
        let src = 'data:image/svg+xml;base64,' + btoa(unescape($svg.prop('outerHTML')))
        console.log('条形码 bar ',src)
        return src;
}

排查1

可能原因 1:JsBarcode 方法中,width 设置的原因

可能原因 2:图片的宽度、高度导致的

image.png

于是做了 一些尝试,但是问题依然存在。扫码枪依然识别不了底部的条码。 image.png

image.png

排查 2

先看图

图 1

image.png

图 2

image.png

html页面中,底部条码图片中样式 object-fit: cover; 是生效的。但是实际用 c-lodop 来打印的时候,object-fit: cover;就没有生效。特别是订单编号很短的时候,非常明显。

推测 于是,我有了如下的推测。

因为底部的条码是最终生成的是 [SVG 格式的 Base64 数据 URL],再将这个 URL 通过 img 标签来显示出来。是不是 c-lodop 在打印条码的时候,条码图片会被压缩、失真。于是我问了下豆包。豆包提供的回答如下。

image.png

新的尝试

基于上述排查 2 的思路,于是我改变下生成条码图片的方式。问了下豆包,生成条码图片的方式。

image.png

将订单编号改为 123456789,用两种方式生成的条码图片如下。base64 生成的条码图片用扫码枪不能识别,基于 canvas生成的条码图片扫码枪是可以识别的。

纠正下: 这里说的 base64 生成的条码图片,准确的说法应该是 [SVG 格式的 Base64 数据 URL] ,也就是下面的左图。

image.png

我使用扫码枪是可以识别方式 2 生成的条码图片的。听到一声“滴”,我开心的笑了。哈哈

image.png

关键代码如下

// 之前基于 [SVG 格式的 Base64 数据 URL]生成条码图片,c-lodop打印的时候会压缩,导致失真,条码枪识别不了。
// 改为 基于 canvas 生成图片,这种图片不会因压缩导致线条失真
function _barCodeFoo3(tid) {
    const canvas = document.createElement('canvas');
    JsBarcode(canvas, 123456789, {
        format: 'CODE128',
        width: 2,  // 条码宽度(建议 2~3)
        height: 50, // 条码高度(建议 >=50)
        displayValue: true, // 是否显示数字
        margin: 0
    });
    // 转换为 Base64 PNG
    const pngDataUrl = canvas.toDataURL('image/png');
    return pngDataUrl;
}

排查 3

昨天晚上,将代码合并到测试分支后。今天早上就叫测试同学测试下条码不能识别的问题。测试同学反馈说,这个条码的编号是 “123456789”,我一看,昨天粗心将订单编号改为了 “123456789”。 这个 9 位数的条码,用扫码枪确实可以扫码出来。

于是我将订单改为真实的 19 位数,发现扫码枪还是不能识别。昨晚弄到晚上 10 点多,以为搞定了,发现还是没有搞定。还得继续排查原因。

image.png

我仔细观察了下这次生成的条码有类似拖影的感觉。如下图。

image.png

反思: 为啥打印出来的 9 位数的条码,扫码枪可以识别。但是打印出来的 19 位的条码,扫码枪不能识别呢?

可能原因,9 位数的条码信息不是很密集,所以扫码枪轻轻松松识别。但是 19 位的条码,信息比较密集,从条码的样子就可以看出来,这些竖条纹是很密集的。所以扫码枪识别很困难。

新的尝试

c-lodop 打印条码验证

就在我比较疑惑的时候,旁边的大佬给我了我一个思路。使用 lodop 来打印条码(lodop 直接基于订单号来生成并打印条码)。

于是我先用 lodop 打印了一下快递发货单,发现打印出来的条码,很容易被扫码枪识别。

image.png

我肉眼反正是看不出来有啥区别。但是我听到“滴”的声音的时候,我知道 c-lodop 生成的条码是可以的。于是我采用这种方案。

其中,c-lodop 生成条码的 api 如下。这个 Top 的计算很关键。

LODOP.ADD_PRINT_BARCODE(Top, Left, Width, Height, CodeType, CodeContent);

遇到了这个问题: 因为整个外卖小票上部分我是采用 c-lodop 打印 html 的方式来实现的。如果要使用 c-lodop 来生成底部的条码,条码的位置如何计算?于是我做了如下两种方式的探索。

处理方式 1

如果不计算 Top 的位置,c-lodop 打印完 html 后,再接着打印条码。但是如何让 c-lodop 接着打印呢。我问了下 AI 以及 c-lodop 的文档。发现了如下的 api .

LODOP.ADD_PRINT_HTM(00"100%""100%", htmlContent);

LODOP.SET_PRINT_STYLEA(0"LinkedItem"-1);  // 关联到前一项

LODOP.ADD_PRINT_BARCODE("5mm""10mm""200px""50px""128A""123456"); // 自动接在HTML下方

后面,我按照上面的代码去验证的时候,发现打印的条码到另一页了。

image.png

处理方式 2

使用 c-lodop 来生成条码,并计算条码的位置。于是问了下 ai ,采用这种方式。关键代码如下。

1、计算高度的代码如下


function _getHtmlHeight(htmlContent){
    const tempDiv = document.createElement("div");
    tempDiv.innerHTML = htmlContent;
    document.body.appendChild(tempDiv);
    const htmlHeightPx = tempDiv.offsetHeight + 40; // 额外留出 40px 的间距
    const htmlHeightMm = htmlHeightPx * 0.264583; // px转mm (1px≈0.264583mm)
    document.body.removeChild(tempDiv);
    return htmlHeightMm +'mm';
}

2、打印条码的关键代码如下

orderHtmlArr.forEach((item, index) => {
    const htmlStr = item.theHtml
    const htmlTop = item.height
    lodopDom.ADD_PRINT_HTM(0, 0, '100%', '100%', htmlStr);
    lodopDom.ADD_PRINT_BARCODE(htmlTop, '10mm', '56mm', '16mm', "128Auto", item.tid);
    if (index < orderHtmlArr.length - 1) lodopDom.NewPage(); // 非最后一页则分页
});

后面发现生成的条码还是有点问题,后来在其他同事的帮助下,将生成条码的 code 改为 ‘128Auto’,就好了。

image.png

总结

image.png

测试了这么多,终于弄好了,心里还是蛮开心的。也感谢同事提供的帮助。

本文记录了自己用 c-lodop 打印条码遇到的一些问题。记录下,方便后续回顾。

  • 生成条码的时候,最好采用 c-lodop 来生成条码。
  • 并且 生成条码的时候,code 设置为 “128Auto” 识别效果会更好些。
  • 扫码枪使用的时候,扫码枪和条码成一个大概 30 度的角度(扫码枪和条码不要垂直哦),这样识别的效果会更好些。

看了下时间,晚上 11 点了,先这样了。

附上其他更新

  • 25.10.13

SVG格式的Base64数据、PNG格式的Base64数据之间的区别。

image.png