日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

聊聊zxing的qrcode

發(fā)布時間:2025/3/15 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 聊聊zxing的qrcode 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。