zxing 设置条码两边空白 (EncodeHintType.MARGIN) 无效的分析

本贴最后更新于 3157 天前,其中的信息可能已经时移世改

zxing 设置条码两边空白(EncodeHintType.MARGIN)无效的分析,有需要的朋友可以参考下。

最新项目需要使用到 zxing 生成条码,条码格式为 CODE128,CODE128 的规则可参考:点击打开链接

当调用
MultiFormatWriter().encode(str,BarcodeFormat.CODE_128, mwidth, mHeight, hints)

后生成的矩阵数据转换为 Bitmap 图时,会产生很大的左右两边的空白,zxing 提供了 EncodeHintType.MARGIN 选项来设置左右空白,很多时候无效,但偶然会成功,很困惑,所以追踪了一下代码,明白了其生成的原理,现以源码解析的方式整理如下。

此处,以类似“901001*C005”格式的内容来分析,编码格式为 CODE128。

1、

BitMatrix matrix = new MultiFormatWriter().encode(str,BarcodeFormat.CODE_128, mwidth, mHeight, hints);

此处没什么讲的生成条码/二维码的核心代码,zxing 使用方法可以去百度/谷歌。

2、追踪 encode 函数,其原型 MultiFormatWriter.java 中,代码如下:

public BitMatrix encode(String contents,
BarcodeFormat format,
int width, int height,
Map hints) throws WriterException {

Writer writer; switch (format) { case EAN_8: writer = new EAN8Writer(); break; case EAN_13: writer = new EAN13Writer(); break; case UPC_A: writer = new UPCAWriter(); break; case QR_CODE: writer = new QRCodeWriter(); break; case CODE_39: writer = new Code39Writer(); break; case CODE_128: writer = new Code128Writer(); break; case ITF: writer = new ITFWriter(); break; case PDF_417: writer = new PDF417Writer(); break; case CODABAR: writer = new CodaBarWriter(); break; case DATA_MATRIX: writer = new DataMatrixWriter(); break; case AZTEC: writer = new AztecWriter(); break; default: throw new IllegalArgumentException("No encoder available for format " + format); } return writer.encode(contents, format, width, height, hints);

}

可以看到其采用工厂模式,将任务分发到了各个实现类中,以本测试 CODE128 格式为例,其使用的是 Code128Writer 中的 encode 函数,接着追踪到该单元中。

3、

public final class Code128Writer extends OneDimensionalCodeWriter {
@Override
public BitMatrix encode(String contents,
BarcodeFormat format,
int width,
int height,
Map hints) throws WriterException {
if (format != BarcodeFormat.CODE_128) {
throw new IllegalArgumentException("Can only encode CODE_128, but got " + format);
}
return super.encode(contents, format, width, height, hints);
}
@Override
public boolean[] encode(String contents) {
int length = contents.length();
/*
省略,就是根据 CODE128 的规则,生成一个一维的数组,每个元素代表有效内容的条码表示,true 代表“条”,false,代表空,此处测试内容为 901001C005,生成的一维数组长度为 134,
*/
}
}

看到 encode(String contents,BarcodeFormat......)调用了其父类的 encode 函数,继续追踪。

4、

@Override
public BitMatrix encode(String contents,
BarcodeFormat format,
int width,
int height,
Map hints) throws WriterException {
if (contents.isEmpty()) {
throw new IllegalArgumentException("Found empty contents");
}

if (width < 0 || height < 0) { throw new IllegalArgumentException("Negative size is not allowed. Input: " + width + 'x' + height); } int sidesMargin = getDefaultMargin(); if (hints != null) { Integer sidesMarginInt = (Integer) hints.get(EncodeHintType.MARGIN); if (sidesMarginInt != null) { sidesMargin = sidesMarginInt; } } boolean[] code = encode(contents); return renderResult(code, width, height, sidesMargin);

}

此处可以看到,我们设置的 EncodeHintsType.MARGIN 出现了,代码的具体含义就是,你要是设置了该值就取你设置的值,如果没有设置,去默认值(10),代码为:

public int getDefaultMargin() {
// CodaBar spec requires a side margin to be more than ten times wider than narrow space.
// This seems like a decent idea for a default for all formats.
return 10;
}

然后其其调用了 encode(String contents),该函数在 OneDimensionalCodeWriter 类中声明为抽象方法,下放到子类中实现,此处就是标题 3 处 Code128Writer 类中实现的 encode(String content)生成一个一维数组。

接下来关键的内容来,函数 renderResult。在该函数中计算了生成的矩阵的大小,其有你传入的宽、生成的一维数组长度、你设置的 MARGIN 三个参数共同决定,对于一维条码,高(需大于 1)并无大用。

5、

private static BitMatrix renderResult(boolean[] code, int width, int height, int sidesMargin) {
int inputWidth = code.length;
// Add quiet zone on both sides.
int fullWidth = inputWidth + sidesMargin;
int outputWidth = Math.max(width, fullWidth);
int outputHeight = Math.max(1, height);

int multiple = outputWidth / fullWidth; int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; BitMatrix output = new BitMatrix(outputWidth, outputHeight); for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { if (code[inputX]) { output.setRegion(outputX, 0, multiple, outputHeight); } } return output;

}

首先,inputWidth 即根据 CODE128 规则生成的一维数组的长度;此处为 134

接着,fullWidth 即实际内容宽度和你设置的空白宽度;假设,我设置 MARGIN 为 1,此处 fullwidth 为 135;

接下来,是获取输出矩阵的宽和高,用了取较大值的数学函数 max;假设我们设置的需要的条码宽和高分别为:300 和 100,此处 outputWidth 为 300,outputHeigth 为 100;

接着,关键代码,计算实际内容缩放的比例:multiple,此处可得 300/135=2,;

然后,可计算真实的左右空白:leftPadding,此处为:(300 - 135*2)/2 = 15;

然后,就是根据计算好的宽高及空白,生成矩阵。

我们可以在拿另一个例子解析下,宽设置为 270,MARGIN 设置为 0,故 multiple=2,leftPading = 0;然后生成的条码没有空白,但我们其他参数不变,宽设置为 260,得 multiple = 1;leftPading = (260 - 134*1)/2 = 62,两边有很大的空白。

结束语,之所以,zxing 会采用这种策略,就是为了保持条码中的比例,以免失真出现无法识别的条码矩阵。

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    89 引用 • 1251 回帖 • 390 关注
  • DNSPod

    DNSPod 建立于 2006 年 3 月份,是一款免费智能 DNS 产品。 DNSPod 可以为同时有电信、网通、教育网服务器的网站提供智能的解析,让电信用户访问电信的服务器,网通的用户访问网通的服务器,教育网的用户访问教育网的服务器,达到互联互通的效果。

    6 引用 • 26 回帖 • 530 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    79 引用 • 431 回帖
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    187 引用 • 3914 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    292 引用 • 4495 回帖 • 663 关注
  • danl
    187 关注
  • 开源

    Open Source, Open Mind, Open Sight, Open Future!

    415 引用 • 3601 回帖
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    7 引用 • 69 回帖 • 3 关注
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    134 引用 • 1128 回帖 • 110 关注
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖 • 2 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    142 引用 • 442 回帖
  • Follow
    4 引用 • 12 回帖 • 10 关注
  • Solidity

    Solidity 是一种智能合约高级语言,运行在 [以太坊] 虚拟机(EVM)之上。它的语法接近于 JavaScript,是一种面向对象的语言。

    3 引用 • 18 回帖 • 451 关注
  • Visio
    1 引用 • 2 回帖
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用 • 4 关注
  • OnlyOffice
    4 引用 • 18 关注
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    29 引用 • 66 回帖 • 2 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 651 关注
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    8 引用 • 26 回帖 • 1 关注
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 651 关注
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 663 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1062 引用 • 3455 回帖 • 148 关注
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    53 引用 • 190 回帖 • 3 关注
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    101 引用 • 905 回帖