diff --git a/cpp/QrCodeGeneratorDemo.cpp b/cpp/QrCodeGeneratorDemo.cpp index d94230f..76950c9 100644 --- a/cpp/QrCodeGeneratorDemo.cpp +++ b/cpp/QrCodeGeneratorDemo.cpp @@ -1,4 +1,4 @@ -/* +/* * QR Code generator demo (C++) * * Run this command-line program with no arguments. The program computes a bunch of demonstration @@ -24,8 +24,9 @@ * Software. */ +#define _CRT_SECURE_NO_DEPRECATE + #include -#include #include #include #include @@ -33,12 +34,16 @@ #include #include #include "qrcodegen.hpp" +#include +#include +#include +#include -using std::uint8_t; using qrcodegen::QrCode; 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 short WORD; @@ -66,6 +71,84 @@ typedef struct { DWORD biClrImportant; } 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 static void doBasicDemo(); @@ -79,41 +162,40 @@ static void printQr(const QrCode &qr); // The main application program. int main() { doBasicDemo(); - doVarietyDemo(); - doSegmentDemo(); - doMaskDemo(); + //doVarietyDemo(); + //doSegmentDemo(); + //doMaskDemo(); return EXIT_SUCCESS; } - - /*---- Demo suite ----*/ // Creates a single QR Code, then prints it to the console. static void doBasicDemo() { - const char *text = "Hello, world!"; // User-supplied text - const QrCode::Ecc errCorLvl = QrCode::Ecc::LOW; // Error correction level + const char *text = "https://www.baidu.com/"; // User-supplied text + const QrCode::Ecc errCorLvl = QrCode::LOW; // Error correction level // Make and print the QR Code symbol const QrCode qr = QrCode::encodeText(text, errCorLvl); - printQr(qr); - std::cout << toSvgString(qr, 4) << std::endl; + //printQr(qr); + + SaveToBMP(qr); } // Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console. static void doVarietyDemo() { // 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); // 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); // 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" - "\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); // 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, " "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 " - "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); } @@ -136,12 +218,13 @@ static void doSegmentDemo() { const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799"; const QrCode qr0 = QrCode::encodeText( (std::string(silver0) + silver1).c_str(), - QrCode::Ecc::LOW); + QrCode::LOW); printQr(qr0); - const QrCode qr1 = QrCode::encodeSegments( - {QrSegment::makeAlphanumeric(silver0), QrSegment::makeNumeric(silver1)}, - QrCode::Ecc::LOW); + std::vector segs; + segs.push_back(QrSegment::makeAlphanumeric(silver0)); + segs.push_back(QrSegment::makeAlphanumeric(silver1)); + const QrCode qr1 = QrCode::encodeSegments(segs, QrCode::LOW); printQr(qr1); // Illustration "golden" @@ -150,13 +233,15 @@ static void doSegmentDemo() { const char *golden2 = "......"; const QrCode qr2 = QrCode::encodeText( (std::string(golden0) + golden1 + golden2).c_str(), - QrCode::Ecc::LOW); + QrCode::LOW); printQr(qr2); std::vector bytes(golden0, golden0 + std::strlen(golden0)); - const QrCode qr3 = QrCode::encodeSegments( - {QrSegment::makeBytes(bytes), QrSegment::makeNumeric(golden1), QrSegment::makeAlphanumeric(golden2)}, - QrCode::Ecc::LOW); + std::vector segs3; + segs3.push_back(QrSegment::makeBytes(bytes)); + segs3.push_back(QrSegment::makeNumeric(golden1)); + segs3.push_back(QrSegment::makeAlphanumeric(golden2)); + const QrCode qr3 = QrCode::encodeSegments(segs3, QrCode::LOW); printQr(qr3); // 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" "\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF" "\xBC\x9F"; - const QrCode qr4 = QrCode::encodeText(madoka, QrCode::Ecc::LOW); + const QrCode qr4 = QrCode::encodeText(madoka, QrCode::LOW); printQr(qr4); - const std::vector kanjiChars{ // Kanji mode encoding (13 bits per character) - 0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7, - 0x015C, 0x0147, 0x0129, 0x0059, 0x01BD, - 0x018D, 0x018A, 0x0036, 0x0141, 0x0144, - 0x0001, 0x0000, 0x0249, 0x0240, 0x0249, - 0x0000, 0x0104, 0x0105, 0x0113, 0x0115, - 0x0000, 0x0208, 0x01FF, 0x0008, - }; - qrcodegen::BitBuffer bb; - for (int c : kanjiChars) - bb.appendBits(static_cast(c), 13); - const QrCode qr5 = QrCode::encodeSegments( - {QrSegment(QrSegment::Mode::KANJI, static_cast(kanjiChars.size()), bb)}, - QrCode::Ecc::LOW); - printQr(qr5); + //const std::vector kanjiChars{ // Kanji mode encoding (13 bits per character) + // 0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7, + // 0x015C, 0x0147, 0x0129, 0x0059, 0x01BD, + // 0x018D, 0x018A, 0x0036, 0x0141, 0x0144, + // 0x0001, 0x0000, 0x0249, 0x0240, 0x0249, + // 0x0000, 0x0104, 0x0105, 0x0113, 0x0115, + // 0x0000, 0x0208, 0x01FF, 0x0008, + //}; + //qrcodegen::BitBuffer bb; + //for (int c : kanjiChars) + // bb.appendBits(static_cast(c), 13); + //const QrCode qr5 = QrCode::encodeSegments( + // {QrSegment(QrSegment::Mode::KANJI, static_cast(kanjiChars.size()), bb)}, + // QrCode::LOW); + //printQr(qr5); } @@ -195,8 +280,8 @@ static void doSegmentDemo() { static void doMaskDemo() { // Project Nayuki URL std::vector 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::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, -1, true)); // Automatic mask + printQr(QrCode::encodeSegments(segs0, QrCode::HIGH, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 3, true)); // Force mask 3 // Chinese text as UTF-8 std::vector 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" "\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"); - 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, 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::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, 0, true)); // Force mask 0 + printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 1, true)); // Force mask 1 + printQr(QrCode::encodeSegments(segs1, QrCode::MEDIUM, QrCode::MIN_VERSION, QrCode::MAX_VERSION, 5, true)); // Force mask 5 + 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(); } - // Prints the given QrCode object to the console. static void printQr(const QrCode &qr) { int border = 4; for (int y = -border; y < qr.getSize() + border; y++) { 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; } + + + + diff --git a/cpp/qrcodegen.cpp b/cpp/qrcodegen.cpp index 0957b79..a562fa7 100644 --- a/cpp/qrcodegen.cpp +++ b/cpp/qrcodegen.cpp @@ -31,9 +31,7 @@ #include #include "qrcodegen.hpp" -using std::int8_t; -using std::uint8_t; -using std::size_t; + using std::vector; @@ -70,9 +68,9 @@ QrSegment QrSegment::makeBytes(const vector &data) { if (data.size() > static_cast(INT_MAX)) throw std::length_error("Data too long"); BitBuffer bb; - for (uint8_t b : data) - bb.appendBits(b, 8); - return QrSegment(Mode::BYTE, static_cast(data.size()), std::move(bb)); + for (vector::size_type i = 0; i < data.size(); i++) + bb.appendBits(data[i], 8); + return QrSegment(Mode::BYTE, static_cast(data.size()), bb); } @@ -95,7 +93,7 @@ QrSegment QrSegment::makeNumeric(const char *digits) { } if (accumCount > 0) // 1 or 2 digits remaining bb.appendBits(static_cast(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; for (; *text != '\0'; text++, charCount++) { 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"); accumData = accumData * 45 + static_cast(temp - ALPHANUMERIC_CHARSET); accumCount++; @@ -118,7 +116,7 @@ QrSegment QrSegment::makeAlphanumeric(const char *text) { } if (accumCount > 0) // 1 character remaining bb.appendBits(static_cast(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(assignVal), 21); } else 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 &dt) : } -QrSegment::QrSegment(const Mode &md, int numCh, std::vector &&dt) : +QrSegment::QrSegment(const Mode &md, int numCh, std::vector &dt) : mode(&md), numChars(numCh), - data(std::move(dt)) { + data(dt) { if (numCh < 0) throw std::domain_error("Invalid value"); } @@ -178,16 +176,16 @@ QrSegment::QrSegment(const Mode &md, int numCh, std::vector &&dt) : int QrSegment::getTotalBits(const vector &segs, int version) { int result = 0; - for (const QrSegment &seg : segs) { - int ccbits = seg.mode->numCharCountBits(version); - if (seg.numChars >= (1L << ccbits)) + for (vector::size_type i = 0; i numCharCountBits(version); + if (segs[i].numChars >= (1L << ccbits)) return -1; // The segment's length doesn't fit the field's bit width if (4 + ccbits > INT_MAX - result) return -1; // The sum will overflow an int type result += 4 + ccbits; - if (seg.data.size() > static_cast(INT_MAX - result)) + if (segs[i].data.size() > static_cast(INT_MAX - result)) return -1; // The sum will overflow an int type - result += static_cast(seg.data.size()); + result += static_cast(segs[i].data.size()); } return result; } @@ -205,7 +203,7 @@ bool QrSegment::isNumeric(const char *text) { bool QrSegment::isAlphanumeric(const char *text) { for (; *text != '\0'; text++) { - if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr) + if (std::strchr(ALPHANUMERIC_CHARSET, *text) == NULL) return false; } return true; @@ -235,10 +233,10 @@ const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVW int QrCode::getFormatBits(Ecc ecl) { switch (ecl) { - case Ecc::LOW : return 1; - case Ecc::MEDIUM : return 0; - case Ecc::QUARTILE: return 3; - case Ecc::HIGH : return 2; + case LOW : return 1; + case MEDIUM : return 0; + case QUARTILE: return 3; + case HIGH : return 2; default: throw std::logic_error("Unreachable"); } } @@ -251,7 +249,8 @@ QrCode QrCode::encodeText(const char *text, Ecc ecl) { QrCode QrCode::encodeBinary(const vector &data, Ecc ecl) { - vector segs{QrSegment::makeBytes(data)}; + vector segs; + segs.push_back(QrSegment::makeBytes(data)); return encodeSegments(segs, ecl); } @@ -282,17 +281,18 @@ QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, assert(dataUsedBits != -1); // 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 - if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) - ecl = newEcl; + Ecc ecls[3] = {MEDIUM, QUARTILE, HIGH}; + for (uint8_t i = 0; i < 3; ++i) { // From low to high + if (boostEcl && dataUsedBits <= getNumDataCodewords(version, ecls[i]) * 8) + ecl = ecls[i]; } // Concatenate all segments to create the data bit string BitBuffer bb; - for (const QrSegment &seg : segs) { - bb.appendBits(static_cast(seg.getMode().getModeBits()), 4); - bb.appendBits(static_cast(seg.getNumChars()), seg.getMode().numCharCountBits(version)); - bb.insert(bb.end(), seg.getData().begin(), seg.getData().end()); + for (vector::size_type i = 0; i < segs.size(); ++i) { + bb.appendBits(static_cast(segs[i].getMode().getModeBits()), 4); + bb.appendBits(static_cast(segs[i].getNumChars()), segs[i].getMode().numCharCountBits(version)); + bb.insert(bb.end(), segs[i].getData().begin(), segs[i].getData().end()); } assert(bb.size() == static_cast(dataUsedBits)); @@ -355,7 +355,9 @@ QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int msk) drawFormatBits(msk); // Overwrite old format bits isFunction.clear(); - isFunction.shrink_to_fit(); + //isFunction.shrink_to_fit(); + + //vector(isFunction).swap(isFunction); } @@ -510,13 +512,13 @@ vector QrCode::addEccAndInterleave(const vector &data) const { vector > blocks; const vector rsDiv = reedSolomonComputeDivisor(blockEccLen); for (int i = 0, k = 0; i < numBlocks; i++) { - vector dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); + vector dat(data.begin() + k, data.begin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); k += static_cast(dat.size()); const vector ecc = reedSolomonComputeRemainder(dat, rsDiv); if (i < numShortBlocks) dat.push_back(0); - dat.insert(dat.end(), ecc.cbegin(), ecc.cend()); - blocks.push_back(std::move(dat)); + dat.insert(dat.end(), ecc.begin(), ecc.end()); + blocks.push_back(dat); } // 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++) { bool runColor = false; int runX = 0; - std::array runHistory = {}; + int runHistory[7] = {}; for (int x = 0; x < size; x++) { if (module(x, y) == runColor) { runX++; @@ -613,7 +615,7 @@ long QrCode::getPenaltyScore() const { for (int x = 0; x < size; x++) { bool runColor = false; int runY = 0; - std::array runHistory = {}; + int runHistory[7] = {}; for (int y = 0; y < size; y++) { if (module(x, y) == runColor) { runY++; @@ -645,9 +647,9 @@ long QrCode::getPenaltyScore() const { // Balance of dark and light modules int dark = 0; - for (const vector &row : modules) { - for (bool color : row) { - if (color) + for (std::vector >::const_iterator row = modules.begin(); row != modules.end(); ++row) { + for (std::vector::const_iterator color = row->begin(); color != row->end(); ++color) { + if (*color) dark++; } } @@ -726,8 +728,8 @@ vector QrCode::reedSolomonComputeDivisor(int degree) { vector QrCode::reedSolomonComputeRemainder(const vector &data, const vector &divisor) { vector result(divisor.size()); - for (uint8_t b : data) { // Polynomial division - uint8_t factor = b ^ result.at(0); + for (vector::size_type n = 0; n < data.size(); ++n) { // Polynomial division + uint8_t factor = data[n] ^ result.at(0); result.erase(result.begin()); result.push_back(0); 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 &runHistory) const { - int n = runHistory.at(1); +int QrCode::finderPenaltyCountPatterns(const int runHistory[7]) const { + int n = runHistory[1]; 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; - return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0) - + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0); + bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n; + return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) + + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); } -int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &runHistory) const { +int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7]) const { if (currentRunColor) { // Terminate dark run finderPenaltyAddHistory(currentRunLength, runHistory); currentRunLength = 0; @@ -769,11 +771,11 @@ int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunL } -void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const { - if (runHistory.at(0) == 0) +void QrCode::finderPenaltyAddHistory(int currentRunLength, int runHistory[7]) const { + if (runHistory[0] == 0) currentRunLength += size; // Add light border to initial run - std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end()); - runHistory.at(0) = currentRunLength; + std::copy_backward(runHistory, runHistory + 6, runHistory + 7); + runHistory[0] = currentRunLength; } @@ -820,11 +822,13 @@ BitBuffer::BitBuffer() : std::vector() {} -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) throw std::domain_error("Value out of range"); for (int i = len - 1; i >= 0; i--) // Append bit by bit this->push_back(((val >> i) & 1) != 0); } + + } diff --git a/cpp/qrcodegen.hpp b/cpp/qrcodegen.hpp index 9448982..b63a870 100644 --- a/cpp/qrcodegen.hpp +++ b/cpp/qrcodegen.hpp @@ -24,14 +24,16 @@ #pragma once #include -#include #include #include #include +typedef char int8_t; +typedef unsigned char uint8_t; +typedef unsigned int size_t; +typedef unsigned int uint32_t; namespace qrcodegen { - /* * A segment of character/binary/control data in a QR Code symbol. * 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. * Any segment longer than this is meaningless for the purpose of generating QR Codes. */ -class QrSegment final { +class QrSegment { /*---- Public helper enumeration ----*/ /* * Describes how a segment's data bits are interpreted. Immutable. */ - public: class Mode final { + public: class Mode { /*-- Constants --*/ @@ -99,7 +101,7 @@ class QrSegment final { * 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. */ - public: static QrSegment makeBytes(const std::vector &data); + public: static QrSegment makeBytes(const std::vector &data); /* @@ -178,7 +180,7 @@ class QrSegment final { * 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. */ - public: QrSegment(const Mode &md, int numCh, std::vector &&dt); + public: QrSegment(const Mode &md, int numCh, std::vector &dt); /*---- Methods ----*/ @@ -233,14 +235,14 @@ class QrSegment final { * supply the appropriate version number, and call the QrCode() constructor. * (Note that all ways require supplying the desired error correction level.) */ -class QrCode final { +class QrCode { /*---- Public helper enumeration ----*/ /* * 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 MEDIUM , // The QR Code can tolerate about 15% 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. * 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 &data, Ecc ecl); + public: static QrCode encodeBinary(const std::vector &data, Ecc ecl); /*---- 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. * A mid-level API is the encodeSegments() function. */ - public: QrCode(int ver, Ecc ecl, const std::vector &dataCodewords, int msk); + public: QrCode(int ver, Ecc ecl, const std::vector &dataCodewords, int msk); @@ -409,12 +411,12 @@ class QrCode final { // 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. - private: std::vector addEccAndInterleave(const std::vector &data) const; + private: std::vector addEccAndInterleave(const std::vector &data) const; // 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. - private: void drawCodewords(const std::vector &data); + private: void drawCodewords(const std::vector &data); // 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 // implemented as a lookup table over all possible parameter values, instead of as an algorithm. - private: static std::vector reedSolomonComputeDivisor(int degree); + private: static std::vector reedSolomonComputeDivisor(int degree); // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. - private: static std::vector reedSolomonComputeRemainder(const std::vector &data, const std::vector &divisor); + private: static std::vector reedSolomonComputeRemainder(const std::vector &data, const std::vector &divisor); // 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. - 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 // returns either 0, 1, or 2. A helper function for getPenaltyScore(). - private: int finderPenaltyCountPatterns(const std::array &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(). - private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &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(). - private: void finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const; + private: void finderPenaltyAddHistory(int currentRunLength, int runHistory[7]) const; // Returns true iff the i'th bit of x is set to 1. @@ -485,10 +487,10 @@ class QrCode final { /*---- Constants and tables ----*/ // 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. - public: static constexpr int MAX_VERSION = 40; + public: static const int MAX_VERSION = 40; // 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 std::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 ECC_CODEWORDS_PER_BLOCK[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. */ -class BitBuffer final : public std::vector { +class BitBuffer : public std::vector { /*---- Constructor ----*/ @@ -542,7 +544,7 @@ class BitBuffer final : public std::vector { // Appends the given number of low-order bits of the given value // 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); };