port to wince

pull/162/head
hwenb 3 years ago
parent 9ca3dd36aa
commit 3f8bb419d4

@ -1,4 +1,4 @@
/* /*
* QR Code generator demo (C++) * QR Code generator demo (C++)
* *
* Run this command-line program with no arguments. The program computes a bunch of demonstration * Run this command-line program with no arguments. The program computes a bunch of demonstration
@ -24,8 +24,9 @@
* Software. * Software.
*/ */
#define _CRT_SECURE_NO_DEPRECATE
#include <climits> #include <climits>
#include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
@ -33,12 +34,16 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "qrcodegen.hpp" #include "qrcodegen.hpp"
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
using std::uint8_t;
using qrcodegen::QrCode; using qrcodegen::QrCode;
using qrcodegen::QrSegment; using qrcodegen::QrSegment;
#pragma pack(2)// need this, otherwise cant get correct result of sizeof
#pragma pack(2)//必须得写否则sizeof得不到正确的结果
typedef unsigned char BYTE; typedef unsigned char BYTE;
typedef unsigned short WORD; typedef unsigned short WORD;
@ -66,6 +71,84 @@ typedef struct {
DWORD biClrImportant; DWORD biClrImportant;
} BITMAPINFOHEADER; } BITMAPINFOHEADER;
int SaveToBMP(const QrCode& qrCode) // to 145*145
{
//将要生成的二维码保存为BMP真彩色图片文件
FILE* pf = fopen("qrcode.bmp", "wb");
if (NULL == pf)
{
printf("file open fail.\n");
fclose(pf);
return -1;
}
int width = qrCode.getSize();
int height = qrCode.getSize();
int biCount = 24;//真彩色
int lineByte = (width * biCount / 8 + 3) / 4 * 4; //每line字节数必须为4的倍数
//位图文件头
BITMAPFILEHEADER bitMapFileHeader;
bitMapFileHeader.bfType = 0x4D42;
bitMapFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + lineByte * height;
bitMapFileHeader.bfReserved1 = 0;
bitMapFileHeader.bfReserved2 = 0;
bitMapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//位图信息头
BITMAPINFOHEADER bitMapInfoHeader;
bitMapInfoHeader.biBitCount = biCount;
bitMapInfoHeader.biClrImportant = 0;
bitMapInfoHeader.biClrUsed = 0;
bitMapInfoHeader.biCompression = 0;
bitMapInfoHeader.biHeight = height;
bitMapInfoHeader.biPlanes = 1;
bitMapInfoHeader.biSize = 40;
bitMapInfoHeader.biSizeImage = lineByte * height;
bitMapInfoHeader.biWidth = width;
bitMapInfoHeader.biXPelsPerMeter = 0;
bitMapInfoHeader.biYPelsPerMeter = 0;
//写文件头进文件
fwrite(&bitMapFileHeader, sizeof(BITMAPFILEHEADER), 1, pf);
//写位图信息头进文件
fwrite(&bitMapInfoHeader, sizeof(BITMAPINFOHEADER), 1, pf);
unsigned char* pBMPData = new unsigned char[lineByte * height];
memset(pBMPData, 255, lineByte * height);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < height; x++)
{
//qrCode.getModule(x, y) ? printf("##") : printf(" ");
qrCode.getModule(x, y) ? printf("%c%c", 219, 219) : printf(" ");
}
std::cout << std::endl;
}
std::cout << std::endl;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < lineByte / 3; j++)
{
if (qrCode.getModule(j, i))
{
//设置rgb颜色可自定义设置这里设为黑色。
*(pBMPData + lineByte * i + 3 * j) = 0;
*(pBMPData + lineByte * i + 3 * j + 1) = 0;
*(pBMPData + lineByte * i + 3 * j + 2) = 0;
}
}
}
//写数据进文件
fwrite(pBMPData, sizeof(unsigned char), lineByte * height, pf);
fclose(pf);
delete[] pBMPData;
pBMPData = NULL;
return 0;
}
// Function prototypes // Function prototypes
static void doBasicDemo(); static void doBasicDemo();
@ -79,41 +162,40 @@ static void printQr(const QrCode &qr);
// The main application program. // The main application program.
int main() { int main() {
doBasicDemo(); doBasicDemo();
doVarietyDemo(); //doVarietyDemo();
doSegmentDemo(); //doSegmentDemo();
doMaskDemo(); //doMaskDemo();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
/*---- Demo suite ----*/ /*---- Demo suite ----*/
// Creates a single QR Code, then prints it to the console. // Creates a single QR Code, then prints it to the console.
static void doBasicDemo() { static void doBasicDemo() {
const char *text = "Hello, world!"; // User-supplied text const char *text = "https://www.baidu.com/"; // User-supplied text
const QrCode::Ecc errCorLvl = QrCode::Ecc::LOW; // Error correction level const QrCode::Ecc errCorLvl = QrCode::LOW; // Error correction level
// Make and print the QR Code symbol // Make and print the QR Code symbol
const QrCode qr = QrCode::encodeText(text, errCorLvl); const QrCode qr = QrCode::encodeText(text, errCorLvl);
printQr(qr); //printQr(qr);
std::cout << toSvgString(qr, 4) << std::endl;
SaveToBMP(qr);
} }
// Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console. // Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.
static void doVarietyDemo() { static void doVarietyDemo() {
// Numeric mode encoding (3.33 bits per digit) // Numeric mode encoding (3.33 bits per digit)
const QrCode qr0 = QrCode::encodeText("314159265358979323846264338327950288419716939937510", QrCode::Ecc::MEDIUM); const QrCode qr0 = QrCode::encodeText("314159265358979323846264338327950288419716939937510", QrCode::MEDIUM);
printQr(qr0); printQr(qr0);
// Alphanumeric mode encoding (5.5 bits per character) // Alphanumeric mode encoding (5.5 bits per character)
const QrCode qr1 = QrCode::encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode::Ecc::HIGH); const QrCode qr1 = QrCode::encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode::HIGH);
printQr(qr1); printQr(qr1);
// Unicode text as UTF-8 // Unicode text as UTF-8
const QrCode qr2 = QrCode::encodeText("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81" const QrCode qr2 = QrCode::encodeText("\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81"
"\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4", QrCode::Ecc::QUARTILE); "\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4", QrCode::QUARTILE);
printQr(qr2); printQr(qr2);
// Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland) // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
@ -124,7 +206,7 @@ static void doVarietyDemo() {
"'without pictures or conversations?' So she was considering in her own mind (as well as she could, " "'without pictures or conversations?' So she was considering in her own mind (as well as she could, "
"for the hot day made her feel very sleepy and stupid), whether the pleasure of making a " "for the hot day made her feel very sleepy and stupid), whether the pleasure of making a "
"daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly " "daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly "
"a White Rabbit with pink eyes ran close by her.", QrCode::Ecc::HIGH); "a White Rabbit with pink eyes ran close by her.", QrCode::HIGH);
printQr(qr3); printQr(qr3);
} }
@ -136,12 +218,13 @@ static void doSegmentDemo() {
const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799"; const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
const QrCode qr0 = QrCode::encodeText( const QrCode qr0 = QrCode::encodeText(
(std::string(silver0) + silver1).c_str(), (std::string(silver0) + silver1).c_str(),
QrCode::Ecc::LOW); QrCode::LOW);
printQr(qr0); printQr(qr0);
const QrCode qr1 = QrCode::encodeSegments( std::vector<QrSegment> segs;
{QrSegment::makeAlphanumeric(silver0), QrSegment::makeNumeric(silver1)}, segs.push_back(QrSegment::makeAlphanumeric(silver0));
QrCode::Ecc::LOW); segs.push_back(QrSegment::makeAlphanumeric(silver1));
const QrCode qr1 = QrCode::encodeSegments(segs, QrCode::LOW);
printQr(qr1); printQr(qr1);
// Illustration "golden" // Illustration "golden"
@ -150,13 +233,15 @@ static void doSegmentDemo() {
const char *golden2 = "......"; const char *golden2 = "......";
const QrCode qr2 = QrCode::encodeText( const QrCode qr2 = QrCode::encodeText(
(std::string(golden0) + golden1 + golden2).c_str(), (std::string(golden0) + golden1 + golden2).c_str(),
QrCode::Ecc::LOW); QrCode::LOW);
printQr(qr2); printQr(qr2);
std::vector<uint8_t> bytes(golden0, golden0 + std::strlen(golden0)); std::vector<uint8_t> bytes(golden0, golden0 + std::strlen(golden0));
const QrCode qr3 = QrCode::encodeSegments( std::vector<QrSegment> segs3;
{QrSegment::makeBytes(bytes), QrSegment::makeNumeric(golden1), QrSegment::makeAlphanumeric(golden2)}, segs3.push_back(QrSegment::makeBytes(bytes));
QrCode::Ecc::LOW); segs3.push_back(QrSegment::makeNumeric(golden1));
segs3.push_back(QrSegment::makeAlphanumeric(golden2));
const QrCode qr3 = QrCode::encodeSegments(segs3, QrCode::LOW);
printQr(qr3); printQr(qr3);
// Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters // Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
@ -170,24 +255,24 @@ static void doSegmentDemo() {
"\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF" "\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF"
"\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF" "\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF"
"\xBC\x9F"; "\xBC\x9F";
const QrCode qr4 = QrCode::encodeText(madoka, QrCode::Ecc::LOW); const QrCode qr4 = QrCode::encodeText(madoka, QrCode::LOW);
printQr(qr4); printQr(qr4);
const std::vector<int> kanjiChars{ // Kanji mode encoding (13 bits per character) //const std::vector<int> kanjiChars{ // Kanji mode encoding (13 bits per character)
0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7, // 0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7,
0x015C, 0x0147, 0x0129, 0x0059, 0x01BD, // 0x015C, 0x0147, 0x0129, 0x0059, 0x01BD,
0x018D, 0x018A, 0x0036, 0x0141, 0x0144, // 0x018D, 0x018A, 0x0036, 0x0141, 0x0144,
0x0001, 0x0000, 0x0249, 0x0240, 0x0249, // 0x0001, 0x0000, 0x0249, 0x0240, 0x0249,
0x0000, 0x0104, 0x0105, 0x0113, 0x0115, // 0x0000, 0x0104, 0x0105, 0x0113, 0x0115,
0x0000, 0x0208, 0x01FF, 0x0008, // 0x0000, 0x0208, 0x01FF, 0x0008,
}; //};
qrcodegen::BitBuffer bb; //qrcodegen::BitBuffer bb;
for (int c : kanjiChars) //for (int c : kanjiChars)
bb.appendBits(static_cast<std::uint32_t>(c), 13); // bb.appendBits(static_cast<std::uint32_t>(c), 13);
const QrCode qr5 = QrCode::encodeSegments( //const QrCode qr5 = QrCode::encodeSegments(
{QrSegment(QrSegment::Mode::KANJI, static_cast<int>(kanjiChars.size()), bb)}, // {QrSegment(QrSegment::Mode::KANJI, static_cast<int>(kanjiChars.size()), bb)},
QrCode::Ecc::LOW); // QrCode::LOW);
printQr(qr5); //printQr(qr5);
} }
@ -195,8 +280,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, QrCode::MIN_VERSION, QrCode::MAX_VERSION, -1, true)); // Automatic mask printQr(QrCode::encodeSegments(segs0, QrCode::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, -1, true)); // Automatic mask
printQr(QrCode::encodeSegments(segs0, QrCode::Ecc::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 3, true)); // Force mask 3 printQr(QrCode::encodeSegments(segs0, QrCode::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(
@ -207,10 +292,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, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 0, true)); // Force mask 0 printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 0, true)); // Force mask 0
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 1, true)); // Force mask 1 printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 1, true)); // Force mask 1
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 5, true)); // Force mask 5 printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 5, true)); // Force mask 5
printQr(QrCode::encodeSegments(segs1, QrCode::Ecc::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 7, true)); // Force mask 7 printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 7, true)); // Force mask 7
} }
@ -246,15 +331,18 @@ static std::string toSvgString(const QrCode &qr, int border) {
return sb.str(); return sb.str();
} }
// Prints the given QrCode object to the console. // Prints the given QrCode object to the console.
static void printQr(const QrCode &qr) { static void printQr(const QrCode &qr) {
int border = 4; int border = 4;
for (int y = -border; y < qr.getSize() + border; y++) { for (int y = -border; y < qr.getSize() + border; y++) {
for (int x = -border; x < qr.getSize() + border; x++) { for (int x = -border; x < qr.getSize() + border; x++) {
std::cout << (qr.getModule(x, y) ? "##" : " "); qr.getModule(x, y) ? printf("%c%c", 219, 219) : printf(" ");
} }
std::cout << std::endl; std::cout << std::endl;
} }
std::cout << std::endl; std::cout << std::endl;
} }

@ -31,9 +31,7 @@
#include <utility> #include <utility>
#include "qrcodegen.hpp" #include "qrcodegen.hpp"
using std::int8_t;
using std::uint8_t;
using std::size_t;
using std::vector; using std::vector;
@ -70,9 +68,9 @@ QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
if (data.size() > static_cast<unsigned int>(INT_MAX)) if (data.size() > static_cast<unsigned int>(INT_MAX))
throw std::length_error("Data too long"); throw std::length_error("Data too long");
BitBuffer bb; BitBuffer bb;
for (uint8_t b : data) for (vector<uint8_t>::size_type i = 0; i < data.size(); i++)
bb.appendBits(b, 8); bb.appendBits(data[i], 8);
return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb)); return QrSegment(Mode::BYTE, static_cast<int>(data.size()), bb);
} }
@ -95,7 +93,7 @@ QrSegment QrSegment::makeNumeric(const char *digits) {
} }
if (accumCount > 0) // 1 or 2 digits remaining if (accumCount > 0) // 1 or 2 digits remaining
bb.appendBits(static_cast<uint32_t>(accumData), accumCount * 3 + 1); bb.appendBits(static_cast<uint32_t>(accumData), accumCount * 3 + 1);
return QrSegment(Mode::NUMERIC, charCount, std::move(bb)); return QrSegment(Mode::NUMERIC, charCount, bb);
} }
@ -106,7 +104,7 @@ QrSegment QrSegment::makeAlphanumeric(const char *text) {
int charCount = 0; int charCount = 0;
for (; *text != '\0'; text++, charCount++) { for (; *text != '\0'; text++, charCount++) {
const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text); const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
if (temp == nullptr) if (temp == NULL)
throw std::domain_error("String contains unencodable characters in alphanumeric mode"); throw std::domain_error("String contains unencodable characters in alphanumeric mode");
accumData = accumData * 45 + static_cast<int>(temp - ALPHANUMERIC_CHARSET); accumData = accumData * 45 + static_cast<int>(temp - ALPHANUMERIC_CHARSET);
accumCount++; accumCount++;
@ -118,7 +116,7 @@ QrSegment QrSegment::makeAlphanumeric(const char *text) {
} }
if (accumCount > 0) // 1 character remaining if (accumCount > 0) // 1 character remaining
bb.appendBits(static_cast<uint32_t>(accumData), 6); bb.appendBits(static_cast<uint32_t>(accumData), 6);
return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb)); return QrSegment(Mode::ALPHANUMERIC, charCount, bb);
} }
@ -154,7 +152,7 @@ QrSegment QrSegment::makeEci(long assignVal) {
bb.appendBits(static_cast<uint32_t>(assignVal), 21); bb.appendBits(static_cast<uint32_t>(assignVal), 21);
} else } else
throw std::domain_error("ECI assignment value out of range"); throw std::domain_error("ECI assignment value out of range");
return QrSegment(Mode::ECI, 0, std::move(bb)); return QrSegment(Mode::ECI, 0, bb);
} }
@ -167,10 +165,10 @@ QrSegment::QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt) :
} }
QrSegment::QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt) : QrSegment::QrSegment(const Mode &md, int numCh, std::vector<bool> &dt) :
mode(&md), mode(&md),
numChars(numCh), numChars(numCh),
data(std::move(dt)) { data(dt) {
if (numCh < 0) if (numCh < 0)
throw std::domain_error("Invalid value"); throw std::domain_error("Invalid value");
} }
@ -178,16 +176,16 @@ QrSegment::QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt) :
int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) { int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
int result = 0; int result = 0;
for (const QrSegment &seg : segs) { for (vector<QrSegment>::size_type i = 0; i <segs.size(); i++) {
int ccbits = seg.mode->numCharCountBits(version); int ccbits = segs[i].mode->numCharCountBits(version);
if (seg.numChars >= (1L << ccbits)) if (segs[i].numChars >= (1L << ccbits))
return -1; // The segment's length doesn't fit the field's bit width return -1; // The segment's length doesn't fit the field's bit width
if (4 + ccbits > INT_MAX - result) if (4 + ccbits > INT_MAX - result)
return -1; // The sum will overflow an int type return -1; // The sum will overflow an int type
result += 4 + ccbits; result += 4 + ccbits;
if (seg.data.size() > static_cast<unsigned int>(INT_MAX - result)) if (segs[i].data.size() > static_cast<unsigned int>(INT_MAX - result))
return -1; // The sum will overflow an int type return -1; // The sum will overflow an int type
result += static_cast<int>(seg.data.size()); result += static_cast<int>(segs[i].data.size());
} }
return result; return result;
} }
@ -205,7 +203,7 @@ bool QrSegment::isNumeric(const char *text) {
bool QrSegment::isAlphanumeric(const char *text) { bool QrSegment::isAlphanumeric(const char *text) {
for (; *text != '\0'; text++) { for (; *text != '\0'; text++) {
if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr) if (std::strchr(ALPHANUMERIC_CHARSET, *text) == NULL)
return false; return false;
} }
return true; return true;
@ -235,10 +233,10 @@ const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVW
int QrCode::getFormatBits(Ecc ecl) { int QrCode::getFormatBits(Ecc ecl) {
switch (ecl) { switch (ecl) {
case Ecc::LOW : return 1; case LOW : return 1;
case Ecc::MEDIUM : return 0; case MEDIUM : return 0;
case Ecc::QUARTILE: return 3; case QUARTILE: return 3;
case Ecc::HIGH : return 2; case HIGH : return 2;
default: throw std::logic_error("Unreachable"); default: throw std::logic_error("Unreachable");
} }
} }
@ -251,7 +249,8 @@ QrCode QrCode::encodeText(const char *text, Ecc ecl) {
QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) { QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
vector<QrSegment> segs{QrSegment::makeBytes(data)}; vector<QrSegment> segs;
segs.push_back(QrSegment::makeBytes(data));
return encodeSegments(segs, ecl); return encodeSegments(segs, ecl);
} }
@ -282,17 +281,18 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
assert(dataUsedBits != -1); assert(dataUsedBits != -1);
// Increase the error correction level while the data still fits in the current version number // Increase the error correction level while the data still fits in the current version number
for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high Ecc ecls[3] = {MEDIUM, QUARTILE, HIGH};
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) for (uint8_t i = 0; i < 3; ++i) { // From low to high
ecl = newEcl; if (boostEcl && dataUsedBits <= getNumDataCodewords(version, ecls[i]) * 8)
ecl = ecls[i];
} }
// Concatenate all segments to create the data bit string // Concatenate all segments to create the data bit string
BitBuffer bb; BitBuffer bb;
for (const QrSegment &seg : segs) { for (vector<QrSegment>::size_type i = 0; i < segs.size(); ++i) {
bb.appendBits(static_cast<uint32_t>(seg.getMode().getModeBits()), 4); bb.appendBits(static_cast<uint32_t>(segs[i].getMode().getModeBits()), 4);
bb.appendBits(static_cast<uint32_t>(seg.getNumChars()), seg.getMode().numCharCountBits(version)); bb.appendBits(static_cast<uint32_t>(segs[i].getNumChars()), segs[i].getMode().numCharCountBits(version));
bb.insert(bb.end(), seg.getData().begin(), seg.getData().end()); bb.insert(bb.end(), segs[i].getData().begin(), segs[i].getData().end());
} }
assert(bb.size() == static_cast<unsigned int>(dataUsedBits)); assert(bb.size() == static_cast<unsigned int>(dataUsedBits));
@ -355,7 +355,9 @@ QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk)
drawFormatBits(msk); // Overwrite old format bits drawFormatBits(msk); // Overwrite old format bits
isFunction.clear(); isFunction.clear();
isFunction.shrink_to_fit(); //isFunction.shrink_to_fit();
//vector<int>(isFunction).swap(isFunction);
} }
@ -510,13 +512,13 @@ vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
vector<vector<uint8_t> > blocks; vector<vector<uint8_t> > blocks;
const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen); const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen);
for (int i = 0, k = 0; i < numBlocks; i++) { for (int i = 0, k = 0; i < numBlocks; i++) {
vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); vector<uint8_t> dat(data.begin() + k, data.begin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
k += static_cast<int>(dat.size()); k += static_cast<int>(dat.size());
const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv); const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv);
if (i < numShortBlocks) if (i < numShortBlocks)
dat.push_back(0); dat.push_back(0);
dat.insert(dat.end(), ecc.cbegin(), ecc.cend()); dat.insert(dat.end(), ecc.begin(), ecc.end());
blocks.push_back(std::move(dat)); blocks.push_back(dat);
} }
// Interleave (not concatenate) the bytes from every block into a single sequence // Interleave (not concatenate) the bytes from every block into a single sequence
@ -591,7 +593,7 @@ long QrCode::getPenaltyScore() const {
for (int y = 0; y < size; y++) { for (int y = 0; y < size; y++) {
bool runColor = false; bool runColor = false;
int runX = 0; int runX = 0;
std::array<int,7> runHistory = {}; int runHistory[7] = {};
for (int x = 0; x < size; x++) { for (int x = 0; x < size; x++) {
if (module(x, y) == runColor) { if (module(x, y) == runColor) {
runX++; runX++;
@ -613,7 +615,7 @@ long QrCode::getPenaltyScore() const {
for (int x = 0; x < size; x++) { for (int x = 0; x < size; x++) {
bool runColor = false; bool runColor = false;
int runY = 0; int runY = 0;
std::array<int,7> runHistory = {}; int runHistory[7] = {};
for (int y = 0; y < size; y++) { for (int y = 0; y < size; y++) {
if (module(x, y) == runColor) { if (module(x, y) == runColor) {
runY++; runY++;
@ -645,9 +647,9 @@ long QrCode::getPenaltyScore() const {
// Balance of dark and light modules // Balance of dark and light modules
int dark = 0; int dark = 0;
for (const vector<bool> &row : modules) { for (std::vector<std::vector<bool> >::const_iterator row = modules.begin(); row != modules.end(); ++row) {
for (bool color : row) { for (std::vector<bool>::const_iterator color = row->begin(); color != row->end(); ++color) {
if (color) if (*color)
dark++; dark++;
} }
} }
@ -726,8 +728,8 @@ vector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) {
vector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data, const vector<uint8_t> &divisor) { vector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data, const vector<uint8_t> &divisor) {
vector<uint8_t> result(divisor.size()); vector<uint8_t> result(divisor.size());
for (uint8_t b : data) { // Polynomial division for (vector<uint8_t>::size_type n = 0; n < data.size(); ++n) { // Polynomial division
uint8_t factor = b ^ result.at(0); uint8_t factor = data[n] ^ result.at(0);
result.erase(result.begin()); result.erase(result.begin());
result.push_back(0); result.push_back(0);
for (size_t i = 0; i < result.size(); i++) for (size_t i = 0; i < result.size(); i++)
@ -749,16 +751,16 @@ uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
} }
int QrCode::finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const { int QrCode::finderPenaltyCountPatterns(const int runHistory[7]) const {
int n = runHistory.at(1); int n = runHistory[1];
assert(n <= size * 3); assert(n <= size * 3);
bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n; bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;
return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0) return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0)
+ (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0); + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0);
} }
int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const { int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7]) const {
if (currentRunColor) { // Terminate dark run if (currentRunColor) { // Terminate dark run
finderPenaltyAddHistory(currentRunLength, runHistory); finderPenaltyAddHistory(currentRunLength, runHistory);
currentRunLength = 0; currentRunLength = 0;
@ -769,11 +771,11 @@ int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunL
} }
void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const { void QrCode::finderPenaltyAddHistory(int currentRunLength, int runHistory[7]) const {
if (runHistory.at(0) == 0) if (runHistory[0] == 0)
currentRunLength += size; // Add light border to initial run currentRunLength += size; // Add light border to initial run
std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end()); std::copy_backward(runHistory, runHistory + 6, runHistory + 7);
runHistory.at(0) = currentRunLength; runHistory[0] = currentRunLength;
} }
@ -820,11 +822,13 @@ BitBuffer::BitBuffer()
: std::vector<bool>() {} : std::vector<bool>() {}
void BitBuffer::appendBits(std::uint32_t val, int len) { void BitBuffer::appendBits(uint32_t val, int len) {
if (len < 0 || len > 31 || val >> len != 0) if (len < 0 || len > 31 || val >> len != 0)
throw std::domain_error("Value out of range"); throw std::domain_error("Value out of range");
for (int i = len - 1; i >= 0; i--) // Append bit by bit for (int i = len - 1; i >= 0; i--) // Append bit by bit
this->push_back(((val >> i) & 1) != 0); this->push_back(((val >> i) & 1) != 0);
} }
} }

@ -24,14 +24,16 @@
#pragma once #pragma once
#include <array> #include <array>
#include <cstdint>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <vector> #include <vector>
typedef char int8_t;
typedef unsigned char uint8_t;
typedef unsigned int size_t;
typedef unsigned int uint32_t;
namespace qrcodegen { namespace qrcodegen {
/* /*
* A segment of character/binary/control data in a QR Code symbol. * A segment of character/binary/control data in a QR Code symbol.
* Instances of this class are immutable. * Instances of this class are immutable.
@ -43,14 +45,14 @@ namespace qrcodegen {
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
* Any segment longer than this is meaningless for the purpose of generating QR Codes. * Any segment longer than this is meaningless for the purpose of generating QR Codes.
*/ */
class QrSegment final { class QrSegment {
/*---- Public helper enumeration ----*/ /*---- Public helper enumeration ----*/
/* /*
* Describes how a segment's data bits are interpreted. Immutable. * Describes how a segment's data bits are interpreted. Immutable.
*/ */
public: class Mode final { public: class Mode {
/*-- Constants --*/ /*-- Constants --*/
@ -99,7 +101,7 @@ class QrSegment final {
* byte mode. All input byte vectors are acceptable. Any text string * byte mode. All input byte vectors are acceptable. Any text string
* can be converted to UTF-8 bytes and encoded as a byte mode segment. * can be converted to UTF-8 bytes and encoded as a byte mode segment.
*/ */
public: static QrSegment makeBytes(const std::vector<std::uint8_t> &data); public: static QrSegment makeBytes(const std::vector<uint8_t> &data);
/* /*
@ -178,7 +180,7 @@ class QrSegment final {
* The character count (numCh) must agree with the mode and the bit buffer length, * The character count (numCh) must agree with the mode and the bit buffer length,
* but the constraint isn't checked. The given bit buffer is moved and stored. * but the constraint isn't checked. The given bit buffer is moved and stored.
*/ */
public: QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt); public: QrSegment(const Mode &md, int numCh, std::vector<bool> &dt);
/*---- Methods ----*/ /*---- Methods ----*/
@ -233,14 +235,14 @@ class QrSegment final {
* supply the appropriate version number, and call the QrCode() constructor. * supply the appropriate version number, and call the QrCode() constructor.
* (Note that all ways require supplying the desired error correction level.) * (Note that all ways require supplying the desired error correction level.)
*/ */
class QrCode final { class QrCode {
/*---- Public helper enumeration ----*/ /*---- Public helper enumeration ----*/
/* /*
* The error correction level in a QR Code symbol. * The error correction level in a QR Code symbol.
*/ */
public: enum class Ecc { public: enum Ecc {
LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords
MEDIUM , // The QR Code can tolerate about 15% erroneous codewords MEDIUM , // The QR Code can tolerate about 15% erroneous codewords
QUARTILE, // The QR Code can tolerate about 25% erroneous codewords QUARTILE, // The QR Code can tolerate about 25% erroneous codewords
@ -271,7 +273,7 @@ class QrCode final {
* bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
*/ */
public: static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl); public: static QrCode encodeBinary(const std::vector<uint8_t> &data, Ecc ecl);
/*---- Static factory functions (mid level) ----*/ /*---- Static factory functions (mid level) ----*/
@ -331,7 +333,7 @@ class QrCode final {
* This is a low-level API that most users should not use directly. * This is a low-level API that most users should not use directly.
* A mid-level API is the encodeSegments() function. * A mid-level API is the encodeSegments() function.
*/ */
public: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk); public: QrCode(int ver, Ecc ecl, const std::vector<uint8_t> &dataCodewords, int msk);
@ -409,12 +411,12 @@ class QrCode final {
// Returns a new byte string representing the given data with the appropriate error correction // Returns a new byte string representing the given data with the appropriate error correction
// codewords appended to it, based on this object's version and error correction level. // codewords appended to it, based on this object's version and error correction level.
private: std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data) const; private: std::vector<uint8_t> addEccAndInterleave(const std::vector<uint8_t> &data) const;
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
// data area of this QR Code. Function modules need to be marked off before this is called. // data area of this QR Code. Function modules need to be marked off before this is called.
private: void drawCodewords(const std::vector<std::uint8_t> &data); private: void drawCodewords(const std::vector<uint8_t> &data);
// XORs the codeword modules in this QR Code with the given mask pattern. // XORs the codeword modules in this QR Code with the given mask pattern.
@ -453,29 +455,29 @@ class QrCode final {
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
// implemented as a lookup table over all possible parameter values, instead of as an algorithm. // implemented as a lookup table over all possible parameter values, instead of as an algorithm.
private: static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree); private: static std::vector<uint8_t> reedSolomonComputeDivisor(int degree);
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
private: static std::vector<std::uint8_t> reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, const std::vector<std::uint8_t> &divisor); private: static std::vector<uint8_t> reedSolomonComputeRemainder(const std::vector<uint8_t> &data, const std::vector<uint8_t> &divisor);
// Returns the product of the two given field elements modulo GF(2^8/0x11D). // Returns the product of the two given field elements modulo GF(2^8/0x11D).
// All inputs are valid. This could be implemented as a 256*256 lookup table. // All inputs are valid. This could be implemented as a 256*256 lookup table.
private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y); private: static uint8_t reedSolomonMultiply(uint8_t x, uint8_t y);
// Can only be called immediately after a light run is added, and // Can only be called immediately after a light run is added, and
// returns either 0, 1, or 2. A helper function for getPenaltyScore(). // returns either 0, 1, or 2. A helper function for getPenaltyScore().
private: int finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const; private: int finderPenaltyCountPatterns(const int runHistory[7]) const;
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array<int,7> &runHistory) const; private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7]) const;
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
private: void finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const; private: void finderPenaltyAddHistory(int currentRunLength, int runHistory[7]) const;
// Returns true iff the i'th bit of x is set to 1. // Returns true iff the i'th bit of x is set to 1.
@ -485,10 +487,10 @@ class QrCode final {
/*---- Constants and tables ----*/ /*---- Constants and tables ----*/
// The minimum version number supported in the QR Code Model 2 standard. // The minimum version number supported in the QR Code Model 2 standard.
public: static constexpr int MIN_VERSION = 1; public: static const int MIN_VERSION = 1;
// The maximum version number supported in the QR Code Model 2 standard. // The maximum version number supported in the QR Code Model 2 standard.
public: static constexpr int MAX_VERSION = 40; public: static const int MAX_VERSION = 40;
// For use in getPenaltyScore(), when evaluating which mask is best. // For use in getPenaltyScore(), when evaluating which mask is best.
@ -498,8 +500,8 @@ class QrCode final {
private: static const int PENALTY_N4; private: static const int PENALTY_N4;
private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41]; private: static const int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]; private: static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
}; };
@ -529,7 +531,7 @@ class data_too_long : public std::length_error {
/* /*
* An appendable sequence of bits (0s and 1s). Mainly used by QrSegment. * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment.
*/ */
class BitBuffer final : public std::vector<bool> { class BitBuffer : public std::vector<bool> {
/*---- Constructor ----*/ /*---- Constructor ----*/
@ -542,7 +544,7 @@ class BitBuffer final : public std::vector<bool> {
// Appends the given number of low-order bits of the given value // Appends the given number of low-order bits of the given value
// to this buffer. Requires 0 <= len <= 31 and val < 2^len. // to this buffer. Requires 0 <= len <= 31 and val < 2^len.
public: void appendBits(std::uint32_t val, int len); public: void appendBits(uint32_t val, int len);
}; };

Loading…
Cancel
Save