摘要:序本文主要研究下的的一些代碼。可以看到這里重新計算了輸出的寬度和高度,是取了的寬高兩邊的與輸入參數的目標寬高取最大值。也就是說如果的寬高大于目標的寬高,則以的寬高為準,這種情況下的基本跟輸出的一致。
序
本文主要研究下zxing的qrcode的一些代碼。
mavenQRCodeWritercom.google.zxing core 3.3.1 com.google.zxing javase 3.3.1
core-3.3.1-sources.jar!/com/google/zxing/qrcode/QRCodeWriter.java
QRCodeWriter的encode方法進行編碼,轉換為BitMatrix
@Override public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, MapQRCodehints) 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); }
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; } @Override public String toString() { StringBuilder result = new StringBuilder(200); result.append("<< "); result.append(" mode: "); result.append(mode); result.append(" ecLevel: "); result.append(ecLevel); result.append(" version: "); result.append(version); result.append(" maskPattern: "); result.append(maskPattern); if (matrix == null) { result.append(" matrix: null "); } else { result.append(" matrix: "); result.append(matrix); } result.append(">> "); 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而來
Encodercore/3.3.1/core-3.3.1-sources.jar!/com/google/zxing/qrcode/encoder/Encoder.java
public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, Maphints) throws WriterException { // Determine what character encoding has been specified by the caller, if any String 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 applicable if (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 marker appendModeInfo(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 it int numLetters = mode == Mode.BYTE ? dataBits.getSizeInBytes() : content.length(); appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.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 = 196 int numBytes = version.getTotalCodewords(); // getNumECBytes = 130 Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); int numEcBytes = ecBlocks.getTotalECCodewords(); // getNumDataBytes = 196 - 130 = 66 int 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 barcode for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { if (input.get(inputX, inputY) == 1) { output.setRegion(outputX, outputY, multiple, multiple); } } } return output; }
doc這個renderResult根據QRCode信息來構造BitMatrix。可以看到這里重新計算了輸出的寬度和高度,是取了qrcode的寬高+兩邊的quietZone與輸入參數的目標寬高取最大值。也就是說如果qrcode的寬高大于目標的寬高,則以qrcode的寬高為準,這種情況下的quietZone基本跟輸出的一致。
一般而言qrcode的寬高小于目標寬高的話,這種情況下quietZone就跟輸出的不一致,需要經過重新放大,得到的才是最后輸出的padding。
二維碼最大能包含多少信息量?
使用zxing生成和識別二維碼
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67897.html
摘要:序本文主要介紹下的,也就是定位圖案,用于定位一張圖片中二維碼所處的位置。分類分為三類是和的原型,從到共種尺寸。是的改良版本,添加了對齊標記,從到共種尺寸。這里默認有個的概念,不同的對應不同的尺寸大小。最高,,所以最高是的矩陣。 序 本文主要介紹下qrcode的detect position,也就是定位圖案,用于定位一張圖片中二維碼所處的位置。 qrcode分類 QRCode 分為 Mo...
摘要:時間年月日星期五說明本文部分內容均來自慕課網。線性堆疊式二維碼示意圖矩陣式二維碼在一個矩形空間通過黑白像素在矩陣中的不同分布進行編碼。 時間:2017年06月23日星期五說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學示例源碼:無個人學習源碼:https://github.com/zccodere/s... 第一章:二維碼的概念 1-1 二維碼概述...
摘要:最近項目中需要開發生成二維碼的功能,便于宣傳和使用產品,于是便去研究一番,以下是研究的成果使用生成二維碼二維碼測試內容渲染方式有方式兼容和方式計算模式背景顏色二維碼顏色二維碼糾錯級別默認查看源碼可以看出生成的二維碼使用生成二維 最近項目中需要開發生成二維碼的功能,便于宣傳和使用產品,于是便去研究一番,以下是研究的成果 1.使用jquery生成二維碼 ...
閱讀 4365·2021-11-24 10:24
閱讀 1409·2021-11-22 15:22
閱讀 2038·2021-11-17 09:33
閱讀 2428·2021-09-22 15:29
閱讀 515·2019-08-30 15:55
閱讀 1652·2019-08-29 18:42
閱讀 2731·2019-08-29 12:55
閱讀 1772·2019-08-26 13:55