Added integer constants for QR Code min/max version numbers, made use of new constants in library and example applications, in all language versions except C.

This commit is contained in:
Project Nayuki 2017-10-23 04:42:53 +00:00
parent 6f5eccf2fc
commit 5a5626edb2
12 changed files with 96 additions and 56 deletions

View File

@ -73,7 +73,7 @@ QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl, QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
int minVersion, int maxVersion, int mask, bool boostEcl) { int minVersion, int maxVersion, int mask, bool boostEcl) {
if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7) if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
throw "Invalid value"; throw "Invalid value";
// Find the minimal version number to use // Find the minimal version number to use
@ -122,13 +122,13 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int mask) : QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int mask) :
// Initialize fields // Initialize fields
version(ver), version(ver),
size(1 <= ver && ver <= 40 ? ver * 4 + 17 : -1), // Avoid signed overflow undefined behavior size(MIN_VERSION <= ver && ver <= MAX_VERSION ? ver * 4 + 17 : -1), // Avoid signed overflow undefined behavior
errorCorrectionLevel(ecl), errorCorrectionLevel(ecl),
modules(size, vector<bool>(size)), // Entirely white grid modules(size, vector<bool>(size)), // Entirely white grid
isFunction(size, vector<bool>(size)) { isFunction(size, vector<bool>(size)) {
// Check arguments // Check arguments
if (ver < 1 || ver > 40 || mask < -1 || mask > 7) if (ver < MIN_VERSION || ver > MAX_VERSION || mask < -1 || mask > 7)
throw "Value out of range"; throw "Value out of range";
// Draw function patterns, draw all codewords, do masking // Draw function patterns, draw all codewords, do masking
@ -497,7 +497,7 @@ long QrCode::getPenaltyScore() const {
vector<int> QrCode::getAlignmentPatternPositions(int ver) { vector<int> QrCode::getAlignmentPatternPositions(int ver) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw "Version number out of range"; throw "Version number out of range";
else if (ver == 1) else if (ver == 1)
return vector<int>(); return vector<int>();
@ -520,7 +520,7 @@ vector<int> QrCode::getAlignmentPatternPositions(int ver) {
int QrCode::getNumRawDataModules(int ver) { int QrCode::getNumRawDataModules(int ver) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw "Version number out of range"; throw "Version number out of range";
int result = (16 * ver + 128) * ver + 64; int result = (16 * ver + 128) * ver + 64;
if (ver >= 2) { if (ver >= 2) {
@ -534,7 +534,7 @@ int QrCode::getNumRawDataModules(int ver) {
int QrCode::getNumDataCodewords(int ver, Ecc ecl) { int QrCode::getNumDataCodewords(int ver, Ecc ecl) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw "Version number out of range"; throw "Version number out of range";
return getNumRawDataModules(ver) / 8 return getNumRawDataModules(ver) / 8
- ECC_CODEWORDS_PER_BLOCK[ecl.getOrdinal()][ver] - ECC_CODEWORDS_PER_BLOCK[ecl.getOrdinal()][ver]

View File

@ -97,6 +97,13 @@ class QrCode final {
/*---- Public constants ----*/
public: static constexpr int MIN_VERSION = 1;
public: static constexpr int MAX_VERSION = 40;
/*---- Instance fields ----*/ /*---- Instance fields ----*/
// Immutable scalar parameters // Immutable scalar parameters

View File

@ -164,8 +164,8 @@ static void doSegmentDemo() {
static void doMaskDemo() { static void doMaskDemo() {
// Project Nayuki URL // Project Nayuki URL
std::vector<QrSegment> segs0 = QrSegment::makeSegments("https://www.nayuki.io/"); std::vector<QrSegment> segs0 = QrSegment::makeSegments("https://www.nayuki.io/");
printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, 1, 40, -1, true)); // Automatic mask printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, -1, true)); // Automatic mask
printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, 1, 40, 3, true)); // Force mask 3 printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 3, true)); // Force mask 3
// Chinese text as UTF-8 // Chinese text as UTF-8
std::vector<QrSegment> segs1 = QrSegment::makeSegments( std::vector<QrSegment> segs1 = QrSegment::makeSegments(
@ -176,10 +176,10 @@ static void doMaskDemo() {
"\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4" "\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4"
"\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7" "\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7"
"\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB"); "\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB");
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, 1, 40, 0, true)); // Force mask 0 printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 0, true)); // Force mask 0
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, 1, 40, 1, true)); // Force mask 1 printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 1, true)); // Force mask 1
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, 1, 40, 5, true)); // Force mask 5 printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 5, true)); // Force mask 5
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, 1, 40, 7, true)); // Force mask 7 printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 7, true)); // Force mask 7
} }

View File

@ -91,7 +91,7 @@ public final class QrCode {
* @throws IllegalArgumentException if the data is too long to fit in the largest version QR Code at the ECL * @throws IllegalArgumentException if the data is too long to fit in the largest version QR Code at the ECL
*/ */
public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl) { public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl) {
return encodeSegments(segs, ecl, 1, 40, -1, true); return encodeSegments(segs, ecl, MIN_VERSION, MAX_VERSION, -1, true);
} }
@ -115,7 +115,7 @@ public final class QrCode {
public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) { public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) {
Objects.requireNonNull(segs); Objects.requireNonNull(segs);
Objects.requireNonNull(ecl); Objects.requireNonNull(ecl);
if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7) if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
throw new IllegalArgumentException("Invalid value"); throw new IllegalArgumentException("Invalid value");
// Find the minimal version number to use // Find the minimal version number to use
@ -162,6 +162,13 @@ public final class QrCode {
/*---- Public constants ----*/
public static final int MIN_VERSION = 1;
public static final int MAX_VERSION = 40;
/*---- Instance fields ----*/ /*---- Instance fields ----*/
// Public immutable scalar parameters // Public immutable scalar parameters
@ -203,7 +210,7 @@ public final class QrCode {
public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int mask) { public QrCode(int ver, Ecc ecl, byte[] dataCodewords, int mask) {
// Check arguments // Check arguments
Objects.requireNonNull(ecl); Objects.requireNonNull(ecl);
if (ver < 1 || ver > 40 || mask < -1 || mask > 7) if (ver < MIN_VERSION || ver > MAX_VERSION || mask < -1 || mask > 7)
throw new IllegalArgumentException("Value out of range"); throw new IllegalArgumentException("Value out of range");
Objects.requireNonNull(dataCodewords); Objects.requireNonNull(dataCodewords);
@ -630,7 +637,7 @@ public final class QrCode {
// used on both the x and y axes. Each value in the resulting array is in the range [0, 177). // used on both the x and y axes. Each value in the resulting array is in the range [0, 177).
// This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes. // This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes.
private static int[] getAlignmentPatternPositions(int ver) { private static int[] getAlignmentPatternPositions(int ver) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw new IllegalArgumentException("Version number out of range"); throw new IllegalArgumentException("Version number out of range");
else if (ver == 1) else if (ver == 1)
return new int[]{}; return new int[]{};
@ -656,7 +663,7 @@ public final class QrCode {
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
private static int getNumRawDataModules(int ver) { private static int getNumRawDataModules(int ver) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw new IllegalArgumentException("Version number out of range"); throw new IllegalArgumentException("Version number out of range");
int size = ver * 4 + 17; int size = ver * 4 + 17;
@ -681,7 +688,7 @@ public final class QrCode {
// QR Code of the given version number and error correction level, with remainder bits discarded. // QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table. // This stateless pure function could be implemented as a (40*4)-cell lookup table.
static int getNumDataCodewords(int ver, Ecc ecl) { static int getNumDataCodewords(int ver, Ecc ecl) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw new IllegalArgumentException("Version number out of range"); throw new IllegalArgumentException("Version number out of range");
return getNumRawDataModules(ver) / 8 return getNumRawDataModules(ver) / 8
- ECC_CODEWORDS_PER_BLOCK[ecl.ordinal()][ver] - ECC_CODEWORDS_PER_BLOCK[ecl.ordinal()][ver]

View File

@ -161,20 +161,20 @@ public final class QrCodeGeneratorDemo {
// Project Nayuki URL // Project Nayuki URL
segs = QrSegment.makeSegments("https://www.nayuki.io/"); segs = QrSegment.makeSegments("https://www.nayuki.io/");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 1, 40, -1, true); // Automatic mask qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, -1, true); // Automatic mask
writePng(qr.toImage(8, 6), "project-nayuki-automask-QR.png"); writePng(qr.toImage(8, 6), "project-nayuki-automask-QR.png");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, 1, 40, 3, true); // Force mask 3 qr = QrCode.encodeSegments(segs, QrCode.Ecc.HIGH, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 3, true); // Force mask 3
writePng(qr.toImage(8, 6), "project-nayuki-mask3-QR.png"); writePng(qr.toImage(8, 6), "project-nayuki-mask3-QR.png");
// Chinese text as UTF-8 // Chinese text as UTF-8
segs = QrSegment.makeSegments("維基百科Wikipedia聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫"); segs = QrSegment.makeSegments("維基百科Wikipedia聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, 1, 40, 0, true); // Force mask 0 qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 0, true); // Force mask 0
writePng(qr.toImage(10, 3), "unicode-mask0-QR.png"); writePng(qr.toImage(10, 3), "unicode-mask0-QR.png");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, 1, 40, 1, true); // Force mask 1 qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 1, true); // Force mask 1
writePng(qr.toImage(10, 3), "unicode-mask1-QR.png"); writePng(qr.toImage(10, 3), "unicode-mask1-QR.png");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, 1, 40, 5, true); // Force mask 5 qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 5, true); // Force mask 5
writePng(qr.toImage(10, 3), "unicode-mask5-QR.png"); writePng(qr.toImage(10, 3), "unicode-mask5-QR.png");
qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, 1, 40, 7, true); // Force mask 7 qr = QrCode.encodeSegments(segs, QrCode.Ecc.MEDIUM, QrCode.MIN_VERSION, QrCode.MAX_VERSION, 7, true); // Force mask 7
writePng(qr.toImage(10, 3), "unicode-mask7-QR.png"); writePng(qr.toImage(10, 3), "unicode-mask7-QR.png");
} }

View File

@ -67,7 +67,7 @@ public final class QrCodeGeneratorWorker {
int mask = input.nextInt(); int mask = input.nextInt();
int boostEcl = input.nextInt(); int boostEcl = input.nextInt();
if (!(0 <= errCorLvl && errCorLvl <= 3) || !(-1 <= mask && mask <= 7) || (boostEcl >>> 1) != 0 if (!(0 <= errCorLvl && errCorLvl <= 3) || !(-1 <= mask && mask <= 7) || (boostEcl >>> 1) != 0
|| !(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40)) || !(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION))
throw new RuntimeException(); throw new RuntimeException();
// Make segments for encoding // Make segments for encoding

View File

@ -139,8 +139,8 @@ function handleVersionMinMax(which) {
var maxElem = document.getElementById("version-max-input"); var maxElem = document.getElementById("version-max-input");
var minVal = parseInt(minElem.value, 10); var minVal = parseInt(minElem.value, 10);
var maxVal = parseInt(maxElem.value, 10); var maxVal = parseInt(maxElem.value, 10);
minVal = Math.max(Math.min(minVal, 40), 1); minVal = Math.max(Math.min(minVal, qrcodegen.QrCode.MAX_VERSION), qrcodegen.QrCode.MIN_VERSION);
maxVal = Math.max(Math.min(maxVal, 40), 1); maxVal = Math.max(Math.min(maxVal, qrcodegen.QrCode.MAX_VERSION), qrcodegen.QrCode.MIN_VERSION);
if (which == "min" && minVal > maxVal) if (which == "min" && minVal > maxVal)
maxVal = minVal; maxVal = minVal;
else if (which == "max" && maxVal < minVal) else if (which == "max" && maxVal < minVal)

View File

@ -31,6 +31,7 @@
* - Function encodeBinary(list<byte> data, QrCode.Ecc ecl) -> QrCode * - Function encodeBinary(list<byte> data, QrCode.Ecc ecl) -> QrCode
* - Function encodeSegments(list<QrSegment> segs, QrCode.Ecc ecl, * - Function encodeSegments(list<QrSegment> segs, QrCode.Ecc ecl,
* int minVersion=1, int maxVersion=40, mask=-1, boostEcl=true) -> QrCode * int minVersion=1, int maxVersion=40, mask=-1, boostEcl=true) -> QrCode
* - Constants int MIN_VERSION, MAX_VERSION
* - Constructor QrCode(list<int> datacodewords, int mask, int version, QrCode.Ecc ecl) * - Constructor QrCode(list<int> datacodewords, int mask, int version, QrCode.Ecc ecl)
* - Fields int version, size, mask * - Fields int version, size, mask
* - Field QrCode.Ecc errorCorrectionLevel * - Field QrCode.Ecc errorCorrectionLevel
@ -74,7 +75,7 @@ var qrcodegen = new function() {
// Check arguments and handle simple scalar fields // Check arguments and handle simple scalar fields
if (mask < -1 || mask > 7) if (mask < -1 || mask > 7)
throw "Mask value out of range"; throw "Mask value out of range";
if (version < 1 || version > 40) if (version < MIN_VERSION || version > MAX_VERSION)
throw "Version value out of range"; throw "Version value out of range";
var size = version * 4 + 17; var size = version * 4 + 17;
@ -536,11 +537,11 @@ var qrcodegen = new function() {
* This function is considered to be lower level than simply encoding text or binary data. * This function is considered to be lower level than simply encoding text or binary data.
*/ */
this.QrCode.encodeSegments = function(segs, ecl, minVersion, maxVersion, mask, boostEcl) { this.QrCode.encodeSegments = function(segs, ecl, minVersion, maxVersion, mask, boostEcl) {
if (minVersion == undefined) minVersion = 1; if (minVersion == undefined) minVersion = MIN_VERSION;
if (maxVersion == undefined) maxVersion = 40; if (maxVersion == undefined) maxVersion = MAX_VERSION;
if (mask == undefined) mask = -1; if (mask == undefined) mask = -1;
if (boostEcl == undefined) boostEcl = true; if (boostEcl == undefined) boostEcl = true;
if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7) if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
throw "Invalid value"; throw "Invalid value";
// Find the minimal version number to use // Find the minimal version number to use
@ -586,6 +587,14 @@ var qrcodegen = new function() {
}; };
/*---- Public constants for QrCode ----*/
var MIN_VERSION = 1;
var MAX_VERSION = 40;
Object.defineProperty(this.QrCode, "MIN_VERSION", {value:MIN_VERSION});
Object.defineProperty(this.QrCode, "MAX_VERSION", {value:MAX_VERSION});
/*---- Private static helper functions QrCode ----*/ /*---- Private static helper functions QrCode ----*/
var QrCode = {}; // Private object to assign properties to. Not the same object as 'this.QrCode'. var QrCode = {}; // Private object to assign properties to. Not the same object as 'this.QrCode'.
@ -595,7 +604,7 @@ var qrcodegen = new function() {
// used on both the x and y axes. Each value in the resulting sequence is in the range [0, 177). // used on both the x and y axes. Each value in the resulting sequence is in the range [0, 177).
// This stateless pure function could be implemented as table of 40 variable-length lists of integers. // This stateless pure function could be implemented as table of 40 variable-length lists of integers.
QrCode.getAlignmentPatternPositions = function(ver) { QrCode.getAlignmentPatternPositions = function(ver) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw "Version number out of range"; throw "Version number out of range";
else if (ver == 1) else if (ver == 1)
return []; return [];
@ -620,7 +629,7 @@ var qrcodegen = new function() {
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
QrCode.getNumRawDataModules = function(ver) { QrCode.getNumRawDataModules = function(ver) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw "Version number out of range"; throw "Version number out of range";
var result = (16 * ver + 128) * ver + 64; var result = (16 * ver + 128) * ver + 64;
if (ver >= 2) { if (ver >= 2) {
@ -637,7 +646,7 @@ var qrcodegen = new function() {
// QR Code of the given version number and error correction level, with remainder bits discarded. // QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table. // This stateless pure function could be implemented as a (40*4)-cell lookup table.
QrCode.getNumDataCodewords = function(ver, ecl) { QrCode.getNumDataCodewords = function(ver, ecl) {
if (ver < 1 || ver > 40) if (ver < MIN_VERSION || ver > MAX_VERSION)
throw "Version number out of range"; throw "Version number out of range";
return Math.floor(QrCode.getNumRawDataModules(ver) / 8) - return Math.floor(QrCode.getNumRawDataModules(ver) / 8) -
QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] * QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] *
@ -816,7 +825,7 @@ var qrcodegen = new function() {
// Package-private helper function. // Package-private helper function.
this.QrSegment.getTotalBits = function(segs, version) { this.QrSegment.getTotalBits = function(segs, version) {
if (version < 1 || version > 40) if (version < MIN_VERSION || version > MAX_VERSION)
throw "Version number out of range"; throw "Version number out of range";
var result = 0; var result = 0;
for (var i = 0; i < segs.length; i++) { for (var i = 0; i < segs.length; i++) {

View File

@ -31,6 +31,7 @@ This module "qrcodegen", public members:
- Function encode_binary(bytes data, QrCode.Ecc ecl) -> QrCode - Function encode_binary(bytes data, QrCode.Ecc ecl) -> QrCode
- Function encode_segments(list<QrSegment> segs, QrCode.Ecc ecl, - Function encode_segments(list<QrSegment> segs, QrCode.Ecc ecl,
int minversion=1, int maxversion=40, mask=-1, boostecl=true) -> QrCode int minversion=1, int maxversion=40, mask=-1, boostecl=true) -> QrCode
- Constants int MIN_VERSION, MAX_VERSION
- Constructor QrCode(bytes datacodewords, int mask, int version, QrCode.Ecc ecl) - Constructor QrCode(bytes datacodewords, int mask, int version, QrCode.Ecc ecl)
- Method get_version() -> int - Method get_version() -> int
- Method get_size() -> int - Method get_size() -> int
@ -95,7 +96,7 @@ class QrCode(object):
between modes (such as alphanumeric and binary) to encode text more efficiently. between modes (such as alphanumeric and binary) to encode text more efficiently.
This function is considered to be lower level than simply encoding text or binary data.""" This function is considered to be lower level than simply encoding text or binary data."""
if not (1 <= minversion <= maxversion <= 40) or not (-1 <= mask <= 7): if not (QrCode.MIN_VERSION <= minversion <= maxversion <= QrCode.MAX_VERSION) or not (-1 <= mask <= 7):
raise ValueError("Invalid value") raise ValueError("Invalid value")
# Find the minimal version number to use # Find the minimal version number to use
@ -137,6 +138,12 @@ class QrCode(object):
return QrCode(bb.get_bytes(), mask, version, ecl) return QrCode(bb.get_bytes(), mask, version, ecl)
# ---- Public constants ----
MIN_VERSION = 1
MAX_VERSION = 40
# ---- Constructor ---- # ---- Constructor ----
def __init__(self, datacodewords, mask, version, errcorlvl): def __init__(self, datacodewords, mask, version, errcorlvl):
@ -147,7 +154,7 @@ class QrCode(object):
# Check arguments and handle simple scalar fields # Check arguments and handle simple scalar fields
if not (-1 <= mask <= 7): if not (-1 <= mask <= 7):
raise ValueError("Mask value out of range") raise ValueError("Mask value out of range")
if not (1 <= version <= 40): if not (QrCode.MIN_VERSION <= version <= QrCode.MAX_VERSION):
raise ValueError("Version value out of range") raise ValueError("Version value out of range")
if not isinstance(errcorlvl, QrCode.Ecc): if not isinstance(errcorlvl, QrCode.Ecc):
raise TypeError("QrCode.Ecc expected") raise TypeError("QrCode.Ecc expected")
@ -480,7 +487,7 @@ class QrCode(object):
"""Returns a sequence of positions of the alignment patterns in ascending order. These positions are """Returns a sequence of positions of the alignment patterns in ascending order. These positions are
used on both the x and y axes. Each value in the resulting sequence is in the range [0, 177). used on both the x and y axes. Each value in the resulting sequence is in the range [0, 177).
This stateless pure function could be implemented as table of 40 variable-length lists of integers.""" This stateless pure function could be implemented as table of 40 variable-length lists of integers."""
if not (1 <= ver <= 40): if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION):
raise ValueError("Version number out of range") raise ValueError("Version number out of range")
elif ver == 1: elif ver == 1:
return [] return []
@ -504,7 +511,7 @@ class QrCode(object):
"""Returns the number of data bits that can be stored in a QR Code of the given version number, after """Returns the number of data bits that can be stored in a QR Code of the given version number, after
all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.""" The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table."""
if not (1 <= ver <= 40): if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION):
raise ValueError("Version number out of range") raise ValueError("Version number out of range")
result = (16 * ver + 128) * ver + 64 result = (16 * ver + 128) * ver + 64
if ver >= 2: if ver >= 2:
@ -520,7 +527,7 @@ class QrCode(object):
"""Returns the number of 8-bit data (i.e. not error correction) codewords contained in any """Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
QR Code of the given version number and error correction level, with remainder bits discarded. QR Code of the given version number and error correction level, with remainder bits discarded.
This stateless pure function could be implemented as a (40*4)-cell lookup table.""" This stateless pure function could be implemented as a (40*4)-cell lookup table."""
if not (1 <= ver <= 40): if not (QrCode.MIN_VERSION <= ver <= QrCode.MAX_VERSION):
raise ValueError("Version number out of range") raise ValueError("Version number out of range")
return QrCode._get_num_raw_data_modules(ver) // 8 \ return QrCode._get_num_raw_data_modules(ver) // 8 \
- QrCode._ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] \ - QrCode._ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] \
@ -698,7 +705,7 @@ class QrSegment(object):
# Package-private helper function. # Package-private helper function.
@staticmethod @staticmethod
def get_total_bits(segs, version): def get_total_bits(segs, version):
if not (1 <= version <= 40): if not (QrCode.MIN_VERSION <= version <= QrCode.MAX_VERSION):
raise ValueError("Version number out of range") raise ValueError("Version number out of range")
result = 0 result = 0
for seg in segs: for seg in segs:

View File

@ -28,6 +28,8 @@ extern crate qrcodegen;
use qrcodegen::QrCode; use qrcodegen::QrCode;
use qrcodegen::QrCodeEcc; use qrcodegen::QrCodeEcc;
use qrcodegen::QrSegment; use qrcodegen::QrSegment;
use qrcodegen::QrCode_MAX_VERSION;
use qrcodegen::QrCode_MIN_VERSION;
// The main application program. // The main application program.
@ -140,20 +142,20 @@ fn do_segment_demo() {
fn do_mask_demo() { fn do_mask_demo() {
// Project Nayuki URL // Project Nayuki URL
let segs = QrSegment::make_segments(&to_chars("https://www.nayuki.io/")); let segs = QrSegment::make_segments(&to_chars("https://www.nayuki.io/"));
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, 1, 40, None, true).unwrap(); // Automatic mask let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true).unwrap(); // Automatic mask
print_qr(&qr); print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, 1, 40, Some(3), true).unwrap(); // Force mask 3 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::High, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(3), true).unwrap(); // Force mask 3
print_qr(&qr); print_qr(&qr);
// Chinese text as UTF-8 // Chinese text as UTF-8
let segs = QrSegment::make_segments(&to_chars("維基百科Wikipedia聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫")); let segs = QrSegment::make_segments(&to_chars("維基百科Wikipedia聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫"));
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, 1, 40, Some(0), true).unwrap(); // Force mask 0 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(0), true).unwrap(); // Force mask 0
print_qr(&qr); print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, 1, 40, Some(1), true).unwrap(); // Force mask 1 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(1), true).unwrap(); // Force mask 1
print_qr(&qr); print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, 1, 40, Some(5), true).unwrap(); // Force mask 5 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(5), true).unwrap(); // Force mask 5
print_qr(&qr); print_qr(&qr);
let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, 1, 40, Some(7), true).unwrap(); // Force mask 7 let qr = QrCode::encode_segments_advanced(&segs, QrCodeEcc::Medium, QrCode_MIN_VERSION, QrCode_MAX_VERSION, Some(7), true).unwrap(); // Force mask 7
print_qr(&qr); print_qr(&qr);
} }

View File

@ -57,7 +57,9 @@ fn main() {
let mask = read_int(); let mask = read_int();
let boostecl = read_int(); let boostecl = read_int();
assert!(0 <= errcorlvl && errcorlvl <= 3); assert!(0 <= errcorlvl && errcorlvl <= 3);
assert!(1 <= minversion && minversion <= maxversion && maxversion <= 40); assert!((qrcodegen::QrCode_MIN_VERSION as i16) <= minversion
&& minversion <= maxversion
&& maxversion <= (qrcodegen::QrCode_MAX_VERSION as i16));
assert!(-1 <= mask && mask <= 7); assert!(-1 <= mask && mask <= 7);
assert!(boostecl >> 1 == 0); assert!(boostecl >> 1 == 0);

View File

@ -89,7 +89,7 @@ impl QrCode {
// This function is considered to be lower level than simply encoding text or binary data. // This function is considered to be lower level than simply encoding text or binary data.
// Returns a wrapped QrCode if successful, or None if the data is too long to fit in any version at the given ECC level. // Returns a wrapped QrCode if successful, or None if the data is too long to fit in any version at the given ECC level.
pub fn encode_segments(segs: &[QrSegment], ecl: QrCodeEcc) -> Option<QrCode> { pub fn encode_segments(segs: &[QrSegment], ecl: QrCodeEcc) -> Option<QrCode> {
QrCode::encode_segments_advanced(segs, ecl, 1, 40, None, true) QrCode::encode_segments_advanced(segs, ecl, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true)
} }
@ -102,7 +102,7 @@ impl QrCode {
// in any version in the given range at the given ECC level. // in any version in the given range at the given ECC level.
pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc, pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc,
minversion: u8, maxversion: u8, mask: Option<u8>, boostecl: bool) -> Option<QrCode> { minversion: u8, maxversion: u8, mask: Option<u8>, boostecl: bool) -> Option<QrCode> {
assert!(1 <= minversion && minversion <= maxversion && maxversion <= 40, "Invalid value"); assert!(QrCode_MIN_VERSION <= minversion && minversion <= maxversion && maxversion <= QrCode_MAX_VERSION, "Invalid value");
assert!(mask == None || mask.unwrap() <= 7, "Invalid value"); assert!(mask == None || mask.unwrap() <= 7, "Invalid value");
// Find the minimal version number to use // Find the minimal version number to use
@ -170,7 +170,7 @@ impl QrCode {
// should not be invoked directly by the user. To go one level up, see the encode_segments() function. // should not be invoked directly by the user. To go one level up, see the encode_segments() function.
pub fn encode_codewords(ver: u8, ecl: QrCodeEcc, datacodewords: &[u8], mask: Option<u8>) -> QrCode { pub fn encode_codewords(ver: u8, ecl: QrCodeEcc, datacodewords: &[u8], mask: Option<u8>) -> QrCode {
// Check arguments // Check arguments
assert!(1 <= ver && ver <= 40, "Value out of range"); assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Value out of range");
assert!(mask == None || mask.unwrap() <= 7, "Value out of range"); assert!(mask == None || mask.unwrap() <= 7, "Value out of range");
// Initialize fields // Initialize fields
@ -622,7 +622,7 @@ impl QrCode {
// used on both the x and y axes. Each value in the resulting list is in the range [0, 177). // used on both the x and y axes. Each value in the resulting list is in the range [0, 177).
// This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes. // This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes.
fn get_alignment_pattern_positions(ver: u8) -> Vec<i32> { fn get_alignment_pattern_positions(ver: u8) -> Vec<i32> {
assert!(1 <= ver && ver <= 40, "Version number out of range"); assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Version number out of range");
if ver == 1 { if ver == 1 {
vec![] vec![]
} else { } else {
@ -648,7 +648,7 @@ impl QrCode {
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
fn get_num_raw_data_modules(ver: u8) -> usize { fn get_num_raw_data_modules(ver: u8) -> usize {
assert!(1 <= ver && ver <= 40, "Version number out of range"); assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Version number out of range");
let mut result: usize = (16 * (ver as usize) + 128) * (ver as usize) + 64; let mut result: usize = (16 * (ver as usize) + 128) * (ver as usize) + 64;
if ver >= 2 { if ver >= 2 {
let numalign: usize = (ver as usize) / 7 + 2; let numalign: usize = (ver as usize) / 7 + 2;
@ -665,7 +665,7 @@ impl QrCode {
// QR Code of the given version number and error correction level, with remainder bits discarded. // QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table. // This stateless pure function could be implemented as a (40*4)-cell lookup table.
fn get_num_data_codewords(ver: u8, ecl: QrCodeEcc) -> usize { fn get_num_data_codewords(ver: u8, ecl: QrCodeEcc) -> usize {
assert!(1 <= ver && ver <= 40, "Version number out of range"); assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Version number out of range");
QrCode::get_num_raw_data_modules(ver) / 8 QrCode::get_num_raw_data_modules(ver) / 8
- QrCode::table_get(&ECC_CODEWORDS_PER_BLOCK, ver, ecl) - QrCode::table_get(&ECC_CODEWORDS_PER_BLOCK, ver, ecl)
* QrCode::table_get(&NUM_ERROR_CORRECTION_BLOCKS, ver, ecl) * QrCode::table_get(&NUM_ERROR_CORRECTION_BLOCKS, ver, ecl)
@ -674,13 +674,19 @@ impl QrCode {
// Returns an entry from the given table based on the given values. // Returns an entry from the given table based on the given values.
fn table_get(table: &'static [[i8; 41]; 4], ver: u8, ecl: QrCodeEcc) -> usize { fn table_get(table: &'static [[i8; 41]; 4], ver: u8, ecl: QrCodeEcc) -> usize {
assert!(1 <= ver && ver <= 40, "Version number out of range"); assert!(QrCode_MIN_VERSION <= ver && ver <= QrCode_MAX_VERSION, "Version number out of range");
table[ecl.ordinal()][ver as usize] as usize table[ecl.ordinal()][ver as usize] as usize
} }
} }
/*---- Public constants ----*/
pub const QrCode_MIN_VERSION: u8 = 1;
pub const QrCode_MAX_VERSION: u8 = 40;
/*---- Private tables of constants ----*/ /*---- Private tables of constants ----*/
// For use in get_penalty_score(), when evaluating which mask is best. // For use in get_penalty_score(), when evaluating which mask is best.
@ -978,7 +984,7 @@ impl QrSegment {
// Package-private helper function. // Package-private helper function.
fn get_total_bits(segs: &[QrSegment], version: u8) -> Option<usize> { fn get_total_bits(segs: &[QrSegment], version: u8) -> Option<usize> {
assert!(1 <= version && version <= 40, "Version number out of range"); assert!(QrCode_MIN_VERSION <= version && version <= QrCode_MAX_VERSION, "Version number out of range");
let mut result: usize = 0; let mut result: usize = 0;
for seg in segs { for seg in segs {
let ccbits = seg.mode.num_char_count_bits(version); let ccbits = seg.mode.num_char_count_bits(version);