diff --git a/.clang-format b/.clang-format index 298c908..d83582f 100644 --- a/.clang-format +++ b/.clang-format @@ -1,123 +1,38 @@ ---- -Language: Cpp -BasedOnStyle: LLVM -AccessModifierOffset: -2 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: false -AlignConsecutiveBitFields: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlines: Right -AlignOperands: true -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: false -AllowAllConstructorInitializersOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: Empty -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -BinPackArguments: true -BinPackParameters: true +BasedOnStyle: LLVM +Standard: Cpp11 +CommentPragmas: "^!|^:" +PointerBindsToType: false +SpaceAfterTemplateKeyword: false +BreakBeforeBinaryOperators: All +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +ConstructorInitializerIndentWidth: 2 +NamespaceIndentation: None +AlignAfterOpenBracket: true +AlwaysBreakTemplateDeclarations: true +AllowShortFunctionsOnASingleLine: Inline +SortIncludes: false +IndentCaseLabels: true +IndentPPDirectives: AfterHash +AccessModifierOffset: -2 +IndentWidth: 2 +ColumnLimit: 80 + BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: false - SplitEmptyNamespace: false -BreakBeforeBinaryOperators: NonAssignment -BreakBeforeBraces: Custom -BreakBeforeInheritanceComma: false -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -ColumnLimit: 100 -CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 2 -ContinuationIndentWidth: 2 -Cpp11BracedListStyle: true -DeriveLineEnding: true -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: true -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Preserve -IncludeCategories: - - Regex: '^$' - Priority: -1 - - Regex: '^<.*\.h>$' - Priority: 1 - - Regex: '^<.*>' - Priority: 2 - - Regex: '.*' - Priority: 3 -IncludeIsMainRegex: '(Test)?$' -IndentCaseBlocks: true -IndentCaseLabels: false -IndentGotoLabels: true -IndentPPDirectives: AfterHash -IndentWidth: 2 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2000 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Right -ReflowComments: true -SortIncludes: true -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Latest -TabWidth: 2 -UseTab: Never -... + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE ] +#StatementMacros ['Q_OBJECT', 'Q_UNUSED'] + + diff --git a/.gitignore b/.gitignore index 2284c29..c78d976 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,19 @@ .DS_Store .AppleDouble .LSOverride +.cache + +# Binary builds +udp_function_generator +udp_function_generator.exe + +# Build & IDEs +*.kdev* +build/* +example/build/* +*.vscode +*.layout +*.qmlls.ini # Icon must end with two \r Icon @@ -28,3 +41,8 @@ Temporary Items # Qt project file *.pro.user +*.user + +# Clion +.idea/* +cmake-build-* diff --git a/README.md b/README.md index dc81138..46f5555 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Qt QR Code Generator is a simple C++ class that uses the [qrcodegen](https://github.com/nayuki/QR-Code-generator) library to generate QR codes from QStrings in Qt applications. -[![Screenshot](example/screenshot.png)](example/screenshot.png) +[![Demo](example/demo.gif)](example/demo.gif) ## Usage diff --git a/example/MainWindow.cpp b/example/MainWindow.cpp index 070a0c7..4f0a135 100644 --- a/example/MainWindow.cpp +++ b/example/MainWindow.cpp @@ -22,75 +22,104 @@ #include "MainWindow.h" -MainWindow::MainWindow() { - // Initialize layout-related widgets - m_centralWidget = new QWidget(this); - m_header = new QWidget(m_centralWidget); +#include +#include +#include - // Initialize horizontal layout widgets - m_label = new QLabel(tr("Message") + ": ", m_header); - m_pushButton = new QPushButton(tr("Generate QR Code"), m_header); - m_lineEdit = new QLineEdit(m_header); +MainWindow::MainWindow() +{ + // Initialize layout-related widgets + m_centralWidget = new QWidget(this); + m_header = new QWidget(m_centralWidget); - // Initialize QR code image label - m_qrCodeDisplay = new QLabel(m_centralWidget); - m_qrCodeDisplay->setMinimumSize(QSize(500, 500)); - m_qrCodeDisplay->setMaximumSize(QSize(500, 500)); + // Initialize horizontal layout widgets + m_label = new QLabel(tr("Message") + ": ", m_header); + m_saveButton = new QPushButton(tr("Export QR Code"), m_header); + m_lineEdit = new QLineEdit(m_header); - // Setup horizontal layout for line edit & push button - m_verticalLayout = new QVBoxLayout(m_centralWidget); - m_headerLayout = new QHBoxLayout(m_header); - m_headerLayout->addWidget(m_label); - m_headerLayout->addWidget(m_lineEdit); - m_headerLayout->addWidget(m_pushButton); - m_headerLayout->setContentsMargins(0, 0, 0, 0); - m_headerLayout->setStretch(1, 1); + // Initialize QR code image label + m_qrCodeDisplay = new QLabel(m_centralWidget); + m_qrCodeDisplay->setMinimumSize(QSize(500, 500)); + m_qrCodeDisplay->setMaximumSize(QSize(500, 500)); - // Setup vertical layout with QR code label & QR code generation controls - m_verticalLayout->addWidget(m_header); - m_verticalLayout->addWidget(m_qrCodeDisplay); - m_verticalLayout->setStretch(0, 1); + // Setup horizontal layout for line edit & push button + m_verticalLayout = new QVBoxLayout(m_centralWidget); + m_headerLayout = new QHBoxLayout(m_header); + m_headerLayout->addWidget(m_label); + m_headerLayout->addWidget(m_lineEdit); + m_headerLayout->addWidget(m_saveButton); + m_headerLayout->setContentsMargins(0, 0, 0, 0); + m_headerLayout->setStretch(1, 1); - // Set central widget & resize window to minimum size possible - setCentralWidget(m_centralWidget); - setFixedSize(minimumSize()); + // Setup vertical layout with QR code label & QR code generation controls + m_verticalLayout->addWidget(m_header); + m_verticalLayout->addWidget(m_qrCodeDisplay); + m_verticalLayout->setStretch(0, 1); - // Set window title - setWindowTitle(tr("QR Code Generator")); + // Set central widget & resize window to minimum size possible + setCentralWidget(m_centralWidget); + setFixedSize(minimumSize()); - // Disable "Generate QR code" button when line edit contains empty text - connect(m_lineEdit, &QLineEdit::textChanged, this, [this](const QString& text) { - m_pushButton->setEnabled(!text.isEmpty()); - }); + // Set window title + setWindowTitle(tr("QR Code Generator")); - // Update QR code when user clicks on the generate QR code button - connect(m_pushButton, &QPushButton::clicked, this, &MainWindow::onGenerateButtonClicked); + // Disable "Generate QR code" button when line edit contains empty text + connect(m_lineEdit, &QLineEdit::textChanged, this, + [this](const QString &text) { + m_saveButton->setEnabled(!text.isEmpty()); + if (!text.isEmpty()) + generateQrCode(); + }); - // Set "Hello World" text & generate QR code - m_lineEdit->setText(tr("Hello World!")); - onGenerateButtonClicked(); + // Update QR code when user clicks on the generate QR code button + connect(m_saveButton, &QPushButton::clicked, this, &MainWindow::saveQrCode); + + // Set "Hello World" text & generate QR code + m_lineEdit->setText(tr("Hello World!")); + generateQrCode(); } -MainWindow::~MainWindow() { - delete m_label; - delete m_lineEdit; - delete m_pushButton; - delete m_qrCodeDisplay; - delete m_headerLayout; - delete m_verticalLayout; - delete m_header; - delete m_centralWidget; +MainWindow::~MainWindow() +{ + delete m_label; + delete m_lineEdit; + delete m_saveButton; + delete m_qrCodeDisplay; + delete m_headerLayout; + delete m_verticalLayout; + delete m_header; + delete m_centralWidget; } -void MainWindow::onGenerateButtonClicked() { - // Get text from line edit - auto text = m_lineEdit->text(); +void MainWindow::saveQrCode() +{ + auto svg = m_generator.generateSvgQr(m_lineEdit->text()); + if (svg.isEmpty()) + return; - // Generate QR code from text - QImage unscaledImage = m_generator.generateQr(text); - QImage image = unscaledImage.scaled(500, 500); - - // Display generated image - m_qrCodeDisplay->setPixmap(QPixmap::fromImage(image)); - m_qrCodeDisplay->setToolTip(text); + auto path = QFileDialog::getSaveFileName(this, tr("Save QR Code"), + QDir::homePath(), tr("*.svg")); + if (!path.isEmpty()) + { + QFile file(path); + if (file.open(QFile::WriteOnly)) + { + file.write(svg.toUtf8()); + file.close(); + } + } +} + +void MainWindow::generateQrCode() +{ + // Get text from line edit + auto text = m_lineEdit->text(); + + // Generate QR code from text + QImage unscaledImage = m_generator.generateQr(text); + QImage image = unscaledImage.scaled(500, 500); + + // Display generated image + m_qrCodeDisplay->setPixmap(QPixmap::fromImage(image)); + m_qrCodeDisplay->setToolTip(text); } diff --git a/example/MainWindow.h b/example/MainWindow.h index 90174d2..822e455 100644 --- a/example/MainWindow.h +++ b/example/MainWindow.h @@ -30,27 +30,29 @@ #include -class MainWindow : public QMainWindow { - Q_OBJECT +class MainWindow : public QMainWindow +{ + Q_OBJECT public: - explicit MainWindow(); - ~MainWindow(); + explicit MainWindow(); + ~MainWindow(); private Q_SLOTS: - void onGenerateButtonClicked(); + void saveQrCode(); + void generateQrCode(); private: - QrCodeGenerator m_generator; + QrCodeGenerator m_generator; - QWidget *m_header; - QWidget *m_centralWidget; + QWidget *m_header; + QWidget *m_centralWidget; - QLabel *m_label; - QLineEdit *m_lineEdit; - QLabel *m_qrCodeDisplay; - QPushButton *m_pushButton; + QLabel *m_label; + QLineEdit *m_lineEdit; + QLabel *m_qrCodeDisplay; + QPushButton *m_saveButton; - QHBoxLayout *m_headerLayout; - QVBoxLayout *m_verticalLayout; + QHBoxLayout *m_headerLayout; + QVBoxLayout *m_verticalLayout; }; diff --git a/example/demo.gif b/example/demo.gif new file mode 100644 index 0000000..2c24c88 Binary files /dev/null and b/example/demo.gif differ diff --git a/example/main.cpp b/example/main.cpp index 409376b..f4c0d17 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -22,9 +22,10 @@ #include "MainWindow.h" -int main(int argc, char** argv) { - QApplication app(argc, argv); - MainWindow window; - window.show(); - return app.exec(); +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + MainWindow window; + window.show(); + return app.exec(); } diff --git a/example/screenshot.png b/example/screenshot.png deleted file mode 100644 index 8e0a6da..0000000 Binary files a/example/screenshot.png and /dev/null differ diff --git a/src/QrCodeGenerator.cpp b/src/QrCodeGenerator.cpp index 8bf4ca3..b6ffb8a 100644 --- a/src/QrCodeGenerator.cpp +++ b/src/QrCodeGenerator.cpp @@ -33,9 +33,9 @@ * @param parent QObject parent */ QrCodeGenerator::QrCodeGenerator(QObject *parent) - : QObject(parent) + : QObject(parent) { - // No implementation needed for default constructor. + // No implementation needed for default constructor. } /** @@ -46,12 +46,14 @@ QrCodeGenerator::QrCodeGenerator(QObject *parent) * @param errorCorrection The level of error correction to apply. * @return QImage representing the generated QR code. */ -QImage QrCodeGenerator::generateQr(const QString &data, quint16 size, quint16 borderSize, +QImage QrCodeGenerator::generateQr(const QString &data, quint16 size, + quint16 borderSize, qrcodegen::QrCode::Ecc errorCorrection) { - auto b = data.toUtf8(); - const auto qrCode = qrcodegen::QrCode::encodeText(b.constData(), errorCorrection); - return qrCodeToImage(qrCode, borderSize, size); + auto b = data.toUtf8(); + const auto qrCode + = qrcodegen::QrCode::encodeText(b.constData(), errorCorrection); + return qrCodeToImage(qrCode, borderSize, size); } /** @@ -64,9 +66,10 @@ QImage QrCodeGenerator::generateQr(const QString &data, quint16 size, quint16 bo QString QrCodeGenerator::generateSvgQr(const QString &data, quint16 borderSize, qrcodegen::QrCode::Ecc errorCorrection) { - auto b = data.toUtf8(); - const auto qrCode = qrcodegen::QrCode::encodeText(b.constData(), errorCorrection); - return toSvgString(qrCode, borderSize); + auto b = data.toUtf8(); + const auto qrCode + = qrcodegen::QrCode::encodeText(b.constData(), errorCorrection); + return toSvgString(qrCode, borderSize); } /** @@ -75,31 +78,32 @@ QString QrCodeGenerator::generateSvgQr(const QString &data, quint16 borderSize, * @param border The border size to use. * @return QString containing the SVG representation of the QR code. */ -QString QrCodeGenerator::toSvgString(const qrcodegen::QrCode &qr, quint16 border) const +QString QrCodeGenerator::toSvgString(const qrcodegen::QrCode &qr, + quint16 border) const { - QString str; - QTextStream sb(&str); + QString str; + QTextStream sb(&str); - sb << R"()" - << R"()" - << R"()" + << R"()" + << R"()"; - return str; + sb << R"(" fill="#000000"/>)"; + return str; } /** @@ -109,15 +113,15 @@ QString QrCodeGenerator::toSvgString(const qrcodegen::QrCode &qr, quint16 border * @param size The image size to generate. * @return QImage representing the QR code. */ -QImage QrCodeGenerator::qrCodeToImage(const qrcodegen::QrCode &qrCode, quint16 border, - quint16 size) const +QImage QrCodeGenerator::qrCodeToImage(const qrcodegen::QrCode &qrCode, + quint16 border, quint16 size) const { - QString svg = toSvgString(qrCode, border); - QSvgRenderer render(svg.toUtf8()); - QImage image(size, size, QImage::Format_Mono); - image.fill(Qt::white); - QPainter painter(&image); - painter.setRenderHint(QPainter::Antialiasing); - render.render(&painter); - return image; + QString svg = toSvgString(qrCode, border); + QSvgRenderer render(svg.toUtf8()); + QImage image(size, size, QImage::Format_Mono); + image.fill(Qt::white); + QPainter painter(&image); + painter.setRenderHint(QPainter::Antialiasing); + render.render(&painter); + return image; } diff --git a/src/QrCodeGenerator.h b/src/QrCodeGenerator.h index 694d60b..bd4d840 100644 --- a/src/QrCodeGenerator.h +++ b/src/QrCodeGenerator.h @@ -30,60 +30,66 @@ /** * @class QrCodeGenerator - * @brief The QrCodeGenerator class is a simple C++ class that uses the qrcodegen library - * to generate QR codes from QStrings in Qt applications. + * @brief The QrCodeGenerator class is a simple C++ class that uses the + * qrcodegen library to generate QR codes from QStrings in Qt applications. */ class QrCodeGenerator : public QObject { public: - /** - * @brief Constructs a QrCodeGenerator object. - * @param parent The parent QObject. - */ - explicit QrCodeGenerator(QObject *parent = nullptr); + /** + * @brief Constructs a QrCodeGenerator object. + * @param parent The parent QObject. + */ + explicit QrCodeGenerator(QObject *parent = nullptr); - /** - * @brief Generates a QR code from the given data and error correction level. - * @param data The QString containing the data to encode in the QR code. - * @param size The desired width/height of the generated image (default: 500). - * @param borderSize The desired border width of the generated image (default: 1). - * @param errorCorrection The desired error correction level (default: - * qrcodegen::QrCode::Ecc::MEDIUM). - * - * @return QImage containing the generated QR code. - */ - QImage generateQr(const QString &data, const quint16 size = 1000, const quint16 borderSize = 1, - qrcodegen::QrCode::Ecc errorCorrection = qrcodegen::QrCode::Ecc::MEDIUM); + /** + * @brief Generates a QR code from the given data and error correction level. + * @param data The QString containing the data to encode in the QR code. + * @param size The desired width/height of the generated image (default: 500). + * @param borderSize The desired border width of the generated image (default: + * 1). + * @param errorCorrection The desired error correction level (default: + * qrcodegen::QrCode::Ecc::MEDIUM). + * + * @return QImage containing the generated QR code. + */ + QImage generateQr(const QString &data, const quint16 size = 1000, + const quint16 borderSize = 1, + qrcodegen::QrCode::Ecc errorCorrection + = qrcodegen::QrCode::Ecc::MEDIUM); - /** - * @brief Generates a QR code from the given data and error correction level. - * @param data The QString containing the data to encode in the QR code. - * @param borderSize The desired border width of the generated image (default: 1). - * @param errorCorrection The desired error correction level (default: - * qrcodegen::QrCode::Ecc::MEDIUM). - * - * @return QString string containing the generated QR code in SVG format. - */ - QString generateSvgQr(const QString &data, const quint16 borderSize = 1, - qrcodegen::QrCode::Ecc errorCorrection = qrcodegen::QrCode::Ecc::MEDIUM); + /** + * @brief Generates a QR code from the given data and error correction level. + * @param data The QString containing the data to encode in the QR code. + * @param borderSize The desired border width of the generated image (default: + * 1). + * @param errorCorrection The desired error correction level (default: + * qrcodegen::QrCode::Ecc::MEDIUM). + * + * @return QString string containing the generated QR code in SVG format. + */ + QString generateSvgQr(const QString &data, const quint16 borderSize = 1, + qrcodegen::QrCode::Ecc errorCorrection + = qrcodegen::QrCode::Ecc::MEDIUM); private: - /** - * @brief Converts a qrcodegen::QrCode object to a SVG image. - * @param qrCode The qrcodegen::QrCode object to convert. - * @param border The desired border width of the generated image (default: 1). - * - * @return SVG containing the QR code. - */ - QString toSvgString(const qrcodegen::QrCode &qr, quint16 border) const; + /** + * @brief Converts a qrcodegen::QrCode object to a SVG image. + * @param qrCode The qrcodegen::QrCode object to convert. + * @param border The desired border width of the generated image (default: 1). + * + * @return SVG containing the QR code. + */ + QString toSvgString(const qrcodegen::QrCode &qr, quint16 border) const; - /** - * @brief Converts a qrcodegen::QrCode object to a QImage. - * @param qrCode The qrcodegen::QrCode object to convert. - * @param size The desired width/height of the generated image. - * @param borderSize The desired border width of the generated image. - * - * @return QImage containing the QR code. - */ - QImage qrCodeToImage(const qrcodegen::QrCode &qrCode, quint16 border, const quint16 size) const; + /** + * @brief Converts a qrcodegen::QrCode object to a QImage. + * @param qrCode The qrcodegen::QrCode object to convert. + * @param size The desired width/height of the generated image. + * @param borderSize The desired border width of the generated image. + * + * @return QImage containing the QR code. + */ + QImage qrCodeToImage(const qrcodegen::QrCode &qrCode, quint16 border, + const quint16 size) const; }; diff --git a/src/qrcodegen/qrcodegen.cpp b/src/qrcodegen/qrcodegen.cpp index 9e0e290..b0492e7 100644 --- a/src/qrcodegen/qrcodegen.cpp +++ b/src/qrcodegen/qrcodegen.cpp @@ -4,21 +4,21 @@ * Copyright (c) Project Nayuki. (MIT License) * https://www.nayuki.io/page/qr-code-generator-library * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - The Software is provided "as is", without warranty of any kind, express or * implied, including but not limited to the warranties of merchantability, * fitness for a particular purpose and noninfringement. In no event shall the * authors or copyright holders be liable for any claim, damages or other - * liability, whether in an action of contract, tort or otherwise, arising from, - * out of or in connection with the Software or the use or other dealings in the - * Software. + * liability, whether in an action of contract, tort or otherwise, arising + * from, out of or in connection with the Software or the use or other dealings + * in the Software. */ #include "qrcodegen.h" @@ -37,21 +37,26 @@ using std::size_t; using std::uint8_t; using std::vector; -namespace qrcodegen { +namespace qrcodegen +{ /*---- Class QrSegment ----*/ -QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) : modeBits(mode) { +QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) + : modeBits(mode) +{ numBitsCharCount[0] = cc0; numBitsCharCount[1] = cc1; numBitsCharCount[2] = cc2; } -int QrSegment::Mode::getModeBits() const { +int QrSegment::Mode::getModeBits() const +{ return modeBits; } -int QrSegment::Mode::numCharCountBits(int ver) const { +int QrSegment::Mode::numCharCountBits(int ver) const +{ return numBitsCharCount[(ver + 7) / 17]; } @@ -61,7 +66,8 @@ const QrSegment::Mode QrSegment::Mode::BYTE(0x4, 8, 16, 16); const QrSegment::Mode QrSegment::Mode::KANJI(0x8, 8, 10, 12); const QrSegment::Mode QrSegment::Mode::ECI(0x7, 0, 0, 0); -QrSegment QrSegment::makeBytes(const vector &data) { +QrSegment QrSegment::makeBytes(const vector &data) +{ if (data.size() > static_cast(INT_MAX)) throw std::length_error("Data too long"); BitBuffer bb; @@ -70,60 +76,69 @@ QrSegment QrSegment::makeBytes(const vector &data) { return QrSegment(Mode::BYTE, static_cast(data.size()), std::move(bb)); } -QrSegment QrSegment::makeNumeric(const char *digits) { +QrSegment QrSegment::makeNumeric(const char *digits) +{ BitBuffer bb; int accumData = 0; int accumCount = 0; int charCount = 0; - for (; *digits != '\0'; digits++, charCount++) { + for (; *digits != '\0'; digits++, charCount++) + { char c = *digits; if (c < '0' || c > '9') throw std::domain_error("String contains non-numeric characters"); accumData = accumData * 10 + (c - '0'); accumCount++; - if (accumCount == 3) { + if (accumCount == 3) + { bb.appendBits(static_cast(accumData), 10); accumData = 0; accumCount = 0; } } - if (accumCount > 0) // 1 or 2 digits remaining + if (accumCount > 0) // 1 or 2 digits remaining bb.appendBits(static_cast(accumData), accumCount * 3 + 1); return QrSegment(Mode::NUMERIC, charCount, std::move(bb)); } -QrSegment QrSegment::makeAlphanumeric(const char *text) { +QrSegment QrSegment::makeAlphanumeric(const char *text) +{ BitBuffer bb; int accumData = 0; int accumCount = 0; int charCount = 0; - for (; *text != '\0'; text++, charCount++) { + for (; *text != '\0'; text++, charCount++) + { const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text); if (temp == nullptr) - 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(temp - ALPHANUMERIC_CHARSET); accumCount++; - if (accumCount == 2) { + if (accumCount == 2) + { bb.appendBits(static_cast(accumData), 11); accumData = 0; accumCount = 0; } } - if (accumCount > 0) // 1 character remaining + if (accumCount > 0) // 1 character remaining bb.appendBits(static_cast(accumData), 6); return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb)); } -vector QrSegment::makeSegments(const char *text) { +vector QrSegment::makeSegments(const char *text) +{ // Select the most efficient segment encoding automatically vector result; if (*text == '\0') - ; // Leave result empty + ; // Leave result empty else if (isNumeric(text)) result.push_back(makeNumeric(text)); else if (isAlphanumeric(text)) result.push_back(makeAlphanumeric(text)); - else { + else + { vector bytes; for (; *text != '\0'; text++) bytes.push_back(static_cast(*text)); @@ -132,57 +147,68 @@ vector QrSegment::makeSegments(const char *text) { return result; } -QrSegment QrSegment::makeEci(long assignVal) { +QrSegment QrSegment::makeEci(long assignVal) +{ BitBuffer bb; if (assignVal < 0) throw std::domain_error("ECI assignment value out of range"); else if (assignVal < (1 << 7)) bb.appendBits(static_cast(assignVal), 8); - else if (assignVal < (1 << 14)) { + else if (assignVal < (1 << 14)) + { bb.appendBits(2, 2); bb.appendBits(static_cast(assignVal), 14); - } else if (assignVal < 1000000L) { + } + else if (assignVal < 1000000L) + { bb.appendBits(6, 3); bb.appendBits(static_cast(assignVal), 21); - } else + } + else throw std::domain_error("ECI assignment value out of range"); return QrSegment(Mode::ECI, 0, std::move(bb)); } QrSegment::QrSegment(const Mode &md, int numCh, const std::vector &dt) - : mode(&md), - numChars(numCh), - data(dt) { + : mode(&md) + , numChars(numCh) + , data(dt) +{ if (numCh < 0) throw std::domain_error("Invalid value"); } QrSegment::QrSegment(const Mode &md, int numCh, std::vector &&dt) - : mode(&md), - numChars(numCh), - data(std::move(dt)) { + : mode(&md) + , numChars(numCh) + , data(std::move(dt)) +{ if (numCh < 0) throw std::domain_error("Invalid value"); } -int QrSegment::getTotalBits(const vector &segs, int version) { +int QrSegment::getTotalBits(const vector &segs, int version) +{ int result = 0; - for (const QrSegment &seg : segs) { + for (const QrSegment &seg : segs) + { int ccbits = seg.mode->numCharCountBits(version); if (seg.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) - return -1; // The sum will overflow an int type + return -1; // The sum will overflow an int type result += 4 + ccbits; if (seg.data.size() > static_cast(INT_MAX - result)) - return -1; // The sum will overflow an int type + return -1; // The sum will overflow an int type result += static_cast(seg.data.size()); } return result; } -bool QrSegment::isNumeric(const char *text) { - for (; *text != '\0'; text++) { +bool QrSegment::isNumeric(const char *text) +{ + for (; *text != '\0'; text++) + { char c = *text; if (c < '0' || c > '9') return false; @@ -190,73 +216,90 @@ bool QrSegment::isNumeric(const char *text) { return true; } -bool QrSegment::isAlphanumeric(const char *text) { - for (; *text != '\0'; text++) { +bool QrSegment::isAlphanumeric(const char *text) +{ + for (; *text != '\0'; text++) + { if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr) return false; } return true; } -const QrSegment::Mode &QrSegment::getMode() const { +const QrSegment::Mode &QrSegment::getMode() const +{ return *mode; } -int QrSegment::getNumChars() const { +int QrSegment::getNumChars() const +{ return numChars; } -const std::vector &QrSegment::getData() const { +const std::vector &QrSegment::getData() const +{ return data; } -const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; +const char *QrSegment::ALPHANUMERIC_CHARSET + = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; /*---- Class QrCode ----*/ -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; - default: - throw std::logic_error("Unreachable"); +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; + default: + throw std::logic_error("Unreachable"); } } -QrCode QrCode::encodeText(const char *text, Ecc ecl) { +QrCode QrCode::encodeText(const char *text, Ecc ecl) +{ vector segs = QrSegment::makeSegments(text); return encodeSegments(segs, ecl); } -QrCode QrCode::encodeBinary(const vector &data, Ecc ecl) { +QrCode QrCode::encodeBinary(const vector &data, Ecc ecl) +{ vector segs{QrSegment::makeBytes(data)}; return encodeSegments(segs, ecl); } -QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, int minVersion, - int maxVersion, int mask, bool boostEcl) { - if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) +QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, + int minVersion, int maxVersion, int mask, + bool boostEcl) +{ + if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion + && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) throw std::invalid_argument("Invalid value"); // Find the minimal version number to use int version, dataUsedBits; - for (version = minVersion;; version++) { - int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available + 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 + break; // This version number is found to be suitable + if (version >= maxVersion) + { // All versions in the range could not fit the given data std::ostringstream sb; if (dataUsedBits == -1) sb << "Segment too long"; - else { + else + { sb << "Data length = " << dataUsedBits << " bits, "; sb << "Max capacity = " << dataCapacityBits << " bits"; } @@ -265,15 +308,18 @@ QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, int minVer } 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 + // 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; } // Concatenate all segments to create the data bit string BitBuffer bb; - for (const QrSegment &seg : segs) { + for (const QrSegment &seg : segs) + { bb.appendBits(static_cast(seg.getMode().getModeBits()), 4); bb.appendBits(static_cast(seg.getNumChars()), seg.getMode().numCharCountBits(version)); @@ -282,14 +328,16 @@ QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, int minVer assert(bb.size() == static_cast(dataUsedBits)); // Add terminator and pad up to a byte if applicable - size_t dataCapacityBits = static_cast(getNumDataCodewords(version, ecl)) * 8; + size_t dataCapacityBits + = static_cast(getNumDataCodewords(version, ecl)) * 8; assert(bb.size() <= dataCapacityBits); bb.appendBits(0, std::min(4, static_cast(dataCapacityBits - bb.size()))); bb.appendBits(0, (8 - static_cast(bb.size() % 8)) % 8); assert(bb.size() % 8 == 0); // Pad with alternating bytes until data capacity is reached - for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; + padByte ^= 0xEC ^ 0x11) bb.appendBits(padByte, 8); // Pack bits into bytes in big endian @@ -302,16 +350,17 @@ QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, int minVer } QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int msk) - : // Initialize fields and check arguments - version(ver), - errorCorrectionLevel(ecl) { + : // Initialize fields and check arguments + version(ver) + , errorCorrectionLevel(ecl) +{ if (ver < MIN_VERSION || ver > MAX_VERSION) throw std::domain_error("Version value out of range"); if (msk < -1 || msk > 7) throw std::domain_error("Mask value out of range"); size = ver * 4 + 17; size_t sz = static_cast(size); - modules = vector>(sz, vector(sz)); // Initially all light + modules = vector>(sz, vector(sz)); // Initially all light isFunction = vector>(sz, vector(sz)); // Compute ECC, draw modules @@ -320,56 +369,67 @@ QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int msk) drawCodewords(allCodewords); // Do masking - if (msk == -1) { // Automatically choose best mask + if (msk == -1) + { // Automatically choose best mask long minPenalty = LONG_MAX; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { applyMask(i); drawFormatBits(i); long penalty = getPenaltyScore(); - if (penalty < minPenalty) { + if (penalty < minPenalty) + { msk = i; minPenalty = penalty; } - applyMask(i); // Undoes the mask due to XOR + applyMask(i); // Undoes the mask due to XOR } } assert(0 <= msk && msk <= 7); mask = msk; - applyMask(msk); // Apply the final choice of mask - drawFormatBits(msk); // Overwrite old format bits + applyMask(msk); // Apply the final choice of mask + drawFormatBits(msk); // Overwrite old format bits isFunction.clear(); isFunction.shrink_to_fit(); } -int QrCode::getVersion() const { +int QrCode::getVersion() const +{ return version; } -int QrCode::getSize() const { +int QrCode::getSize() const +{ return size; } -QrCode::Ecc QrCode::getErrorCorrectionLevel() const { +QrCode::Ecc QrCode::getErrorCorrectionLevel() const +{ return errorCorrectionLevel; } -int QrCode::getMask() const { +int QrCode::getMask() const +{ return mask; } -bool QrCode::getModule(int x, int y) const { +bool QrCode::getModule(int x, int y) const +{ return 0 <= x && x < size && 0 <= y && y < size && module(x, y); } -void QrCode::drawFunctionPatterns() { +void QrCode::drawFunctionPatterns() +{ // Draw horizontal and vertical timing patterns - for (int i = 0; i < size; i++) { + for (int i = 0; i < size; i++) + { setFunctionModule(6, i, i % 2 == 0); setFunctionModule(i, 6, i % 2 == 0); } - // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) + // Draw 3 finder patterns (all corners except bottom right; overwrites some + // timing modules) drawFinderPattern(3, 3); drawFinderPattern(size - 4, 3); drawFinderPattern(3, size - 4); @@ -377,26 +437,31 @@ void QrCode::drawFunctionPatterns() { // Draw numerous alignment patterns const vector alignPatPos = getAlignmentPatternPositions(); size_t numAlign = alignPatPos.size(); - for (size_t i = 0; i < numAlign; i++) { - for (size_t j = 0; j < numAlign; j++) { + for (size_t i = 0; i < numAlign; i++) + { + for (size_t j = 0; j < numAlign; j++) + { // Don't draw on the three finder corners - if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) + if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) + || (i == numAlign - 1 && j == 0))) drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j)); } } // Draw configuration data - drawFormatBits(0); // Dummy mask value; overwritten later in the constructor + drawFormatBits(0); // Dummy mask value; overwritten later in the constructor drawVersion(); } -void QrCode::drawFormatBits(int msk) { +void QrCode::drawFormatBits(int msk) +{ // Calculate error correction code and pack bits - int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3 + int data = getFormatBits(errorCorrectionLevel) << 3 + | msk; // errCorrLvl is uint2, msk is uint3 int rem = data; for (int i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >> 9) * 0x537); - int bits = (data << 10 | rem) ^ 0x5412; // uint15 + int bits = (data << 10 | rem) ^ 0x5412; // uint15 assert(bits >> 15 == 0); // Draw first copy @@ -413,22 +478,24 @@ void QrCode::drawFormatBits(int msk) { setFunctionModule(size - 1 - i, 8, getBit(bits, i)); for (int i = 8; i < 15; i++) setFunctionModule(8, size - 15 + i, getBit(bits, i)); - setFunctionModule(8, size - 8, true); // Always dark + setFunctionModule(8, size - 8, true); // Always dark } -void QrCode::drawVersion() { +void QrCode::drawVersion() +{ if (version < 7) return; // Calculate error correction code and pack bits - int rem = version; // version is uint6, in the range [7, 40] + int rem = version; // version is uint6, in the range [7, 40] for (int i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); - long bits = static_cast(version) << 12 | rem; // uint18 + long bits = static_cast(version) << 12 | rem; // uint18 assert(bits >> 18 == 0); // Draw two copies - for (int i = 0; i < 18; i++) { + for (int i = 0; i < 18; i++) + { bool bit = getBit(bits, i); int a = size - 11 + i % 3; int b = i / 3; @@ -437,10 +504,14 @@ void QrCode::drawVersion() { } } -void QrCode::drawFinderPattern(int x, int y) { - for (int dy = -4; dy <= 4; dy++) { - for (int dx = -4; dx <= 4; dx++) { - int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm +void QrCode::drawFinderPattern(int x, int y) +{ + for (int dy = -4; dy <= 4; dy++) + { + for (int dx = -4; dx <= 4; dx++) + { + int dist + = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm int xx = x + dx, yy = y + dy; if (0 <= xx && xx < size && 0 <= yy && yy < size) setFunctionModule(xx, yy, dist != 2 && dist != 4); @@ -448,31 +519,43 @@ void QrCode::drawFinderPattern(int x, int y) { } } -void QrCode::drawAlignmentPattern(int x, int y) { - for (int dy = -2; dy <= 2; dy++) { +void QrCode::drawAlignmentPattern(int x, int y) +{ + for (int dy = -2; dy <= 2; dy++) + { for (int dx = -2; dx <= 2; dx++) - setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1); + setFunctionModule(x + dx, y + dy, + std::max(std::abs(dx), std::abs(dy)) != 1); } } -void QrCode::setFunctionModule(int x, int y, bool isDark) { +void QrCode::setFunctionModule(int x, int y, bool isDark) +{ size_t ux = static_cast(x); size_t uy = static_cast(y); modules.at(uy).at(ux) = isDark; isFunction.at(uy).at(ux) = true; } -bool QrCode::module(int x, int y) const { +bool QrCode::module(int x, int y) const +{ return modules.at(static_cast(y)).at(static_cast(x)); } -vector QrCode::addEccAndInterleave(const vector &data) const { - if (data.size() != static_cast(getNumDataCodewords(version, errorCorrectionLevel))) +vector QrCode::addEccAndInterleave(const vector &data) const +{ + if (data.size() + != static_cast( + getNumDataCodewords(version, errorCorrectionLevel))) throw std::invalid_argument("Invalid argument"); // Calculate parameter numbers - int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)][version]; - int blockEccLen = ECC_CODEWORDS_PER_BLOCK[static_cast(errorCorrectionLevel)][version]; + int numBlocks + = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)] + [version]; + int blockEccLen + = ECC_CODEWORDS_PER_BLOCK[static_cast(errorCorrectionLevel)] + [version]; int rawCodewords = getNumRawDataModules(version) / 8; int numShortBlocks = numBlocks - rawCodewords % numBlocks; int shortBlockLen = rawCodewords / numBlocks; @@ -480,10 +563,12 @@ vector QrCode::addEccAndInterleave(const vector &data) const { // Split data into blocks and append ECC to each block 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))); + for (int i = 0, k = 0; i < numBlocks; i++) + { + vector dat( + data.cbegin() + k, + data.cbegin() + + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); k += static_cast(dat.size()); const vector ecc = reedSolomonComputeRemainder(dat, rsDiv); if (i < numShortBlocks) @@ -492,10 +577,13 @@ vector QrCode::addEccAndInterleave(const vector &data) const { blocks.push_back(std::move(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 vector result; - for (size_t i = 0; i < blocks.at(0).size(); i++) { - for (size_t j = 0; j < blocks.size(); j++) { + for (size_t i = 0; i < blocks.at(0).size(); i++) + { + for (size_t j = 0; j < blocks.size(); j++) + { // Skip the padding byte in short blocks if (i != static_cast(shortBlockLen - blockEccLen) || j >= static_cast(numShortBlocks)) @@ -506,88 +594,108 @@ vector QrCode::addEccAndInterleave(const vector &data) const { return result; } -void QrCode::drawCodewords(const vector &data) { - if (data.size() != static_cast(getNumRawDataModules(version) / 8)) +void QrCode::drawCodewords(const vector &data) +{ + if (data.size() + != static_cast(getNumRawDataModules(version) / 8)) throw std::invalid_argument("Invalid argument"); - size_t i = 0; // Bit index into the data + size_t i = 0; // Bit index into the data // Do the funny zigzag scan - for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair + for (int right = size - 1; right >= 1; right -= 2) + { // Index of right column in each column pair if (right == 6) right = 5; - for (int vert = 0; vert < size; vert++) { // Vertical counter - for (int j = 0; j < 2; j++) { - size_t x = static_cast(right - j); // Actual x coordinate + for (int vert = 0; vert < size; vert++) + { // Vertical counter + for (int j = 0; j < 2; j++) + { + size_t x = static_cast(right - j); // Actual x coordinate bool upward = ((right + 1) & 2) == 0; - size_t y = static_cast(upward ? size - 1 - vert : vert); // Actual y coordinate - if (!isFunction.at(y).at(x) && i < data.size() * 8) { - modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast(i & 7)); + size_t y = static_cast(upward ? size - 1 - vert + : vert); // Actual y coordinate + if (!isFunction.at(y).at(x) && i < data.size() * 8) + { + modules.at(y).at(x) + = getBit(data.at(i >> 3), 7 - static_cast(i & 7)); i++; } - // If this QR Code has any remainder bits (0 to 7), they were assigned as - // 0/false/light by the constructor and are left unchanged by this method + // If this QR Code has any remainder bits (0 to 7), they were assigned + // as 0/false/light by the constructor and are left unchanged by this + // method } } } assert(i == data.size() * 8); } -void QrCode::applyMask(int msk) { +void QrCode::applyMask(int msk) +{ if (msk < 0 || msk > 7) throw std::domain_error("Mask value out of range"); size_t sz = static_cast(size); - for (size_t y = 0; y < sz; y++) { - for (size_t x = 0; x < sz; x++) { + for (size_t y = 0; y < sz; y++) + { + for (size_t x = 0; x < sz; x++) + { bool invert; - switch (msk) { - case 0: - invert = (x + y) % 2 == 0; - break; - case 1: - invert = y % 2 == 0; - break; - case 2: - invert = x % 3 == 0; - break; - case 3: - invert = (x + y) % 3 == 0; - break; - case 4: - invert = (x / 3 + y / 2) % 2 == 0; - break; - case 5: - invert = x * y % 2 + x * y % 3 == 0; - break; - case 6: - invert = (x * y % 2 + x * y % 3) % 2 == 0; - break; - case 7: - invert = ((x + y) % 2 + x * y % 3) % 2 == 0; - break; - default: - throw std::logic_error("Unreachable"); + switch (msk) + { + case 0: + invert = (x + y) % 2 == 0; + break; + case 1: + invert = y % 2 == 0; + break; + case 2: + invert = x % 3 == 0; + break; + case 3: + invert = (x + y) % 3 == 0; + break; + case 4: + invert = (x / 3 + y / 2) % 2 == 0; + break; + case 5: + invert = x * y % 2 + x * y % 3 == 0; + break; + case 6: + invert = (x * y % 2 + x * y % 3) % 2 == 0; + break; + case 7: + invert = ((x + y) % 2 + x * y % 3) % 2 == 0; + break; + default: + throw std::logic_error("Unreachable"); } - modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x)); + modules.at(y).at(x) + = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x)); } } } -long QrCode::getPenaltyScore() const { +long QrCode::getPenaltyScore() const +{ long result = 0; // Adjacent modules in row having same color, and finder-like patterns - for (int y = 0; y < size; y++) { + for (int y = 0; y < size; y++) + { bool runColor = false; int runX = 0; std::array runHistory = {}; - for (int x = 0; x < size; x++) { - if (module(x, y) == runColor) { + for (int x = 0; x < size; x++) + { + if (module(x, y) == runColor) + { runX++; if (runX == 5) result += PENALTY_N1; else if (runX > 5) result++; - } else { + } + else + { finderPenaltyAddHistory(runX, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; @@ -595,21 +703,27 @@ long QrCode::getPenaltyScore() const { runX = 1; } } - result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; + result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) + * PENALTY_N3; } // Adjacent modules in column having same color, and finder-like patterns - for (int x = 0; x < size; x++) { + for (int x = 0; x < size; x++) + { bool runColor = false; int runY = 0; std::array runHistory = {}; - for (int y = 0; y < size; y++) { - if (module(x, y) == runColor) { + for (int y = 0; y < size; y++) + { + if (module(x, y) == runColor) + { runY++; if (runY == 5) result += PENALTY_N1; else if (runY > 5) result++; - } else { + } + else + { finderPenaltyAddHistory(runY, runHistory); if (!runColor) result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; @@ -617,43 +731,56 @@ long QrCode::getPenaltyScore() const { runY = 1; } } - result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; + result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) + * PENALTY_N3; } // 2*2 blocks of modules having same color - for (int y = 0; y < size - 1; y++) { - for (int x = 0; x < size - 1; x++) { + for (int y = 0; y < size - 1; y++) + { + for (int x = 0; x < size - 1; x++) + { bool color = module(x, y); - if (color == module(x + 1, y) && color == module(x, y + 1) && color == module(x + 1, y + 1)) + if (color == module(x + 1, y) && color == module(x, y + 1) + && color == module(x + 1, y + 1)) result += PENALTY_N2; } } // Balance of dark and light modules int dark = 0; - for (const vector &row : modules) { - for (bool color : row) { + for (const vector &row : modules) + { + for (bool color : row) + { if (color) dark++; } } - int total = size * size; // Note that size is odd, so dark/total != 1/2 - // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% - int k = static_cast((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1; + int total = size * size; // Note that size is odd, so dark/total != 1/2 + // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= + // (55+5k)% + int k = static_cast((std::abs(dark * 20L - total * 10L) + total - 1) + / total) + - 1; assert(0 <= k && k <= 9); result += k * PENALTY_N4; assert(0 <= result - && result - <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 + && result <= 2568888L); // Non-tight upper bound based on default + // values of PENALTY_N1, ..., N4 return result; } -vector QrCode::getAlignmentPatternPositions() const { +vector QrCode::getAlignmentPatternPositions() const +{ if (version == 1) return vector(); - else { + else + { int numAlign = version / 7 + 2; - int step = (version == 32) ? 26 : (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; + int step = (version == 32) + ? 26 + : (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; vector result; for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step) result.insert(result.begin(), pos); @@ -662,11 +789,13 @@ vector QrCode::getAlignmentPatternPositions() const { } } -int QrCode::getNumRawDataModules(int ver) { +int QrCode::getNumRawDataModules(int ver) +{ if (ver < MIN_VERSION || ver > MAX_VERSION) throw std::domain_error("Version number out of range"); int result = (16 * ver + 128) * ver + 64; - if (ver >= 2) { + if (ver >= 2) + { int numAlign = ver / 7 + 2; result -= (25 * numAlign - 10) * numAlign - 55; if (ver >= 7) @@ -676,28 +805,33 @@ int QrCode::getNumRawDataModules(int ver) { return result; } -int QrCode::getNumDataCodewords(int ver, Ecc ecl) { +int QrCode::getNumDataCodewords(int ver, Ecc ecl) +{ return getNumRawDataModules(ver) / 8 - ECC_CODEWORDS_PER_BLOCK[static_cast(ecl)][ver] - * NUM_ERROR_CORRECTION_BLOCKS[static_cast(ecl)][ver]; + * NUM_ERROR_CORRECTION_BLOCKS[static_cast(ecl)][ver]; } -vector QrCode::reedSolomonComputeDivisor(int degree) { +vector QrCode::reedSolomonComputeDivisor(int degree) +{ if (degree < 1 || degree > 255) throw std::domain_error("Degree out of range"); - // Polynomial coefficients are stored from highest to lowest power, excluding the leading term - // which is always 1. For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 - // array {255, 8, 93}. + // Polynomial coefficients are stored from highest to lowest power, excluding + // the leading term which is always 1. For example the polynomial x^3 + 255x^2 + // + 8x + 93 is stored as the uint8 array {255, 8, 93}. vector result(static_cast(degree)); - result.at(result.size() - 1) = 1; // Start off with the monomial x^0 + result.at(result.size() - 1) = 1; // Start off with the monomial x^0 - // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), - // and drop the highest monomial term which is always 1x^degree. - // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). + // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x + // - r^{degree-1}), and drop the highest monomial term which is always + // 1x^degree. Note that r = 0x02, which is a generator element of this field + // GF(2^8/0x11D). uint8_t root = 1; - for (int i = 0; i < degree; i++) { + for (int i = 0; i < degree; i++) + { // Multiply the current product by (x - r^i) - for (size_t j = 0; j < result.size(); j++) { + for (size_t j = 0; j < result.size(); j++) + { result.at(j) = reedSolomonMultiply(result.at(j), root); if (j + 1 < result.size()) result.at(j) ^= result.at(j + 1); @@ -707,10 +841,13 @@ vector QrCode::reedSolomonComputeDivisor(int degree) { return result; } -vector QrCode::reedSolomonComputeRemainder(const vector &data, - const vector &divisor) { +vector +QrCode::reedSolomonComputeRemainder(const vector &data, + const vector &divisor) +{ vector result(divisor.size()); - for (uint8_t b : data) { // Polynomial division + for (uint8_t b : data) + { // Polynomial division uint8_t factor = b ^ result.at(0); result.erase(result.begin()); result.push_back(0); @@ -720,10 +857,12 @@ vector QrCode::reedSolomonComputeRemainder(const vector &data, return result; } -uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) { +uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) +{ // Russian peasant multiplication int z = 0; - for (int i = 7; i >= 0; i--) { + for (int i = 7; i >= 0; i--) + { z = (z << 1) ^ ((z >> 7) * 0x11D); z ^= ((y >> i) & 1) * x; } @@ -731,34 +870,43 @@ uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) { return static_cast(z); } -int QrCode::finderPenaltyCountPatterns(const std::array &runHistory) const { +int QrCode::finderPenaltyCountPatterns( + const std::array &runHistory) const +{ int n = runHistory.at(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; + 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); } -int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, - std::array &runHistory) const { - if (currentRunColor) { // Terminate dark run +int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, + int currentRunLength, + std::array &runHistory) const +{ + if (currentRunColor) + { // Terminate dark run finderPenaltyAddHistory(currentRunLength, runHistory); currentRunLength = 0; } - currentRunLength += size; // Add light border to final run + currentRunLength += size; // Add light border to final run finderPenaltyAddHistory(currentRunLength, runHistory); return finderPenaltyCountPatterns(runHistory); } -void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const { +void QrCode::finderPenaltyAddHistory(int currentRunLength, + std::array &runHistory) const +{ if (runHistory.at(0) == 0) - currentRunLength += size; // Add light border to initial run - std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end()); + currentRunLength += size; // Add light border to initial run + std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, + runHistory.end()); runHistory.at(0) = currentRunLength; } -bool QrCode::getBit(long x, int i) { +bool QrCode::getBit(long x, int i) +{ return ((x >> i) & 1) != 0; } @@ -770,44 +918,65 @@ const int QrCode::PENALTY_N3 = 40; const int QrCode::PENALTY_N4 = 10; const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = { - // Version: (note that index 0 is for padding, and is set to an illegal value) - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - // 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level - {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, - 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low - {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, - 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium - {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, - 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile - {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, - 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High + // Version: (note that index 0 is for padding, and is set to an illegal + // value) + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + // 18, 19, 20, 21, 22, 23, + // 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error + // correction level + {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, + 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low + {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, + 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium + {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, + 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile + {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, + 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High }; const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = { - // Version: (note that index 0 is for padding, and is set to an illegal value) - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - // 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level - {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, - 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low - {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, - 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium - {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, - 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile - {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, - 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High + // Version: (note that index 0 is for padding, and is set to an illegal + // value) + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + // 21, 22, 23, 24, 25, + // 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error + // correction level + {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, + 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, + 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low + {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, + 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, + 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium + {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, + 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, + 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile + {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, + 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, + 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High }; -data_too_long::data_too_long(const std::string &msg) : std::length_error(msg) {} +data_too_long::data_too_long(const std::string &msg) + : std::length_error(msg) +{ +} /*---- Class BitBuffer ----*/ -BitBuffer::BitBuffer() : std::vector() {} +BitBuffer::BitBuffer() + : std::vector() +{ +} -void BitBuffer::appendBits(std::uint32_t val, int len) { +void BitBuffer::appendBits(std::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 + for (int i = len - 1; i >= 0; i--) // Append bit by bit this->push_back(((val >> i) & 1) != 0); } -} // namespace qrcodegen +} // namespace qrcodegen diff --git a/src/qrcodegen/qrcodegen.h b/src/qrcodegen/qrcodegen.h index 87c394e..7bbf80a 100644 --- a/src/qrcodegen/qrcodegen.h +++ b/src/qrcodegen/qrcodegen.h @@ -4,21 +4,21 @@ * Copyright (c) Project Nayuki. (MIT License) * https://www.nayuki.io/page/qr-code-generator-library * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - The Software is provided "as is", without warranty of any kind, express or * implied, including but not limited to the warranties of merchantability, * fitness for a particular purpose and noninfringement. In no event shall the * authors or copyright holders be liable for any claim, damages or other - * liability, whether in an action of contract, tort or otherwise, arising from, - * out of or in connection with the Software or the use or other dealings in the - * Software. + * liability, whether in an action of contract, tort or otherwise, arising + * from, out of or in connection with the Software or the use or other dealings + * in the Software. */ #pragma once @@ -29,7 +29,8 @@ #include #include -namespace qrcodegen { +namespace qrcodegen +{ /* * A segment of character/binary/control data in a QR Code symbol. @@ -38,11 +39,13 @@ namespace qrcodegen { * and call a static factory function such as QrSegment::makeNumeric(). * The low-level way to create a segment is to custom-make the bit buffer * and call the QrSegment() constructor with appropriate values. - * This segment class imposes no length restrictions, but QR Codes have restrictions. - * 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. + * This segment class imposes no length restrictions, but QR Codes have + * restrictions. 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 final +{ /*---- Public helper enumeration ----*/ @@ -50,7 +53,8 @@ class QrSegment final { * Describes how a segment's data bits are interpreted. Immutable. */ public: - class Mode final { + class Mode final + { /*-- Constants --*/ @@ -87,15 +91,16 @@ public: /*-- Methods --*/ /* - * (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 - * to 15). + * (Package-private) Returns the mode indicator bits, which is an unsigned + * 4-bit value (range 0 to 15). */ public: int getModeBits() const; /* - * (Package-private) Returns the bit width of the character count field for a segment in - * this mode in a QR Code at the given version number. The result is in the range [0, 16]. + * (Package-private) Returns the bit width of the character count field for + * a segment in this mode in a QR Code at the given version number. The + * result is in the range [0, 16]. */ public: int numCharCountBits(int ver) const; @@ -112,22 +117,25 @@ public: static QrSegment makeBytes(const std::vector &data); /* - * Returns a segment representing the given string of decimal digits encoded in numeric mode. + * Returns a segment representing the given string of decimal digits encoded + * in numeric mode. */ public: static QrSegment makeNumeric(const char *digits); /* - * Returns a segment representing the given text string encoded in alphanumeric mode. - * The characters allowed are: 0 to 9, A to Z (uppercase only), space, - * dollar, percent, asterisk, plus, hyphen, period, slash, colon. + * Returns a segment representing the given text string encoded in + * alphanumeric mode. The characters allowed are: 0 to 9, A to Z (uppercase + * only), space, dollar, percent, asterisk, plus, hyphen, period, slash, + * colon. */ public: static QrSegment makeAlphanumeric(const char *text); /* - * Returns a list of zero or more segments to represent the given text string. The result - * may use various segment modes and switch modes to optimize the length of the bit stream. + * Returns a list of zero or more segments to represent the given text string. + * The result may use various segment modes and switch modes to optimize the + * length of the bit stream. */ public: static std::vector makeSegments(const char *text); @@ -149,9 +157,10 @@ public: static bool isNumeric(const char *text); /* - * Tests whether the given string can be encoded as a segment in alphanumeric mode. - * A string is encodable iff each character is in the following set: 0 to 9, A to Z - * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. + * Tests whether the given string can be encoded as a segment in alphanumeric + * mode. A string is encodable iff each character is in the following set: 0 + * to 9, A to Z (uppercase only), space, dollar, percent, asterisk, plus, + * hyphen, period, slash, colon. */ public: static bool isAlphanumeric(const char *text); @@ -177,16 +186,18 @@ private: /* * Creates a new QR Code segment with the given attributes and data. - * 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 copied and stored. + * 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 copied + * and stored. */ public: QrSegment(const Mode &md, int numCh, const std::vector &dt); /* * Creates a new QR Code segment with the given parameters and data. - * 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. + * 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); @@ -211,9 +222,10 @@ public: public: const std::vector &getData() const; - // (Package-private) Calculates the number of bits needed to encode the given segments at - // the given version. Returns a non-negative number if successful. Otherwise returns -1 if a - // segment has too many characters to fit its length field, or the total bits exceeds INT_MAX. + // (Package-private) Calculates the number of bits needed to encode the given + // segments at the given version. Returns a non-negative number if successful. + // Otherwise returns -1 if a segment has too many characters to fit its length + // field, or the total bits exceeds INT_MAX. public: static int getTotalBits(const std::vector &segs, int version); @@ -228,20 +240,24 @@ private: /* * A QR Code symbol, which is a type of two-dimension barcode. * Invented by Denso Wave and described in the ISO/IEC 18004 standard. - * Instances of this class represent an immutable square grid of dark and light cells. - * The class provides static factory functions to create a QR Code from text or binary data. - * The class covers the QR Code Model 2 specification, supporting all versions (sizes) - * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. + * Instances of this class represent an immutable square grid of dark and light + * cells. The class provides static factory functions to create a QR Code from + * text or binary data. The class covers the QR Code Model 2 specification, + * supporting all versions (sizes) from 1 to 40, all 4 error correction levels, + * and 4 character encoding modes. * * Ways to create a QR Code object: - * - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary(). - * - Mid level: Custom-make the list of segments and call QrCode::encodeSegments(). + * - High level: Take the payload data and call QrCode::encodeText() or + * QrCode::encodeBinary(). + * - Mid level: Custom-make the list of segments and call + * QrCode::encodeSegments(). * - Low level: Custom-make the array of data codeword bytes (including * segment headers and final padding, excluding error correction codewords), * 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 final +{ /*---- Public helper enumeration ----*/ @@ -249,11 +265,12 @@ class QrCode final { * The error correction level in a QR Code symbol. */ public: - enum class 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 - HIGH, // The QR Code can tolerate about 30% erroneous codewords + enum class 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 + HIGH, // The QR Code can tolerate about 30% erroneous codewords }; // Returns a value in the range 0 to 3 (unsigned 2-bit integer). @@ -263,22 +280,24 @@ private: /*---- Static factory functions (high level) ----*/ /* - * Returns a QR Code representing the given Unicode text string at the given error correction - * level. As a conservative upper bound, this function is guaranteed to succeed for strings that - * have 2953 or fewer UTF-8 code units (not Unicode code points) if the low error correction level - * is used. 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. + * Returns a QR Code representing the given Unicode text string at the given + * error correction level. As a conservative upper bound, this function is + * guaranteed to succeed for strings that have 2953 or fewer UTF-8 code units + * (not Unicode code points) if the low error correction level is used. 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 encodeText(const char *text, Ecc ecl); /* - * Returns a QR Code representing the given binary data at the given error correction level. - * This function always encodes using the binary segment mode, not any text mode. The maximum - * number of 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. + * Returns a QR Code representing the given binary data at the given error + * correction level. This function always encodes using the binary segment + * mode, not any text mode. The maximum number of 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); @@ -286,20 +305,22 @@ public: /*---- Static factory functions (mid level) ----*/ /* - * Returns a QR Code representing the given segments with the given encoding parameters. - * The smallest possible QR Code version within the given range is automatically - * chosen for the output. Iff boostEcl is true, then the ECC level of the result - * may be higher than the ecl argument if it can be done without increasing the - * version. The mask number is either between 0 to 7 (inclusive) to force that - * mask, or -1 to automatically choose an appropriate mask (which may be slow). - * This function allows the user to create a custom sequence of segments that switches - * between modes (such as alphanumeric and byte) to encode text in less space. - * This is a mid-level API; the high-level API is encodeText() and encodeBinary(). + * Returns a QR Code representing the given segments with the given encoding + * parameters. The smallest possible QR Code version within the given range is + * automatically chosen for the output. Iff boostEcl is true, then the ECC + * level of the result may be higher than the ecl argument if it can be done + * without increasing the version. The mask number is either between 0 to 7 + * (inclusive) to force that mask, or -1 to automatically choose an + * appropriate mask (which may be slow). This function allows the user to + * create a custom sequence of segments that switches between modes (such as + * alphanumeric and byte) to encode text in less space. This is a mid-level + * API; the high-level API is encodeText() and encodeBinary(). */ public: - static QrCode encodeSegments(const std::vector &segs, Ecc ecl, int minVersion = 1, - int maxVersion = 40, int mask = -1, - bool boostEcl = true); // All optional parameters + static QrCode encodeSegments(const std::vector &segs, Ecc ecl, + int minVersion = 1, int maxVersion = 40, + int mask = -1, + bool boostEcl = true); // All optional parameters /*---- Instance fields ----*/ @@ -319,9 +340,10 @@ private: private: Ecc errorCorrectionLevel; - /* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). - * Even if a QR Code is created with automatic masking requested (mask = -1), - * the resulting object still has a mask value between 0 and 7. */ + /* The index of the mask pattern used in this QR Code, which is between 0 and + * 7 (inclusive). Even if a QR Code is created with automatic masking + * requested (mask = -1), the resulting object still has a mask value between + * 0 and 7. */ private: int mask; @@ -332,8 +354,8 @@ private: private: std::vector> modules; - // Indicates function modules that are not subjected to masking. Discarded when constructor - // finishes. + // Indicates function modules that are not subjected to masking. Discarded + // when constructor finishes. private: std::vector> isFunction; @@ -346,7 +368,8 @@ private: * A mid-level API is the encodeSegments() function. */ public: - QrCode(int ver, Ecc ecl, const std::vector &dataCodewords, int msk); + QrCode(int ver, Ecc ecl, const std::vector &dataCodewords, + int msk); /*---- Public instance methods ----*/ @@ -375,16 +398,18 @@ public: int getMask() const; /* - * Returns the color of the module (pixel) at the given coordinates, which is false - * for light or true for dark. The top left corner has the coordinates (x=0, y=0). - * If the given coordinates are out of bounds, then false (light) is returned. + * Returns the color of the module (pixel) at the given coordinates, which is + * false for light or true for dark. The top left corner has the coordinates + * (x=0, y=0). If the given coordinates are out of bounds, then false (light) + * is returned. */ public: bool getModule(int x, int y) const; /*---- Private helper methods for constructor: Drawing function modules ----*/ - // Reads this object's version field, and draws and marks all function modules. + // Reads this object's version field, and draws and marks all function + // modules. private: void drawFunctionPatterns(); @@ -413,19 +438,23 @@ private: private: void setFunctionModule(int x, int y, bool isDark); - // Returns the color of the module at the given coordinates, which must be in range. + // Returns the color of the module at the given coordinates, which must be in + // range. private: bool module(int x, int y) const; /*---- Private helper methods for constructor: Codewords and masking ----*/ - // 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. + // 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; + 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. + // 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); @@ -437,39 +466,44 @@ private: private: void applyMask(int msk); - // Calculates and returns the penalty score based on state of this QR Code's current modules. - // This is used by the automatic mask choice algorithm to find the mask pattern that yields the - // lowest score. + // Calculates and returns the penalty score based on state of this QR Code's + // current modules. This is used by the automatic mask choice algorithm to + // find the mask pattern that yields the lowest score. private: long getPenaltyScore() const; /*---- Private helper functions ----*/ - // Returns an ascending list of positions of alignment patterns for this version number. - // Each position is in the range [0,177), and are used on both the x and y axes. - // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. + // Returns an ascending list of positions of alignment patterns for this + // version number. Each position is in the range [0,177), and are used on both + // the x and y axes. This could be implemented as lookup table of 40 + // variable-length lists of unsigned bytes. private: std::vector getAlignmentPatternPositions() const; - // Returns the number of data bits that can be stored in a QR Code of the given version number, - // after all function modules are excluded. This includes remainder bits, so it might not be a - // multiple of 8. The result is in the range [208, 29648]. This could be implemented as a 40-entry - // lookup table. + // Returns the number of data bits that can be stored in a QR Code of the + // given version number, after all function modules are excluded. This + // includes remainder bits, so it might not be a multiple of 8. The result is + // in the range [208, 29648]. This could be implemented as a 40-entry lookup + // table. private: static int getNumRawDataModules(int ver); - // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any - // QR Code of the given version number and error correction level, with remainder bits discarded. - // This stateless pure function could be implemented as a (40*4)-cell lookup table. + // Returns the number of 8-bit data (i.e. not error correction) codewords + // contained in any QR Code of the given version number and error correction + // level, with remainder bits discarded. This stateless pure function could be + // implemented as a (40*4)-cell lookup table. private: static int getNumDataCodewords(int ver, Ecc ecl); - // 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. + // 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); - // 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 reedSolomonComputeRemainder(const std::vector &data, @@ -485,16 +519,17 @@ private: private: int finderPenaltyCountPatterns(const std::array &runHistory) 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 &runHistory) 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 &runHistory) const; + void finderPenaltyAddHistory(int currentRunLength, + std::array &runHistory) const; // Returns true iff the i'th bit of x is set to 1. private: @@ -533,19 +568,22 @@ private: /*---- Public exception class ----*/ /* - * Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception - * include: + * Thrown when the supplied data does not fit any QR Code version. Ways to + * handle this exception include: * - Decrease the error correction level if it was greater than Ecc::LOW. - * - If the encodeSegments() function was called with a maxVersion argument, then increase - * it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other - * factory functions because they search all versions up to QrCode::MAX_VERSION.) - * - Split the text data into better or optimal segments in order to reduce the number of bits - * required. + * - If the encodeSegments() function was called with a maxVersion argument, + * then increase it if it was less than QrCode::MAX_VERSION. (This advice does + * not apply to the other factory functions because they search all versions up + * to QrCode::MAX_VERSION.) + * - Split the text data into better or optimal segments in order to reduce the + * number of bits required. * - Change the text or binary data to be shorter. - * - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric). + * - Change the text to fit the character set of a particular segment mode (e.g. + * alphanumeric). * - Propagate the error upward to the caller/user. */ -class data_too_long : public std::length_error { +class data_too_long : public std::length_error +{ public: explicit data_too_long(const std::string &msg); @@ -554,7 +592,8 @@ public: /* * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment. */ -class BitBuffer final : public std::vector { +class BitBuffer final : public std::vector +{ /*---- Constructor ----*/ @@ -570,4 +609,4 @@ public: void appendBits(std::uint32_t val, int len); }; -} // namespace qrcodegen +} // namespace qrcodegen