Revamped QrCode.encodeSegments() to add parameters to make a much richer API, in all language versions; updated JavaScript demo script to handle new semantics.
This commit is contained in:
parent
ca7e7a60a7
commit
5692e951dd
|
@ -55,34 +55,34 @@ qrcodegen::QrCode qrcodegen::QrCode::encodeBinary(const std::vector<uint8_t> &da
|
|||
}
|
||||
|
||||
|
||||
qrcodegen::QrCode qrcodegen::QrCode::encodeSegments(const std::vector<QrSegment> &segs, const Ecc &ecl) {
|
||||
qrcodegen::QrCode qrcodegen::QrCode::encodeSegments(const std::vector<QrSegment> &segs, const Ecc &ecl,
|
||||
int minVersion, int maxVersion, int mask, bool boostEcl) {
|
||||
if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7)
|
||||
throw "Invalid value";
|
||||
|
||||
// Find the minimal version number to use
|
||||
int version, dataCapacityBits;
|
||||
for (version = 1; ; version++) { // Increment until the data fits in the QR Code
|
||||
if (version > 40) // All versions could not fit the given data
|
||||
throw "Data too long";
|
||||
dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
|
||||
// Calculate the total number of bits needed at this version number
|
||||
// to encode all the segments (i.e. segment metadata and payloads)
|
||||
int dataUsedBits = 0;
|
||||
for (size_t i = 0; i < segs.size(); i++) {
|
||||
const QrSegment &seg(segs.at(i));
|
||||
if (seg.numChars < 0)
|
||||
throw "Assertion error";
|
||||
int ccbits = seg.mode.numCharCountBits(version);
|
||||
if (seg.numChars >= (1 << ccbits)) {
|
||||
// Segment length value doesn't fit in the length field's bit-width, so fail immediately
|
||||
goto continueOuter;
|
||||
}
|
||||
dataUsedBits += 4 + ccbits + seg.bitLength;
|
||||
}
|
||||
if (dataUsedBits <= dataCapacityBits)
|
||||
int version, dataUsedBits;
|
||||
for (version = minVersion; ; version++) {
|
||||
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
dataUsedBits = QrSegment::getTotalBits(segs, version);
|
||||
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
|
||||
break; // This version number is found to be suitable
|
||||
continueOuter:;
|
||||
if (version >= maxVersion) // All versions in the range could not fit the given data
|
||||
throw "Data too long";
|
||||
}
|
||||
if (dataUsedBits == -1)
|
||||
throw "Assertion error";
|
||||
|
||||
// Increase the error correction level while the data still fits in the current version number
|
||||
const Ecc *newEcl = &ecl;
|
||||
if (boostEcl) {
|
||||
if (dataUsedBits <= getNumDataCodewords(version, Ecc::MEDIUM ) * 8) newEcl = &Ecc::MEDIUM ;
|
||||
if (dataUsedBits <= getNumDataCodewords(version, Ecc::QUARTILE) * 8) newEcl = &Ecc::QUARTILE;
|
||||
if (dataUsedBits <= getNumDataCodewords(version, Ecc::HIGH ) * 8) newEcl = &Ecc::HIGH ;
|
||||
}
|
||||
|
||||
// Create the data bit string by concatenating all segments
|
||||
int dataCapacityBits = getNumDataCodewords(version, *newEcl) * 8;
|
||||
BitBuffer bb;
|
||||
for (size_t i = 0; i < segs.size(); i++) {
|
||||
const QrSegment &seg(segs.at(i));
|
||||
|
@ -102,7 +102,7 @@ qrcodegen::QrCode qrcodegen::QrCode::encodeSegments(const std::vector<QrSegment>
|
|||
throw "Assertion error";
|
||||
|
||||
// Create the QR Code symbol
|
||||
return QrCode(version, ecl, bb.getBytes(), -1);
|
||||
return QrCode(version, *newEcl, bb.getBytes(), mask);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -83,13 +83,14 @@ public:
|
|||
|
||||
|
||||
/*
|
||||
* Returns a QR Code symbol representing the given data segments at the given error
|
||||
* correction level. The smallest possible QR Code version is automatically chosen for the output.
|
||||
* Returns a QR Code symbol representing the specified data segments with the specified encoding parameters.
|
||||
* The smallest possible QR Code version within the specified range is automatically chosen for the output.
|
||||
* This function allows the user to create a custom sequence of segments that switches
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
static QrCode encodeSegments(const std::vector<QrSegment> &segs, const Ecc &ecl);
|
||||
static QrCode encodeSegments(const std::vector<QrSegment> &segs, const Ecc &ecl,
|
||||
int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* Software.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include "BitBuffer.hpp"
|
||||
#include "QrSegment.hpp"
|
||||
|
||||
|
@ -128,6 +129,22 @@ qrcodegen::QrSegment::QrSegment(const Mode &md, int numCh, const std::vector<uin
|
|||
}
|
||||
|
||||
|
||||
int qrcodegen::QrSegment::getTotalBits(const std::vector<QrSegment> &segs, int version) {
|
||||
if (version < 1 || version > 40)
|
||||
throw "Version number out of range";
|
||||
int result = 0;
|
||||
for (size_t i = 0; i < segs.size(); i++) {
|
||||
const QrSegment &seg(segs.at(i));
|
||||
int ccbits = seg.mode.numCharCountBits(version);
|
||||
// Fail if segment length value doesn't fit in the length field's bit-width
|
||||
if (seg.numChars >= (1 << ccbits))
|
||||
return -1;
|
||||
result += 4 + ccbits + seg.bitLength;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool qrcodegen::QrSegment::isAlphanumeric(const char *text) {
|
||||
for (; *text != '\0'; text++) {
|
||||
char c = *text;
|
||||
|
|
|
@ -151,6 +151,10 @@ public:
|
|||
QrSegment(const Mode &md, int numCh, const std::vector<uint8_t> &b, int bitLen);
|
||||
|
||||
|
||||
// Package-private helper function.
|
||||
static int getTotalBits(const std::vector<QrSegment> &segs, int version);
|
||||
|
||||
|
||||
/*---- Constant ----*/
|
||||
private:
|
||||
|
||||
|
|
|
@ -76,49 +76,66 @@ public final class QrCode {
|
|||
|
||||
|
||||
/**
|
||||
* Returns a QR Code symbol representing the specified data segments at the specified error
|
||||
* correction level. The smallest possible QR Code version is automatically chosen for the output.
|
||||
* Returns a QR Code symbol representing the specified data segments at the specified error correction
|
||||
* level or higher. The smallest possible QR Code version is automatically chosen for the output.
|
||||
* <p>This function allows the user to create a custom sequence of segments that switches
|
||||
* 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.</p>
|
||||
* @param segs the segments to encode
|
||||
* @param ecl the error correction level to use
|
||||
* @param ecl the error correction level to use (will be boosted)
|
||||
* @return a QR Code representing the segments
|
||||
* @throws NullPointerException if the list of segments, a segment, or the error correction level is {@code null}
|
||||
* @throws IllegalArgumentException if the data fails to fit in the largest version QR Code, which means it is too long
|
||||
* @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) {
|
||||
return encodeSegments(segs, ecl, 1, 40, -1, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a QR Code symbol representing the specified data segments with the specified encoding parameters.
|
||||
* The smallest possible QR Code version within the specified range is automatically chosen for the output.
|
||||
* <p>This function allows the user to create a custom sequence of segments that switches
|
||||
* 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.</p>
|
||||
* @param segs the segments to encode
|
||||
* @param ecl the error correction level to use (may be boosted)
|
||||
* @param minVersion the minimum allowed version of the QR symbol (at least 1)
|
||||
* @param maxVersion the maximum allowed version of the QR symbol (at most 40)
|
||||
* @param mask the mask pattern to use, which is either -1 for automatic choice or from 0 to 7 for fixed choice
|
||||
* @param boostEcl increases the error correction level if it can be done without increasing the version number
|
||||
* @return a QR Code representing the segments
|
||||
* @throws NullPointerException if the list of segments, a segment, or the error correction level is {@code null}
|
||||
* @throws IllegalArgumentException if 1 ≤ minVersion ≤ maxVersion ≤ 40 is violated, or if mask
|
||||
* < −1 or mask > 7, or if the data is too long to fit in a QR Code at maxVersion at the ECL
|
||||
*/
|
||||
public static QrCode encodeSegments(List<QrSegment> segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) {
|
||||
if (segs == null || ecl == null)
|
||||
throw new NullPointerException();
|
||||
if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7)
|
||||
throw new IllegalArgumentException("Invalid value");
|
||||
|
||||
// Find the minimal version number to use
|
||||
int version, dataCapacityBits;
|
||||
outer:
|
||||
for (version = 1; ; version++) { // Increment until the data fits in the QR Code
|
||||
if (version > 40) // All versions could not fit the given data
|
||||
throw new IllegalArgumentException("Data too long");
|
||||
dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
|
||||
// Calculate the total number of bits needed at this version number
|
||||
// to encode all the segments (i.e. segment metadata and payloads)
|
||||
int dataUsedBits = 0;
|
||||
for (QrSegment seg : segs) {
|
||||
if (seg == null)
|
||||
throw new NullPointerException();
|
||||
if (seg.numChars < 0)
|
||||
throw new AssertionError();
|
||||
int ccbits = seg.mode.numCharCountBits(version);
|
||||
if (seg.numChars >= (1 << ccbits)) {
|
||||
// Segment length value doesn't fit in the length field's bit-width, so fail immediately
|
||||
continue outer;
|
||||
}
|
||||
dataUsedBits += 4 + ccbits + seg.bitLength;
|
||||
}
|
||||
if (dataUsedBits <= dataCapacityBits)
|
||||
int version, dataUsedBits;
|
||||
for (version = minVersion; ; version++) {
|
||||
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
dataUsedBits = QrSegment.getTotalBits(segs, version);
|
||||
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
|
||||
break; // This version number is found to be suitable
|
||||
if (version >= maxVersion) // All versions in the range could not fit the given data
|
||||
throw new IllegalArgumentException("Data too long");
|
||||
}
|
||||
if (dataUsedBits == -1)
|
||||
throw new AssertionError();
|
||||
|
||||
// Increase the error correction level while the data still fits in the current version number
|
||||
for (Ecc newEcl : Ecc.values()) {
|
||||
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
|
||||
ecl = newEcl;
|
||||
}
|
||||
|
||||
// Create the data bit string by concatenating all segments
|
||||
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
|
||||
BitBuffer bb = new BitBuffer();
|
||||
for (QrSegment seg : segs) {
|
||||
bb.appendBits(seg.mode.modeBits, 4);
|
||||
|
@ -137,7 +154,7 @@ public final class QrCode {
|
|||
throw new AssertionError();
|
||||
|
||||
// Create the QR Code symbol
|
||||
return new QrCode(version, ecl, bb.getBytes(), -1);
|
||||
return new QrCode(version, ecl, bb.getBytes(), mask);
|
||||
}
|
||||
|
||||
|
||||
|
@ -732,7 +749,8 @@ public final class QrCode {
|
|||
* Represents the error correction level used in a QR Code symbol.
|
||||
*/
|
||||
public enum Ecc {
|
||||
// Constants declared in ascending order of error protection.
|
||||
// These enum constants must be declared in ascending order of error protection,
|
||||
// for the sake of the implicit ordinal() method and values() function.
|
||||
LOW(1), MEDIUM(0), QUARTILE(3), HIGH(2);
|
||||
|
||||
// In the range 0 to 3 (unsigned 2-bit integer).
|
||||
|
|
|
@ -186,6 +186,27 @@ public final class QrSegment {
|
|||
}
|
||||
|
||||
|
||||
// Package-private helper function.
|
||||
static int getTotalBits(List<QrSegment> segs, int version) {
|
||||
if (segs == null)
|
||||
throw new NullPointerException();
|
||||
if (version < 1 || version > 40)
|
||||
throw new IllegalArgumentException("Version number out of range");
|
||||
|
||||
int result = 0;
|
||||
for (QrSegment seg : segs) {
|
||||
if (seg == null)
|
||||
throw new NullPointerException();
|
||||
int ccbits = seg.mode.numCharCountBits(version);
|
||||
// Fail if segment length value doesn't fit in the length field's bit-width
|
||||
if (seg.numChars >= (1 << ccbits))
|
||||
return -1;
|
||||
result += 4 + ccbits + seg.bitLength;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*---- Constants ----*/
|
||||
|
||||
/** Can test whether a string is encodable in numeric mode (such as by using {@link #makeNumeric(String)}). */
|
||||
|
|
|
@ -88,7 +88,8 @@ function redrawQrCode() {
|
|||
segs.forEach(function(seg) {
|
||||
databits += 4 + seg.getMode().numCharCountBits(qr.getVersion()) + seg.getBits().length;
|
||||
});
|
||||
stats += ", data bits = " + databits + ".";
|
||||
stats += ", error correction = level " + "LMQH".charAt(qr.getErrorCorrectionLevel().ordinal) + ", ";
|
||||
stats += "data bits = " + databits + ".";
|
||||
var elem = document.getElementById("statistics-output");
|
||||
while (elem.firstChild != null)
|
||||
elem.removeChild(elem.firstChild);
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
* Module "qrcodegen". Public members inside this namespace:
|
||||
* - Function encodeText(str text, QrCode.Ecc ecl) -> QrCode
|
||||
* - Function encodeBinary(list<int> data, QrCode.Ecc ecl) -> QrCode
|
||||
* - Function encodeSegments(list<QrSegment> segs, QrCode.Ecc ecl) -> QrCode
|
||||
* - Function encodeSegments(list<QrSegment> segs, QrCode.Ecc ecl,
|
||||
* int minVersion=1, int maxVersion=40, mask=-1, boostEcl=true) -> QrCode
|
||||
* - Class QrCode:
|
||||
* - Constructor QrCode(QrCode qr, int mask)
|
||||
* - Constructor QrCode(list<int> bytes, int mask, int version, QrCode.Ecc ecl)
|
||||
|
@ -84,40 +85,39 @@ var qrcodegen = new function() {
|
|||
|
||||
|
||||
/*
|
||||
* Returns a QR Code symbol representing the given data segments at the given error
|
||||
* correction level. The smallest possible QR Code version is automatically chosen for the output.
|
||||
* Returns a QR Code symbol representing the specified data segments with the specified encoding parameters.
|
||||
* The smallest possible QR Code version within the specified range is automatically chosen for the output.
|
||||
* This function allows the user to create a custom sequence of segments that switches
|
||||
* 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.
|
||||
* 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.encodeSegments = function(segs, ecl) {
|
||||
this.encodeSegments = function(segs, ecl, minVersion, maxVersion, mask, boostEcl) {
|
||||
if (minVersion == undefined) minVersion = 1;
|
||||
if (maxVersion == undefined) maxVersion = 40;
|
||||
if (mask == undefined) mask = -1;
|
||||
if (boostEcl == undefined) boostEcl = true;
|
||||
if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7)
|
||||
throw "Invalid value";
|
||||
|
||||
// Find the minimal version number to use
|
||||
var version, dataCapacityBits;
|
||||
outer:
|
||||
for (version = 1; ; version++) { // Increment until the data fits in the QR Code
|
||||
if (version > 40) // All versions could not fit the given data
|
||||
throw "Data too long";
|
||||
dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
|
||||
// Calculate the total number of bits needed at this version number
|
||||
// to encode all the segments (i.e. segment metadata and payloads)
|
||||
var dataUsedBits = 0;
|
||||
for (var i = 0; i < segs.length; i++) {
|
||||
var seg = segs[i];
|
||||
if (seg.numChars < 0)
|
||||
throw "Assertion error";
|
||||
var ccbits = seg.getMode().numCharCountBits(version);
|
||||
if (seg.getNumChars() >= (1 << ccbits)) {
|
||||
// Segment length value doesn't fit in the length field's bit-width, so fail immediately
|
||||
continue outer;
|
||||
}
|
||||
dataUsedBits += 4 + ccbits + seg.getBits().length;
|
||||
}
|
||||
if (dataUsedBits <= dataCapacityBits)
|
||||
var version, dataUsedBits;
|
||||
for (version = minVersion; ; version++) {
|
||||
var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
dataUsedBits = this.QrSegment.getTotalBits(segs, version);
|
||||
if (dataUsedBits != null && dataUsedBits <= dataCapacityBits)
|
||||
break; // This version number is found to be suitable
|
||||
if (version >= maxVersion) // All versions in the range could not fit the given data
|
||||
throw "Data too long";
|
||||
}
|
||||
|
||||
// Increase the error correction level while the data still fits in the current version number
|
||||
[this.QrCode.Ecc.MEDIUM, this.QrCode.Ecc.QUARTILE, this.QrCode.Ecc.HIGH].forEach(function(newEcl) {
|
||||
if (boostEcl && dataUsedBits <= QrCode.getNumDataCodewords(version, newEcl) * 8)
|
||||
ecl = newEcl;
|
||||
});
|
||||
|
||||
// Create the data bit string by concatenating all segments
|
||||
var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8;
|
||||
var bb = new BitBuffer();
|
||||
segs.forEach(function(seg) {
|
||||
bb.appendBits(seg.getMode().getModeBits(), 4);
|
||||
|
@ -136,7 +136,7 @@ var qrcodegen = new function() {
|
|||
throw "Assertion error";
|
||||
|
||||
// Create the QR Code symbol
|
||||
return new this.QrCode(bb.getBytes(), -1, version, ecl);
|
||||
return new this.QrCode(bb.getBytes(), mask, version, ecl);
|
||||
};
|
||||
|
||||
|
||||
|
@ -775,6 +775,21 @@ var qrcodegen = new function() {
|
|||
return [this.makeBytes(toUtf8ByteArray(text))];
|
||||
};
|
||||
|
||||
// Package-private helper function.
|
||||
this.QrSegment.getTotalBits = function(segs, version) {
|
||||
if (version < 1 || version > 40)
|
||||
throw "Version number out of range";
|
||||
var result = 0;
|
||||
segs.forEach(function(seg) {
|
||||
var ccbits = seg.getMode().numCharCountBits(version);
|
||||
// Fail if segment length value doesn't fit in the length field's bit-width
|
||||
if (seg.getNumChars() >= (1 << ccbits))
|
||||
return null;
|
||||
result += 4 + ccbits + seg.getBits().length;
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
/*-- Constants --*/
|
||||
|
||||
var QrSegment = {}; // Private object to assign properties to
|
||||
|
|
|
@ -29,7 +29,8 @@ import itertools, re, sys
|
|||
Public members inside this module "qrcodegen":
|
||||
- Function encode_text(str text, QrCode.Ecc ecl) -> QrCode
|
||||
- Function encode_binary(bytes data, QrCode.Ecc ecl) -> QrCode
|
||||
- Function encode_segments(list<QrSegment> segs, QrCode.Ecc ecl) -> QrCode
|
||||
- Function encode_segments(list<QrSegment> segs, QrCode.Ecc ecl,
|
||||
int minversion=1, int maxversion=40, mask=-1, boostecl=true) -> QrCode
|
||||
- Class QrCode:
|
||||
- Constructor QrCode(QrCode qr, int mask)
|
||||
- Constructor QrCode(bytes bytes, int mask, int version, QrCode.Ecc ecl)
|
||||
|
@ -77,35 +78,34 @@ def encode_binary(data, ecl):
|
|||
return QrCode.encode_segments([QrSegment.make_bytes(data)], ecl)
|
||||
|
||||
|
||||
def encode_segments(segs, ecl):
|
||||
"""Returns a QR Code symbol representing the given data segments at the given error
|
||||
correction level. The smallest possible QR Code version is automatically chosen for the output.
|
||||
def encode_segments(segs, ecl, minversion=1, maxversion=40, mask=-1, boostecl=True):
|
||||
"""Returns a QR Code symbol representing the specified data segments with the specified encoding parameters.
|
||||
The smallest possible QR Code version within the specified range is automatically chosen for the output.
|
||||
This function allows the user to create a custom sequence of segments that switches
|
||||
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."""
|
||||
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."""
|
||||
|
||||
if not 1 <= minversion <= maxversion <= 40 or not -1 <= mask <= 7:
|
||||
raise ValueError("Invalid value")
|
||||
|
||||
# Find the minimal version number to use
|
||||
for version in itertools.count(1): # Increment until the data fits in the QR Code
|
||||
if version > 40: # All versions could not fit the given data
|
||||
raise ValueError("Data too long")
|
||||
for version in range(minversion, maxversion + 1):
|
||||
datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8 # Number of data bits available
|
||||
|
||||
# Calculate the total number of bits needed at this version number
|
||||
# to encode all the segments (i.e. segment metadata and payloads)
|
||||
datausedbits = 0
|
||||
for seg in segs:
|
||||
if seg.get_num_chars() < 0:
|
||||
raise AssertionError()
|
||||
ccbits = seg.get_mode().num_char_count_bits(version)
|
||||
if seg.get_num_chars() >= (1 << ccbits):
|
||||
# Segment length value doesn't fit in the length field's bit-width, so fail immediately
|
||||
break
|
||||
datausedbits += 4 + ccbits + len(seg.get_bits())
|
||||
else: # If the loop above did not break
|
||||
if datausedbits <= datacapacitybits:
|
||||
break # This version number is found to be suitable
|
||||
datausedbits = QrSegment.get_total_bits(segs, version)
|
||||
if datausedbits is not None and datausedbits <= datacapacitybits:
|
||||
break # This version number is found to be suitable
|
||||
if version >= maxversion: # All versions in the range could not fit the given data
|
||||
raise ValueError("Data too long")
|
||||
if datausedbits is None:
|
||||
raise AssertionError()
|
||||
|
||||
# Increase the error correction level while the data still fits in the current version number
|
||||
for newecl in (QrCode.Ecc.MEDIUM, QrCode.Ecc.QUARTILE, QrCode.Ecc.HIGH):
|
||||
if boostecl and datausedbits <= QrCode._get_num_data_codewords(version, newecl) * 8:
|
||||
ecl = newecl
|
||||
|
||||
# Create the data bit string by concatenating all segments
|
||||
datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8
|
||||
bb = _BitBuffer()
|
||||
for seg in segs:
|
||||
bb.append_bits(seg.get_mode().get_mode_bits(), 4)
|
||||
|
@ -124,7 +124,7 @@ def encode_segments(segs, ecl):
|
|||
assert bb.bit_length() % 8 == 0
|
||||
|
||||
# Create the QR Code symbol
|
||||
return QrCode(datacodewords=bb.get_bytes(), mask=-1, version=version, errcorlvl=ecl)
|
||||
return QrCode(None, bb.get_bytes(), mask, version, ecl)
|
||||
|
||||
|
||||
|
||||
|
@ -686,6 +686,21 @@ class QrSegment(object):
|
|||
return list(self._bitdata) # Defensive copy
|
||||
|
||||
|
||||
# Package-private helper function.
|
||||
@staticmethod
|
||||
def get_total_bits(segs, version):
|
||||
if not 1 <= version <= 40:
|
||||
raise ValueError("Version number out of range")
|
||||
result = 0
|
||||
for seg in segs:
|
||||
ccbits = seg.get_mode().num_char_count_bits(version)
|
||||
# Fail if segment length value doesn't fit in the length field's bit-width
|
||||
if seg.get_num_chars() >= (1 << ccbits):
|
||||
return None
|
||||
result += 4 + ccbits + len(seg.get_bits())
|
||||
return result
|
||||
|
||||
|
||||
# -- Constants --
|
||||
|
||||
# Can test whether a string is encodable in numeric mode (such as by using make_numeric())
|
||||
|
|
Loading…
Reference in New Issue