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

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

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

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 心情

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

    59 引用 • 369 回帖
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    5 引用 • 13 回帖
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    21 引用 • 140 回帖 • 25 关注
  • V2Ray
    1 引用 • 15 回帖
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    28 引用 • 108 回帖 • 2 关注
  • Bootstrap

    Bootstrap 是 Twitter 推出的一个用于前端开发的开源工具包。它由 Twitter 的设计师 Mark Otto 和 Jacob Thornton 合作开发,是一个 CSS / HTML 框架。

    18 引用 • 33 回帖 • 685 关注
  • OnlyOffice
    4 引用 • 27 关注
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 553 关注
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    7 引用 • 30 回帖 • 455 关注
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 511 关注
  • Unity

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

    25 引用 • 7 回帖 • 250 关注
  • 分享

    有什么新发现就分享给大家吧!

    242 引用 • 1746 回帖 • 1 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    84 引用 • 139 回帖 • 1 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    19 引用 • 31 回帖 • 3 关注
  • 导航

    各种网址链接、内容导航。

    37 引用 • 168 回帖
  • JSON

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

    51 引用 • 190 回帖 • 2 关注
  • 星云链

    星云链是一个开源公链,业内简单的将其称为区块链上的谷歌。其实它不仅仅是区块链搜索引擎,一个公链的所有功能,它基本都有,比如你可以用它来开发部署你的去中心化的 APP,你可以在上面编写智能合约,发送交易等等。3 分钟快速接入星云链 (NAS) 测试网

    3 引用 • 16 回帖 • 5 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 454 关注
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖 • 3 关注
  • 书籍

    宋真宗赵恒曾经说过:“书中自有黄金屋,书中自有颜如玉。”

    76 引用 • 390 回帖 • 1 关注
  • frp

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 TCP、UDP、 HTTP 和 HTTPS 协议。

    15 引用 • 7 回帖 • 9 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 696 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    185 引用 • 318 回帖 • 348 关注
  • danl
    61 关注
  • Rust

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

    57 引用 • 22 回帖 • 2 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    35 引用 • 200 回帖 • 24 关注
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 422 关注