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:
Nayuki Minase
2016-04-16 03:53:58 +00:00
parent ca7e7a60a7
commit 5692e951dd
9 changed files with 205 additions and 113 deletions
+24 -24
View File
@@ -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);
}
+6 -5
View File
@@ -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
+17
View File
@@ -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;
+4
View File
@@ -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: