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

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

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 会采用这种策略,就是为了保持条码中的比例,以免失真出现无法识别的条码矩阵。

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 559 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 164 关注
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 159 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖 • 7 关注
  • 电影

    这是一个不能说的秘密。

    121 引用 • 604 回帖 • 1 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    96 引用 • 155 回帖
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 464 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    36 引用 • 37 回帖 • 535 关注
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 161 关注
  • CongSec

    本标签主要用于分享网络空间安全专业的学习笔记

    1 引用 • 1 回帖 • 15 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 683 关注
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 53 关注
  • 工具

    子曰:“工欲善其事,必先利其器。”

    288 引用 • 734 回帖 • 2 关注
  • Unity

    Unity 是由 Unity Technologies 开发的一个让开发者可以轻松创建诸如 2D、3D 多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

    25 引用 • 7 回帖 • 159 关注
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖
  • 负能量

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

    88 引用 • 1235 回帖 • 410 关注
  • Pipe

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

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

    132 引用 • 1114 回帖 • 125 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1737 回帖 • 1 关注
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    53 引用 • 37 回帖 • 3 关注
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    91 引用 • 751 回帖 • 1 关注
  • 自由行
    4 关注
  • API

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

    77 引用 • 430 回帖 • 1 关注
  • 学习

    “梦想从学习开始,事业从实践起步” —— 习近平

    171 引用 • 512 回帖