2021SC@SDUSC Zxing开源代码(十五)PDF417二维码(一)

2021SC@SDUSC


前言:本篇博客简单介绍了PDF417二维码的相关知识,以及编码步骤过程。


一、PDF417概述

1.1 简介

PDF417是美国符号科技(Symbol Technologies, Inc.)发明的二维条码,是一种堆叠式二维条码。PDF(Portable Data File)意思是“便携数据文件”,组成条码的每一个条码字符由4个条和4个空共17个模块构成,故称为PDF417条码。 PDF417条码需要有417解码功能的条码阅读器才能识别。发明人是台湾赴美学人王寅君博士,王博士于1984年毕业于国立交通大学资讯系,获得纽约州立大学石溪分校(University of New York at Stony Brook)电脑硕士和博士学位后,在1988年进入符号科技进行二维条码的研发工作,于1992年底推出PDF417,并于1989年至1992年间领导世界第一部二维条码雷射读码系统的开发。1993年3月作者正式将PDF417引进台湾,交由祥记资讯推广及研发相关套装软体(黄庆祥,1995)。

目前PDF417、Maxicode、Datamatrix同被美国国家标准协会 (American National Standards Institute, ANSI) MH10 SBC-8委员会选为二维条码国际标准制定范围,其中PDF417主要是预备应用于运输包裹与商品资料标签(Burnell, 1995)。PDF417不仅具有错误侦测能力,且可从受损的条码中读回完整的资料(Moore, 1994),亦即「错误复原能力」,其错误复原率最高可达50%。

PDF417条码是一种高密度、高信息含量的便携式数据文件,是实现证件及卡片等大容量、高可靠性信息自动存储、携带并可用机器自动识读的理想手段。

PDF417二维码可应用在:证件管理、执照年检、报表管理、机电产品的生产和组配线、银行票据管理及行包、货物的运输和邮递。PDF417条码最大的优势在于其庞大的数据容量和极强的纠错能力。

1.2 PDF417二维条码的结构

由于PDF417二维条码的容量较大,除了可将人的姓名、单位、地址、电话等基本资料进行编码外,还可将人体的特徵如指纹、视网膜扫瞄、及照片等个人纪录储存在条码中,这样不但可以实现证件资料的自动输入,而且可以防止证件的伪造,减少犯罪。PDF417已在美国、加拿大、纽西兰的交通部门的执照年审、车辆违规登记、罚款及定期检验上开始应用。美国并同时将PDF417应用在身分证、驾照、军人证上。此外墨西哥也将PDF417应用在报关单据与证件上,从而防止了仿造及犯罪。

PDF417是一个公开码,任何人皆可用其演算法而不必付费,因此是一个开放的条码系统。PDF417的PDF为可携性资料档(Portable Data File)的缩写,取其条码类似一个资料档,可储存较多资料,且可随身携带或随产品走而得名(Paclidis, 1992)。正如其名,每一个PDF码的储存量可高达1,108个文数字(Bytes),若将数字压缩则可存放至2,729Bytes。

每一个PDF417码是由3~90横列堆叠而成,而为了扫瞄方便,其四周皆有静空区,静空区分为水平静空区与垂直静空区,至少应为0.020寸,如图:
在这里插入图片描述
其中每一层都包括下列五个部份:

起始码。
左标区:在起始码后面,为一指示符号字元。
资料区:可容纳1~30个资料字元。
右标区: 在资料区的后面,为一指示符号字元。
结束码:在横列之最右边。

除了起始码和结束码外,左标区、资料区和右标区的组成字元皆可称为字码 (Codeword),每一个字码由17个模组(Modules)所构成,每一个字码又可分成4线条(或黑线)及4空白(或白线),每个线条至多不能超过6个模组宽。每个417码因资料大小不同,其行数及每行的资料模组数与字码数都可以从1至30不等。字码的组成如图:
在这里插入图片描述

1.3 PDF417二维条码的尺寸

也因为符号的组合较有弹性,每一个PDF417二维条码可因应不同的实体设备印成不同的长宽比例与密度,以适应印刷条件及扫瞄条件的要求。其中每个模组宽X是PDF417码中最重要的尺寸之一,X值的最小限制为0.0075英寸(约0.191mm),在同一个条码符号中,X的值是固定不变的。

PDF417的最小高度与长度可由下列算式算出:

W= (17C+69)X+ 2Q
H = R ×Y+ 2Q

其中:
W= 条码宽度,H=条码高度,X=条码模组宽,Y=层数
C=每层符号字元的总数(含左右标区),R=层高,Q=静空区大小

1.4 PDF417二维条码的错误纠正能力

PDF417二维条码的一个重要特性是其自动纠正错误的能力较高,不过PDF417的错误纠正能力与每个条码可存放的资料量有关,PDF417码将错误复原分为9个等级,其值从0到8,级数愈高,错误纠正能力愈强,但可存放资料量就愈少,一般建议编入至少10%的检查字码。资料存放量与错误纠正等级的关系如下表所示:

错误纠正等级纠正码数可存资料量(位元)
自动设定641024
021108
141106
281101
3161092
4321072
5641024
6128957
7256804
8512496

下表建议不同的字数所适用的错误纠正等级;

资料字码数错误纠正等级
1~402
40~1603
161~3204
321~8635

如前所述,错误纠正等级涉及拒读错误(E错误)与替代错误(T错误)两种错误类型。无论使用哪一种条码机都有一定的精密度极限,造成线条和空白的宽度与理想宽度间必有偏差存在,条码扫瞄设备能够读出解码演算法所允许范围内的不精确条码符号,目前标准中规定X的值最小为0.0075英寸(约0.191mm),此一限制同时反映出目前标准设备的技术现状。

1.5 PDF417的特性

综合本节所讨论,PDF417的特性如下表所示:

项目特性
可编码字元集8位二进制资料,多达811800种不同的字元集或解释
类型连续型,多层
字元自我检查
尺寸可变高:390层宽:130栏
读码方式双向可读
错误纠正字码数2~512个
最大资料容量安全等级为0, 每个符号可表示1108个位元

二、PDF417Writer

与之前介绍的二维码类似,PDF417Writer类继承了父类Writer。

PDF417Writer有两个静态变量:

分别表示代码周围的默认空白(边距)和默认错误更正级别。

  private static final int WHITE_SPACE = 30;
  private static final int DEFAULT_ERROR_CORRECTION_LEVEL = 2;

PDF 417的值是由一个数组来保存的。

input 是一个信息字节数组,0为黑色,1为白色;
margin 是条形码周围的边距边框;
返回输入的位矩阵。

  private static BitMatrix bitMatrixFromBitArray(byte[][] input, int margin) {
    // 创建带有额外空格的位矩阵
    BitMatrix output = new BitMatrix(input[0].length + 2 * margin, input.length + 2 * margin);
    output.clear();
    for (int y = 0, yOutput = output.getHeight() - margin - 1; y < input.length; y++, yOutput--) {
      byte[] inputY = input[y];
      for (int x = 0; x < input[0].length; x++) {
        // 零在字节矩阵中为白色
        if (inputY[x] == 1) {
          output.set(x + margin, yOutput);
        }
      }
    }
    return output;
  }

除此之外,还有函数rotateArray(),获取PDF417二维码数组并将其旋转90度。
这使得旋转屏幕时二维码在屏幕上的方向一致。

  private static byte[][] rotateArray(byte[][] bitarray) {
    byte[][] temp = new byte[bitarray[0].length][bitarray.length];
    for (int ii = 0; ii < bitarray.length; ii++) {
      int inverseii = bitarray.length - ii - 1;
      for (int jj = 0; jj < bitarray[0].length; jj++) {
        temp[jj][inverseii] = bitarray[ii][jj];
      }
    }
    return temp;
  }

三、class PDF417

PDF417实现的逻辑部分的顶级类。

有两个静态变量,分别表示启动模式(17位)和停止模式(18位)。

  private static final int START_PATTERN = 0x1fea8;
  private static final int STOP_PATTERN = 0x3fa29;

接下来介绍几种set方法:

setDimensions(int maxCols, int minCols, int maxRows, int minRows) 用来设置最大/最小行/列值,其参数分别表示允许的最大列数、允许的最小列数、允许的最大行数、允许的最小行数。

setCompaction(Compaction compaction)设置要使用的压缩模式。

setCompact(boolean compact)如果compact为真,则启用压缩。

setEncoding(Charset encoding)设置要使用的字符编码。

  public void setDimensions(int maxCols, int minCols, int maxRows, int minRows) {
    this.maxCols = maxCols;
    this.minCols = minCols;
    this.maxRows = maxRows;
    this.minRows = minRows;
  }

  public void setCompaction(Compaction compaction) {
    this.compaction = compaction;
  }

  public void setCompact(boolean compact) {
    this.compact = compact;
  }

  public void setEncoding(Charset encoding) {
    this.encoding = encoding;
  }

determineDimensions(int sourceCodeWords, int errorCorrectionCodeWords)用来确定指定码字数的最佳列和行。
其中,sourceCodeWords 为代码字数,errorCorrectionCodeWords 为纠错码字数,该函数返回维度对象包含列作为宽度和行作为高度。

  private int[] determineDimensions(int sourceCodeWords, int errorCorrectionCodeWords) throws WriterException {
    float ratio = 0.0f;
    int[] dimension = null;
    for (int cols = minCols; cols <= maxCols; cols++) {
      int rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, cols);
      if (rows < minRows) {
        break;
      }
      if (rows > maxRows) {
        continue;
      }
      float newRatio = ((float) (17 * cols + 69) * DEFAULT_MODULE_WIDTH) / (rows * HEIGHT);
      // 如果以前的比率更接近首选比率,则忽略
      if (dimension != null && Math.abs(newRatio - PREFERRED_RATIO) > Math.abs(ratio - PREFERRED_RATIO)) {
        continue;
      }
      ratio = newRatio;
      dimension = new int[] {cols, rows};
    }
     // 处理最小值大于必要值时的情况
     if (dimension == null) {
       int rows = calculateNumberOfRows(sourceCodeWords, errorCorrectionCodeWords, minCols);
       if (rows < minRows) {
         dimension = new int[]{minCols, minRows};
       }
     }
    if (dimension == null) {
      throw new WriterException("Unable to fit message in columns");
    }
    return dimension;
  }

参考资料:

PDF417二维条码详解

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值