2021SC@SDUSC Zxing开源代码(十七)Zxing代码解析——一维码

2021SC@SDUSC


前言:本篇博客主要介绍一维码。


Code 39

Code39是条形码的一种,也被称为3 of 9 code、USD-3或者LOGMARS,由于编制简单、能够对任意长度的数据进行编码、支持设备广泛等特性而被广泛采用。

特点:
1、能够对任意长度的数据进行编码。其局限在于印刷品的长度和条码阅读器的识别范围。
2、支持设备广泛。目前几乎所有的条形码阅读设备都能阅读Code39码,打印机也是同样情况。
3、编制简单。简单的开发技术就能快速生成相应的编码图像。
4、一般Code39码由5条线和分开它们的4条缝隙共9个元素构成。线和缝隙有宽窄之分,而且无论线还是缝隙仅有3个比其他的元素要宽一定比例。39码因此得名。

编码规则:
1、每五条线表示一个字符;
2、 粗线表示1,细线表示0;
3、 线条间的间隙宽的表示1,窄的表示0;
4、 五条线加上它们之间的四条间隙就是九位二进制编码,而且这九位中必定有三位是1,所以称为39码;
5、 条形码的首尾各一个 * 标识开始和结束。

使用介绍:
Code 39只接受如下43个有效输入字符:
26个大写字母(A - Z),十个数字(0 - 9),连接号(-),句号(.),空格,美圆符号($),斜扛(/),加号(+)以及百分号(%)。
其余的输入将被忽略。
code39通常情况下不需要校验码。但是对於精确度要求高的应用,需要在code39条形码後面增加一个校验码。
由于可以合并两个字符来表达第三个字符.这样就可以用Code39条形码来表示整个ASCII表.这样就产生了Code 39全ASCII码字型.

  public boolean[] encode(String contents) {
    int length = contents.length();
    if (length > 80) {
      throw new IllegalArgumentException(
          "Requested contents should be less than 80 digits long, but got " + length);
    }

    for (int i = 0; i < length; i++) {
      int indexInString = Code39Reader.ALPHABET_STRING.indexOf(contents.charAt(i));
      if (indexInString < 0) {
        contents = tryToConvertToExtendedMode(contents);
        length = contents.length();
        if (length > 80) {
          throw new IllegalArgumentException(
              "Requested contents should be less than 80 digits long, but got " + length + " (extended full ASCII mode)");
        }
        break;
      }
    }

Code 93

Code 93 条码比 Code 39 条码更新、更安全且更紧凑,能读取字母和数字。它用于军事和汽车领域,还被加拿大邮政用来对特殊投递信息进行编码。

规格:Code 93 跟 Code 39 类似,其起始符和终止符不能以常规 ASCII 字符表示,通常指定为“*”。起始符后面是编码的数据。跟 Code 39 一样,每个字母由数值代表。数据后面是两个字符的校验码,用于在手动输入代码时保证准确性。这两个字符被称为“Modulo-47 校验符 C”和“Modulo-47 校验符 K”。代码中特定的数字组合生成一个余数,对应的字母或数字就变成了校验符 C 或 K。校验码后面是终止符,紧接着是终止条纹,表明条码结束。

优势: Code 93 条码比 Code 39 更小巧、更高效,且拥有更大的数据冗余,具备更高的安全性。它还包括 Code 39 中没有的 5 个特殊字符。

缺点:不同于 Code 39,Code 93 不是自检码,因此需要一个校验位。

  public boolean[] encode(String contents) {
    contents = convertToExtended(contents);
    int length = contents.length();
    if (length > 80) {
      throw new IllegalArgumentException(
        "Requested contents should be less than 80 digits long after converting to extended encoding, but got " + length);
    }

    int codeWidth = (contents.length() + 2 + 2) * 9 + 1;

    boolean[] result = new boolean[codeWidth];

    int pos = appendPattern(result, 0, Code93Reader.ASTERISK_ENCODING);

    for (int i = 0; i < length; i++) {
      int indexInString = Code93Reader.ALPHABET_STRING.indexOf(contents.charAt(i));
      pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[indexInString]);
    }

    //添加两个校验和
    int check1 = computeChecksumIndex(contents, 20);
    pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[check1]);

    //追加内容以反映添加的第一个校验和
    contents += Code93Reader.ALPHABET_STRING.charAt(check1);
    int check2 = computeChecksumIndex(contents, 15);
    pos += appendPattern(result, pos, Code93Reader.CHARACTER_ENCODINGS[check2]);
    pos += appendPattern(result, pos, Code93Reader.ASTERISK_ENCODING);
    result[pos] = true;

    return result;
  }

Code 128

CODE128码是广泛应用在企业内部管理、生产流程、物流控制系统方面的条码码制,由于其优良的特性在管理信息系统的设计中被广泛使用,CODE128码是应用最广泛的条码码制之一。

CODE128码是1981年引入的一种高密度条码,CODE128 码可表示从 ASCII 0 到ASCII 127 共128个字符,故称128码。其中包含了数字、字母和符号字符。

特点:
●可表示高密度数据和字符串;
●每个字符由3个条、3个空、11个单元构成,字符串可变长;
●符号内含校验码;
●有三种不同的版本:A(数字、大写字母、控制字符)B(数字、大小字母、字符)C(双位数字)
CODE128A:标准数字和大写字母,控制符,特殊字符
CODE128B:标准数字和大写字母,小写字母,特殊字符
CODE128C:[00]-[99]的数字对集合,共100个
●可用128个字符分别在A、B或C三个字符串集合中。

在这里插入图片描述

构成:
一个Code 128条形码由六部分组成。
1、空白区域
2、起始标记
3、数据区
4、校验符
5、终止符
6、空白区域
Code 128条码指定相互间隔的3个条形和3个空白(共六个单元)代表一个字符,每个字符由一个条开始,以一个空结束。 在条形码字体中,最后一个条形通常与终止符一起组合成一个更宽的终止符。

Code 128码与Code 39码有很多的相近性,都广泛运用在企业内部管理、生产流程、物流控制系统方面。不同的在于Code 128比Code 39能表现更多的字符,单位长度里的编码密度更高。当单位长度里不能容下Code 39编码或编码字符超出了Code 39的限制时,就可选择Code 128来编码。所以Code 128比Code 39更具灵活性。

由于CODE128码可表示较全面的字符(数字、字母和符号),在同样长度的条码中可容纳的字符长度较长(高密度),条码长度与字符串长度无明显的敏感性,所以CODE128码是企业内部管理系统最为广泛使用的条码码制。

  protected boolean[] encode(String contents, Map<EncodeHintType,?> hints) {
    int length = contents.length();
    // 检查长度
    if (length < 1 || length > 80) {
      throw new IllegalArgumentException(
          "Contents length should be between 1 and 80 characters, but got " + length);
    }

    // 检查强制代码集提示。
    int forcedCodeSet = -1;
    if (hints != null && hints.containsKey(EncodeHintType.FORCE_CODE_SET)) {
      String codeSetHint = hints.get(EncodeHintType.FORCE_CODE_SET).toString();
      switch (codeSetHint) {
        case "A":
          forcedCodeSet = CODE_CODE_A;
          break;
        case "B":
          forcedCodeSet = CODE_CODE_B;
          break;
        case "C":
          forcedCodeSet = CODE_CODE_C;
          break;
        default:
          throw new IllegalArgumentException("Unsupported code set hint: " + codeSetHint);
      }
    }

Codabar

库德巴条形码( Codabar):也称“血库用码”,可表示数字0-9,字符$、+、-,还有只能用作起始和终止符的a、b、c、d四个字符,空白区比窄条宽10倍,非连续性条形码,每个字符表示为4条3空,条形码长度可变,没有校验位,主要应用于血站的献血员管理和血库管理,也可作物料管理、图书馆、机场包裹发送中。

  public boolean[] encode(String contents) {

    if (contents.length() < 2) {
      // 无法有开始/结束保护,因此暂时添加默认保护
      contents = DEFAULT_GUARD + contents + DEFAULT_GUARD;
    } else {
      // 验证输入并计算解码长度。
      char firstChar = Character.toUpperCase(contents.charAt(0));
      char lastChar = Character.toUpperCase(contents.charAt(contents.length() - 1));
      boolean startsNormal = CodaBarReader.arrayContains(START_END_CHARS, firstChar);
      boolean endsNormal = CodaBarReader.arrayContains(START_END_CHARS, lastChar);
      boolean startsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, firstChar);
      boolean endsAlt = CodaBarReader.arrayContains(ALT_START_END_CHARS, lastChar);
      if (startsNormal) {
        if (!endsNormal) {
          throw new IllegalArgumentException("Invalid start/end guards: " + contents);
        }
        // 已具有有效的开始/结束
      } else if (startsAlt) {
        if (!endsAlt) {
          throw new IllegalArgumentException("Invalid start/end guards: " + contents);
        }
        // 已具有有效的开始/结束
      } else {
        // 不是从guard开始的
        if (endsNormal || endsAlt) {
          throw new IllegalArgumentException("Invalid start/end guards: " + contents);
        }
        // 否则也不会以guard结尾,所以添加一个默认值
        contents = DEFAULT_GUARD + contents + DEFAULT_GUARD;
      }
    }

    // 起始字符和结束字符分别解码为10个长度。
    int resultLength = 20;
    for (int i = 1; i < contents.length() - 1; i++) {
      if (Character.isDigit(contents.charAt(i)) || contents.charAt(i) == '-' || contents.charAt(i) == '$') {
        resultLength += 9;
      } else if (CodaBarReader.arrayContains(CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED, contents.charAt(i))) {
        resultLength += 10;
      } else {
        throw new IllegalArgumentException("Cannot encode : '" + contents.charAt(i) + '\'');
      }
    }
    // 在每个字符之间放置一个空格。
    resultLength += contents.length() - 1;
  }

ITF

ITF条码,又称交叉二五条码,主要用于运输包装,是印刷条件较差,不允许印刷EAN-13和UPC-A条码时应选用的一种条码。

ITF条码是有别于EAN、UPC条码的另一种形式的条码。在商品运输包装上使用的主要是14位数字字符代表组成的ITF-14条码。

ITF条码是一种连续型、定长、具有自校验功能,并且条、空都表示信息的双向条码。ITF-14条码的条码字符集、条码字符的组成与交插二五码相同。它由矩形保护框、左侧空白区、条码字符、右侧空白区组成.

  public boolean[] encode(String contents) {
    int length = contents.length();
    if (length % 2 != 0) {
      throw new IllegalArgumentException("The length of the input should be even");
    }
    if (length > 80) {
      throw new IllegalArgumentException(
          "Requested contents should be less than 80 digits long, but got " + length);
    }

    checkNumeric(contents);

    boolean[] result = new boolean[9 + 9 * length];
    int pos = appendPattern(result, 0, START_PATTERN, true);
    for (int i = 0; i < length; i += 2) {
      int one = Character.digit(contents.charAt(i), 10);
      int two = Character.digit(contents.charAt(i + 1), 10);
      int[] encoding = new int[10];
      for (int j = 0; j < 5; j++) {
        encoding[2 * j] = PATTERNS[one][j];
        encoding[2 * j + 1] = PATTERNS[two][j];
      }
      pos += appendPattern(result, pos, encoding, true);
    }
    appendPattern(result, pos, END_PATTERN, true);

    return result;
  }

参考资料

CODE39
CODE 93 条码
code128
ITF条码

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ZXing一维/二维 使用文档 样例: System.IO.Stream stmYiWei = new System.IO.MemoryStream(); BitMatrix byteMatrix = new MultiFormatWriter().encode(sCode, BarcodeFormat.CODE_39, 230, 40); toBitmap(byteMatrix).Save(stmYiWei, ImageFormat.Bmp); Byte[] byteYiWei = new byte[stmYiWei.Length]; stmYiWei.Position = 0; stmYiWei.Read(byteYiWei, 0, (int)stmYiWei.Length); //将图片文件流保存为二进制文件以便保存到数据库中 System.IO.Stream stmErWei = new System.IO.MemoryStream(); IDictionary hints = new Dictionary(); hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8"); byteMatrix = new MultiFormatWriter().encode(sTmp, BarcodeFormat.QR_CODE, 200, 200, hints); toBitmap(byteMatrix).Save(stmErWei, ImageFormat.Bmp); Byte[] byteErWei = new byte[stmErWei.Length]; stmErWei.Position = 0; stmErWei.Read(byteErWei, 0, (int)stmErWei.Length); //将图片文件流保存为二进制文件以便保存到数据库中 strSQL = "insert into gdzc_biaoqian( bq_gd_no,bq_yiweima,bq_erweima,bq_us_no) values("; strSQL = strSQL + " @bq_gd_no,@bq_yiweima,@bq_erweima,@bq_us_no)"; SqlCommand commandImage = new SqlCommand(strSQL, connectionImage); commandImage.Parameters.Clear(); commandImage.Parameters.Add("@bq_gd_no", SqlDbType.Int).Value = Convert.ToInt32(sGdzcNo); commandImage.Parameters.Add("@bq_yiweima", SqlDbType.Image).Value = byteYiWei; commandImage.Parameters.Add("@bq_erweima", SqlDbType.Image).Value = byteErWei; commandImage.Parameters.Add("@bq_us_no", SqlDbType.Int).Value = Convert.ToInt32(Session["LoginUserID"]); commandImage.ExecuteNonQuery(); commandImage.Dispose();

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值