为什么80%的码农都做不了架构师?>>>   

本文主要研究下zxing的qrcode的一些代码。

maven

      <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.1</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.3.1</version></dependency>

QRCodeWriter

core-3.3.1-sources.jar!/com/google/zxing/qrcode/QRCodeWriter.java QRCodeWriter的encode方法进行编码,转换为BitMatrix

  @Overridepublic BitMatrix encode(String contents,BarcodeFormat format,int width,int height,Map<EncodeHintType,?> hints) throws WriterException {if (contents.isEmpty()) {throw new IllegalArgumentException("Found empty contents");}if (format != BarcodeFormat.QR_CODE) {throw new IllegalArgumentException("Can only encode QR_CODE, but got " + format);}if (width < 0 || height < 0) {throw new IllegalArgumentException("Requested dimensions are too small: " + width + 'x' +height);}ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;int quietZone = QUIET_ZONE_SIZE;if (hints != null) {if (hints.containsKey(EncodeHintType.ERROR_CORRECTION)) {errorCorrectionLevel = ErrorCorrectionLevel.valueOf(hints.get(EncodeHintType.ERROR_CORRECTION).toString());}if (hints.containsKey(EncodeHintType.MARGIN)) {quietZone = Integer.parseInt(hints.get(EncodeHintType.MARGIN).toString());}}QRCode code = Encoder.encode(contents, errorCorrectionLevel, hints);return renderResult(code, width, height, quietZone);}

QRCode

core-3.3.1-sources.jar!/com/google/zxing/qrcode/encoder/QRCode.java

public final class QRCode {public static final int NUM_MASK_PATTERNS = 8;private Mode mode;private ErrorCorrectionLevel ecLevel;private Version version;private int maskPattern;private ByteMatrix matrix;public QRCode() {maskPattern = -1;}public Mode getMode() {return mode;}public ErrorCorrectionLevel getECLevel() {return ecLevel;}public Version getVersion() {return version;}public int getMaskPattern() {return maskPattern;}public ByteMatrix getMatrix() {return matrix;}@Overridepublic String toString() {StringBuilder result = new StringBuilder(200);result.append("<<\n");result.append(" mode: ");result.append(mode);result.append("\n ecLevel: ");result.append(ecLevel);result.append("\n version: ");result.append(version);result.append("\n maskPattern: ");result.append(maskPattern);if (matrix == null) {result.append("\n matrix: null\n");} else {result.append("\n matrix:\n");result.append(matrix);}result.append(">>\n");return result.toString();}public void setMode(Mode value) {mode = value;}public void setECLevel(ErrorCorrectionLevel value) {ecLevel = value;}public void setVersion(Version version) {this.version = version;}public void setMaskPattern(int value) {maskPattern = value;}public void setMatrix(ByteMatrix value) {matrix = value;}// Check if "mask_pattern" is valid.public static boolean isValidMaskPattern(int maskPattern) {return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS;}}

是由Encoder类encode而来

Encoder

core/3.3.1/core-3.3.1-sources.jar!/com/google/zxing/qrcode/encoder/Encoder.java

 public static QRCode encode(String content,ErrorCorrectionLevel ecLevel,Map<EncodeHintType,?> hints) throws WriterException {// Determine what character encoding has been specified by the caller, if anyString encoding = DEFAULT_BYTE_MODE_ENCODING;boolean hasEncodingHint = hints != null && hints.containsKey(EncodeHintType.CHARACTER_SET);if (hasEncodingHint) {encoding = hints.get(EncodeHintType.CHARACTER_SET).toString();}// Pick an encoding mode appropriate for the content. Note that this will not attempt to use// multiple modes / segments even if that were more efficient. Twould be nice.Mode mode = chooseMode(content, encoding);// This will store the header information, like mode and// length, as well as "header" segments like an ECI segment.BitArray headerBits = new BitArray();// Append ECI segment if applicableif (mode == Mode.BYTE && (hasEncodingHint || !DEFAULT_BYTE_MODE_ENCODING.equals(encoding))) {CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding);if (eci != null) {appendECI(eci, headerBits);}}// (With ECI in place,) Write the mode markerappendModeInfo(mode, headerBits);// Collect data within the main segment, separately, to count its size if needed. Don't add it to// main payload yet.BitArray dataBits = new BitArray();appendBytes(content, mode, dataBits, encoding);Version version;if (hints != null && hints.containsKey(EncodeHintType.QR_VERSION)) {int versionNumber = Integer.parseInt(hints.get(EncodeHintType.QR_VERSION).toString());version = Version.getVersionForNumber(versionNumber);int bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, version);if (!willFit(bitsNeeded, version, ecLevel)) {throw new WriterException("Data too big for requested version");}} else {version = recommendVersion(ecLevel, mode, headerBits, dataBits);}BitArray headerAndDataBits = new BitArray();headerAndDataBits.appendBitArray(headerBits);// Find "length" of main segment and write itint numLetters = mode == Mode.BYTE ? dataBits.getSizeInBytes() : content.length();appendLengthInfo(numLetters, version, mode, headerAndDataBits);// Put data together into the overall payloadheaderAndDataBits.appendBitArray(dataBits);Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);int numDataBytes = version.getTotalCodewords() - ecBlocks.getTotalECCodewords();// Terminate the bits properly.terminateBits(numDataBytes, headerAndDataBits);// Interleave data bits with error correction code.BitArray finalBits = interleaveWithECBytes(headerAndDataBits,version.getTotalCodewords(),numDataBytes,ecBlocks.getNumBlocks());QRCode qrCode = new QRCode();qrCode.setECLevel(ecLevel);qrCode.setMode(mode);qrCode.setVersion(version);//  Choose the mask pattern and set to "qrCode".int dimension = version.getDimensionForVersion();ByteMatrix matrix = new ByteMatrix(dimension, dimension);int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix);qrCode.setMaskPattern(maskPattern);// Build the matrix and set it to "qrCode".MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix);qrCode.setMatrix(matrix);return qrCode;}

这里重点看Version的这段

    Version version;if (hints != null && hints.containsKey(EncodeHintType.QR_VERSION)) {int versionNumber = Integer.parseInt(hints.get(EncodeHintType.QR_VERSION).toString());version = Version.getVersionForNumber(versionNumber);int bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, version);if (!willFit(bitsNeeded, version, ecLevel)) {throw new WriterException("Data too big for requested version");}} else {version = recommendVersion(ecLevel, mode, headerBits, dataBits);}

这里计算version,同时判断content的大小,是否超出qrcode的容量,超出的话,抛出WriterException("Data too big for requested version")

  • willFit计算方法
/*** @return true if the number of input bits will fit in a code with the specified version and* error correction level.*/private static boolean willFit(int numInputBits, Version version, ErrorCorrectionLevel ecLevel) {// In the following comments, we use numbers of Version 7-H.// numBytes = 196int numBytes = version.getTotalCodewords();// getNumECBytes = 130Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);int numEcBytes = ecBlocks.getTotalECCodewords();// getNumDataBytes = 196 - 130 = 66int numDataBytes = numBytes - numEcBytes;int totalInputBytes = (numInputBits + 7) / 8;return numDataBytes >= totalInputBytes;}

QRCodeWriter.renderResult

// Note that the input matrix uses 0 == white, 1 == black, while the output matrix uses// 0 == black, 255 == white (i.e. an 8 bit greyscale bitmap).private static BitMatrix renderResult(QRCode code, int width, int height, int quietZone) {ByteMatrix input = code.getMatrix();if (input == null) {throw new IllegalStateException();}int inputWidth = input.getWidth();int inputHeight = input.getHeight();int qrWidth = inputWidth + (quietZone * 2);int qrHeight = inputHeight + (quietZone * 2);int outputWidth = Math.max(width, qrWidth);int outputHeight = Math.max(height, qrHeight);int multiple = Math.min(outputWidth / qrWidth, outputHeight / qrHeight);// Padding includes both the quiet zone and the extra white pixels to accommodate the requested// dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone.// If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will// handle all the padding from 100x100 (the actual QR) up to 200x160.int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;int topPadding = (outputHeight - (inputHeight * multiple)) / 2;BitMatrix output = new BitMatrix(outputWidth, outputHeight);for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) {// Write the contents of this row of the barcodefor (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) {if (input.get(inputX, inputY) == 1) {output.setRegion(outputX, outputY, multiple, multiple);}}}return output;}

这个renderResult根据QRCode信息来构造BitMatrix。可以看到这里重新计算了输出的宽度和高度,是取了qrcode的宽高+两边的quietZone与输入参数的目标宽高取最大值。也就是说如果qrcode的宽高大于目标的宽高,则以qrcode的宽高为准,这种情况下的quietZone基本跟输出的一致。

一般而言qrcode的宽高小于目标宽高的话,这种情况下quietZone就跟输出的不一致,需要经过重新放大,得到的才是最后输出的padding。

doc

  • 二维码最大能包含多少信息量?
  • 使用zxing生成和识别二维码

转载于:https://my.oschina.net/go4it/blog/1556912

聊聊zxing的qrcode相关推荐

  1. qrcoder和zxing哪个好_聊聊zxing的qrcode

    序 本文主要研究下zxing的qrcode的一些代码. maven com.google.zxing core 3.3.1 com.google.zxing javase 3.3.1 QRCodeWr ...

  2. zxing 生成 Qrcode (二维码)

    Zxing生成Qrcode 工具类 1.引入依赖 <dependency><groupId>com.google.zxing</groupId><artifa ...

  3. 如何在visual studio下编译zxing cpp,以及zxing c++的使用

    刚开始请允许我发一下牢骚,刚开始学c++,然后,在使用zxing c++解析二维码的时候,需要找资料.但是,我所找的资料都有问题,下载zxing cpp之后,编译的时候各种问题,当时头都大了.而且,网 ...

  4. C++用zxing识别二维码

    zxing 可以从github的官方网站上下载下来,这里提供一个VS 2010编译zxing的静态库工程,编译时注意一点是:zxing的很多不同的文件夹下含有相同名称的源文件,在编译时应该分别设置这些 ...

  5. java创建QRCode二维码的三种方式

    自己在网上看视频学习了下如何使用java创建二维码,感觉还是挺有趣的,有小心思的还可以把秘密存入二维码中噢 视频源网址:http://www.imooc.com/learn/531 点击下载jar包 ...

  6. zxing.net 0.16.8生成二维码,读取二维码,读取多个二维码 c#

    更新到新版本,报错.老版本的函数发现少了很多.把少的文件添加到目录中,发现可以用了. using System.Diagnostics; using System.Text; using ZXing; ...

  7. 生成二维码并将Bitmap保存成图片

    本来项目集成的Zxing Bitmap qrCode = EncodingHandler.createQRCode(shareUrl, DimenUtils.dp2px(105)); 虽然这个类生成的 ...

  8. JAVA生成二维码链接(扫描二维码后进行指定链接跳转)--全网最详细

    需要使用的依赖 <!-- https://mvnrepository.com/artifact/com.google.zxing/core --><dependency>< ...

  9. 批量识别条形码和二维码

    依赖 <dependency><groupId>net.sf.barcode4j</groupId><artifactId>barcode4j-ligh ...

最新文章

  1. 第二十一课.GBDT
  2. JS正则表达式使用方法及示例
  3. fragment中listview触发事件setOnItemClickListener不好使
  4. 金融系列白皮书 |《金融业线上渠道转型的方法与实践》上线
  5. php 0-1,PHP 动态解决0-1背包问题
  6. Storm精华问答 | storm与Hadoop有什么区别?
  7. C#获取网上图片的宽高代码
  8. java 实体类返回大写_解决springboot bean中大写的字段返回变成小写的问题
  9. 安全测试(初测)报告
  10. 达思SQL数据库修复软件升级至 5.0 版本(重要升级支持修复压缩格式的备份文件)
  11. The type of the expression must be an array type but it resolved to ListObj
  12. 现代大学英语精读第二版(第六册)学习笔记(原文及全文翻译)——3 - What Is News?(新闻是什么?)
  13. python 异步爬取必应搜索结果
  14. Unity—Json1
  15. git代码合并了后发现有冲突,我们怎么取消合并?
  16. linux下下载基因组程序,从 NCBI 批量下载基因组的方法
  17. ndarray数组的操作和运算
  18. C语言rot90的头文件,python – np.rot90()破坏了opencv图像
  19. 页面屏蔽backspace键
  20. 开源 java CMS - FreeCMS2.8 评论管理

热门文章

  1. [041] 微信公众帐号开发教程第17篇-应用实例之智能翻译
  2. 编码是件有逻辑的事情
  3. Angularjs切换网站配色模式简单示例2(切换body元素的class)
  4. HDFS查看文件的前几行-后几行-行数
  5. mysql分组失效_请教MySql中使用表子查询时,试着先排序后分组,出现排序失效的原因?...
  6. 手册如何看运放的db_如何处理金属离子与配体之间的配位键?
  7. css书写规范、行高
  8. 大数据技术之kafka (第 3 章 Kafka 架构深入) Kafka 事务
  9. 蒙特卡罗方法介绍( 二)
  10. 2020年小红书美妆行业品牌投放数据报告