Format code & update example

This commit is contained in:
Alex Spataru
2025-04-16 18:25:57 -05:00
parent 40c941bf1b
commit 05ef848a2a
12 changed files with 835 additions and 652 deletions
+37 -122
View File
@@ -1,123 +1,38 @@
--- BasedOnStyle: LLVM
Language: Cpp Standard: Cpp11
BasedOnStyle: LLVM CommentPragmas: "^!|^:"
AccessModifierOffset: -2 PointerBindsToType: false
AlignAfterOpenBracket: Align SpaceAfterTemplateKeyword: false
AlignConsecutiveAssignments: false BreakBeforeBinaryOperators: All
AlignConsecutiveBitFields: false BreakBeforeBraces: Custom
AlignConsecutiveDeclarations: false BreakBeforeTernaryOperators: true
AlignEscapedNewlines: Right BreakConstructorInitializers: BeforeComma
AlignOperands: true ConstructorInitializerIndentWidth: 2
AlignTrailingComments: true NamespaceIndentation: None
AllowAllArgumentsOnNextLine: false AlignAfterOpenBracket: true
AllowAllConstructorInitializersOnNextLine: false AlwaysBreakTemplateDeclarations: true
AllowAllParametersOfDeclarationOnNextLine: true AllowShortFunctionsOnASingleLine: Inline
AllowShortBlocksOnASingleLine: Empty SortIncludes: false
AllowShortCaseLabelsOnASingleLine: false IndentCaseLabels: true
AllowShortFunctionsOnASingleLine: Empty IndentPPDirectives: AfterHash
AllowShortIfStatementsOnASingleLine: false AccessModifierOffset: -2
AllowShortLoopsOnASingleLine: false IndentWidth: 2
AlwaysBreakAfterDefinitionReturnType: None ColumnLimit: 80
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping: BraceWrapping:
AfterCaseLabel: false AfterClass: true
AfterClass: false AfterControlStatement: true
AfterControlStatement: false AfterEnum: true
AfterEnum: false AfterFunction: true
AfterFunction: false AfterNamespace: true
AfterNamespace: false AfterObjCDeclaration: true
AfterObjCDeclaration: false AfterStruct: true
AfterStruct: false AfterUnion: true
AfterUnion: false BeforeCatch: true
AfterExternBlock: false BeforeElse: true
BeforeCatch: false IndentBraces: false
BeforeElse: false
IndentBraces: false ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE ]
SplitEmptyFunction: false #StatementMacros ['Q_OBJECT', 'Q_UNUSED']
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: '^<config.h>$'
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
...
+18
View File
@@ -3,6 +3,19 @@
.DS_Store .DS_Store
.AppleDouble .AppleDouble
.LSOverride .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 must end with two \r
Icon Icon
@@ -28,3 +41,8 @@ Temporary Items
# Qt project file # Qt project file
*.pro.user *.pro.user
*.user
# Clion
.idea/*
cmake-build-*
+1 -1
View File
@@ -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. 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 ## Usage
+86 -57
View File
@@ -22,75 +22,104 @@
#include "MainWindow.h" #include "MainWindow.h"
MainWindow::MainWindow() { #include <QFile>
// Initialize layout-related widgets #include <QFileDialog>
m_centralWidget = new QWidget(this); #include <QStandardPaths>
m_header = new QWidget(m_centralWidget);
// Initialize horizontal layout widgets MainWindow::MainWindow()
m_label = new QLabel(tr("Message") + ": ", m_header); {
m_pushButton = new QPushButton(tr("Generate QR Code"), m_header); // Initialize layout-related widgets
m_lineEdit = new QLineEdit(m_header); m_centralWidget = new QWidget(this);
m_header = new QWidget(m_centralWidget);
// Initialize QR code image label // Initialize horizontal layout widgets
m_qrCodeDisplay = new QLabel(m_centralWidget); m_label = new QLabel(tr("Message") + ": ", m_header);
m_qrCodeDisplay->setMinimumSize(QSize(500, 500)); m_saveButton = new QPushButton(tr("Export QR Code"), m_header);
m_qrCodeDisplay->setMaximumSize(QSize(500, 500)); m_lineEdit = new QLineEdit(m_header);
// Setup horizontal layout for line edit & push button // Initialize QR code image label
m_verticalLayout = new QVBoxLayout(m_centralWidget); m_qrCodeDisplay = new QLabel(m_centralWidget);
m_headerLayout = new QHBoxLayout(m_header); m_qrCodeDisplay->setMinimumSize(QSize(500, 500));
m_headerLayout->addWidget(m_label); m_qrCodeDisplay->setMaximumSize(QSize(500, 500));
m_headerLayout->addWidget(m_lineEdit);
m_headerLayout->addWidget(m_pushButton);
m_headerLayout->setContentsMargins(0, 0, 0, 0);
m_headerLayout->setStretch(1, 1);
// Setup vertical layout with QR code label & QR code generation controls // Setup horizontal layout for line edit & push button
m_verticalLayout->addWidget(m_header); m_verticalLayout = new QVBoxLayout(m_centralWidget);
m_verticalLayout->addWidget(m_qrCodeDisplay); m_headerLayout = new QHBoxLayout(m_header);
m_verticalLayout->setStretch(0, 1); 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 // Setup vertical layout with QR code label & QR code generation controls
setCentralWidget(m_centralWidget); m_verticalLayout->addWidget(m_header);
setFixedSize(minimumSize()); m_verticalLayout->addWidget(m_qrCodeDisplay);
m_verticalLayout->setStretch(0, 1);
// Set window title // Set central widget & resize window to minimum size possible
setWindowTitle(tr("QR Code Generator")); setCentralWidget(m_centralWidget);
setFixedSize(minimumSize());
// Disable "Generate QR code" button when line edit contains empty text // Set window title
connect(m_lineEdit, &QLineEdit::textChanged, this, [this](const QString& text) { setWindowTitle(tr("QR Code Generator"));
m_pushButton->setEnabled(!text.isEmpty());
});
// Update QR code when user clicks on the generate QR code button // Disable "Generate QR code" button when line edit contains empty text
connect(m_pushButton, &QPushButton::clicked, this, &MainWindow::onGenerateButtonClicked); 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 // Update QR code when user clicks on the generate QR code button
m_lineEdit->setText(tr("Hello World!")); connect(m_saveButton, &QPushButton::clicked, this, &MainWindow::saveQrCode);
onGenerateButtonClicked();
// Set "Hello World" text & generate QR code
m_lineEdit->setText(tr("Hello World!"));
generateQrCode();
} }
MainWindow::~MainWindow() { MainWindow::~MainWindow()
delete m_label; {
delete m_lineEdit; delete m_label;
delete m_pushButton; delete m_lineEdit;
delete m_qrCodeDisplay; delete m_saveButton;
delete m_headerLayout; delete m_qrCodeDisplay;
delete m_verticalLayout; delete m_headerLayout;
delete m_header; delete m_verticalLayout;
delete m_centralWidget; delete m_header;
delete m_centralWidget;
} }
void MainWindow::onGenerateButtonClicked() { void MainWindow::saveQrCode()
// Get text from line edit {
auto text = m_lineEdit->text(); auto svg = m_generator.generateSvgQr(m_lineEdit->text());
if (svg.isEmpty())
return;
// Generate QR code from text auto path = QFileDialog::getSaveFileName(this, tr("Save QR Code"),
QImage unscaledImage = m_generator.generateQr(text); QDir::homePath(), tr("*.svg"));
QImage image = unscaledImage.scaled(500, 500); if (!path.isEmpty())
{
// Display generated image QFile file(path);
m_qrCodeDisplay->setPixmap(QPixmap::fromImage(image)); if (file.open(QFile::WriteOnly))
m_qrCodeDisplay->setToolTip(text); {
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);
} }
+16 -14
View File
@@ -30,27 +30,29 @@
#include <QrCodeGenerator.h> #include <QrCodeGenerator.h>
class MainWindow : public QMainWindow { class MainWindow : public QMainWindow
Q_OBJECT {
Q_OBJECT
public: public:
explicit MainWindow(); explicit MainWindow();
~MainWindow(); ~MainWindow();
private Q_SLOTS: private Q_SLOTS:
void onGenerateButtonClicked(); void saveQrCode();
void generateQrCode();
private: private:
QrCodeGenerator m_generator; QrCodeGenerator m_generator;
QWidget *m_header; QWidget *m_header;
QWidget *m_centralWidget; QWidget *m_centralWidget;
QLabel *m_label; QLabel *m_label;
QLineEdit *m_lineEdit; QLineEdit *m_lineEdit;
QLabel *m_qrCodeDisplay; QLabel *m_qrCodeDisplay;
QPushButton *m_pushButton; QPushButton *m_saveButton;
QHBoxLayout *m_headerLayout; QHBoxLayout *m_headerLayout;
QVBoxLayout *m_verticalLayout; QVBoxLayout *m_verticalLayout;
}; };
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

+6 -5
View File
@@ -22,9 +22,10 @@
#include "MainWindow.h" #include "MainWindow.h"
int main(int argc, char** argv) { int main(int argc, char **argv)
QApplication app(argc, argv); {
MainWindow window; QApplication app(argc, argv);
window.show(); MainWindow window;
return app.exec(); window.show();
return app.exec();
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

+42 -38
View File
@@ -33,9 +33,9 @@
* @param parent QObject parent * @param parent QObject parent
*/ */
QrCodeGenerator::QrCodeGenerator(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. * @param errorCorrection The level of error correction to apply.
* @return QImage representing the generated QR code. * @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) qrcodegen::QrCode::Ecc errorCorrection)
{ {
auto b = data.toUtf8(); auto b = data.toUtf8();
const auto qrCode = qrcodegen::QrCode::encodeText(b.constData(), errorCorrection); const auto qrCode
return qrCodeToImage(qrCode, borderSize, size); = 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, QString QrCodeGenerator::generateSvgQr(const QString &data, quint16 borderSize,
qrcodegen::QrCode::Ecc errorCorrection) qrcodegen::QrCode::Ecc errorCorrection)
{ {
auto b = data.toUtf8(); auto b = data.toUtf8();
const auto qrCode = qrcodegen::QrCode::encodeText(b.constData(), errorCorrection); const auto qrCode
return toSvgString(qrCode, borderSize); = 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. * @param border The border size to use.
* @return QString containing the SVG representation of the QR code. * @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; QString str;
QTextStream sb(&str); QTextStream sb(&str);
sb << R"(<?xml version="1.0" encoding="UTF-8"?>)" sb << R"(<?xml version="1.0" encoding="UTF-8"?>)"
<< R"(<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">)" << R"(<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">)"
<< R"(<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 )" << R"(<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 )"
<< (qr.getSize() + border * 2) << " " << (qr.getSize() + border * 2) << (qr.getSize() + border * 2) << " " << (qr.getSize() + border * 2)
<< R"(" stroke="none"><rect width="100%" height="100%" fill="#FFFFFF"/><path d=")"; << R"(" stroke="none"><rect width="100%" height="100%" fill="#FFFFFF"/><path d=")";
for (int y = 0; y < qr.getSize(); y++) for (int y = 0; y < qr.getSize(); y++)
{
for (int x = 0; x < qr.getSize(); x++)
{ {
for (int x = 0; x < qr.getSize(); x++) if (qr.getModule(x, y))
{ {
if (qr.getModule(x, y)) sb << (x == 0 && y == 0 ? "" : " ") << "M" << (x + border) << ","
{ << (y + border) << "h1v1h-1z";
sb << (x == 0 && y == 0 ? "" : " ") << "M" << (x + border) << "," << (y + border) }
<< "h1v1h-1z";
}
}
} }
}
sb << R"(" fill="#000000"/></svg>)"; sb << R"(" fill="#000000"/></svg>)";
return str; return str;
} }
/** /**
@@ -109,15 +113,15 @@ QString QrCodeGenerator::toSvgString(const qrcodegen::QrCode &qr, quint16 border
* @param size The image size to generate. * @param size The image size to generate.
* @return QImage representing the QR code. * @return QImage representing the QR code.
*/ */
QImage QrCodeGenerator::qrCodeToImage(const qrcodegen::QrCode &qrCode, quint16 border, QImage QrCodeGenerator::qrCodeToImage(const qrcodegen::QrCode &qrCode,
quint16 size) const quint16 border, quint16 size) const
{ {
QString svg = toSvgString(qrCode, border); QString svg = toSvgString(qrCode, border);
QSvgRenderer render(svg.toUtf8()); QSvgRenderer render(svg.toUtf8());
QImage image(size, size, QImage::Format_Mono); QImage image(size, size, QImage::Format_Mono);
image.fill(Qt::white); image.fill(Qt::white);
QPainter painter(&image); QPainter painter(&image);
painter.setRenderHint(QPainter::Antialiasing); painter.setRenderHint(QPainter::Antialiasing);
render.render(&painter); render.render(&painter);
return image; return image;
} }
+53 -47
View File
@@ -30,60 +30,66 @@
/** /**
* @class QrCodeGenerator * @class QrCodeGenerator
* @brief The QrCodeGenerator class is a simple C++ class that uses the qrcodegen library * @brief The QrCodeGenerator class is a simple C++ class that uses the
* to generate QR codes from QStrings in Qt applications. * qrcodegen library to generate QR codes from QStrings in Qt applications.
*/ */
class QrCodeGenerator : public QObject class QrCodeGenerator : public QObject
{ {
public: public:
/** /**
* @brief Constructs a QrCodeGenerator object. * @brief Constructs a QrCodeGenerator object.
* @param parent The parent QObject. * @param parent The parent QObject.
*/ */
explicit QrCodeGenerator(QObject *parent = nullptr); explicit QrCodeGenerator(QObject *parent = nullptr);
/** /**
* @brief Generates a QR code from the given data and error correction level. * @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 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 size The desired width/height of the generated image (default: 500).
* @param borderSize The desired border width of the generated image (default: 1). * @param borderSize The desired border width of the generated image (default:
* @param errorCorrection The desired error correction level (default: * 1).
* qrcodegen::QrCode::Ecc::MEDIUM). * @param errorCorrection The desired error correction level (default:
* * qrcodegen::QrCode::Ecc::MEDIUM).
* @return QImage containing the generated QR code. *
*/ * @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); 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. * @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 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 borderSize The desired border width of the generated image (default:
* @param errorCorrection The desired error correction level (default: * 1).
* qrcodegen::QrCode::Ecc::MEDIUM). * @param errorCorrection The desired error correction level (default:
* * qrcodegen::QrCode::Ecc::MEDIUM).
* @return QString string containing the generated QR code in SVG format. *
*/ * @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); QString generateSvgQr(const QString &data, const quint16 borderSize = 1,
qrcodegen::QrCode::Ecc errorCorrection
= qrcodegen::QrCode::Ecc::MEDIUM);
private: private:
/** /**
* @brief Converts a qrcodegen::QrCode object to a SVG image. * @brief Converts a qrcodegen::QrCode object to a SVG image.
* @param qrCode The qrcodegen::QrCode object to convert. * @param qrCode The qrcodegen::QrCode object to convert.
* @param border The desired border width of the generated image (default: 1). * @param border The desired border width of the generated image (default: 1).
* *
* @return SVG containing the QR code. * @return SVG containing the QR code.
*/ */
QString toSvgString(const qrcodegen::QrCode &qr, quint16 border) const; QString toSvgString(const qrcodegen::QrCode &qr, quint16 border) const;
/** /**
* @brief Converts a qrcodegen::QrCode object to a QImage. * @brief Converts a qrcodegen::QrCode object to a QImage.
* @param qrCode The qrcodegen::QrCode object to convert. * @param qrCode The qrcodegen::QrCode object to convert.
* @param size The desired width/height of the generated image. * @param size The desired width/height of the generated image.
* @param borderSize The desired border width of the generated image. * @param borderSize The desired border width of the generated image.
* *
* @return QImage containing the QR code. * @return QImage containing the QR code.
*/ */
QImage qrCodeToImage(const qrcodegen::QrCode &qrCode, quint16 border, const quint16 size) const; QImage qrCodeToImage(const qrcodegen::QrCode &qrCode, quint16 border,
const quint16 size) const;
}; };
File diff suppressed because it is too large Load Diff
+157 -118
View File
@@ -4,21 +4,21 @@
* Copyright (c) Project Nayuki. (MIT License) * Copyright (c) Project Nayuki. (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library * https://www.nayuki.io/page/qr-code-generator-library
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of * Permission is hereby granted, free of charge, to any person obtaining a copy
* this software and associated documentation files (the "Software"), to deal in * of this software and associated documentation files (the "Software"), to deal
* the Software without restriction, including without limitation the rights to * in the Software without restriction, including without limitation the rights
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* the Software, and to permit persons to whom the Software is furnished to do so, * copies of the Software, and to permit persons to whom the Software is
* subject to the following conditions: * furnished to do so, subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in * - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or * - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability, * implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the * fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other * authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from, * liability, whether in an action of contract, tort or otherwise, arising
* out of or in connection with the Software or the use or other dealings in the * from, out of or in connection with the Software or the use or other dealings
* Software. * in the Software.
*/ */
#pragma once #pragma once
@@ -29,7 +29,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace qrcodegen { namespace qrcodegen
{
/* /*
* A segment of character/binary/control data in a QR Code symbol. * A segment of character/binary/control data in a QR Code symbol.
@@ -38,11 +39,13 @@ namespace qrcodegen {
* and call a static factory function such as QrSegment::makeNumeric(). * 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 * The low-level way to create a segment is to custom-make the bit buffer
* and call the QrSegment() constructor with appropriate values. * and call the QrSegment() constructor with appropriate values.
* This segment class imposes no length restrictions, but QR Codes have restrictions. * This segment class imposes no length restrictions, but QR Codes have
* Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. * restrictions. Even in the most favorable conditions, a QR Code can only hold
* Any segment longer than this is meaningless for the purpose of generating QR Codes. * 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 ----*/ /*---- Public helper enumeration ----*/
@@ -50,7 +53,8 @@ class QrSegment final {
* Describes how a segment's data bits are interpreted. Immutable. * Describes how a segment's data bits are interpreted. Immutable.
*/ */
public: public:
class Mode final { class Mode final
{
/*-- Constants --*/ /*-- Constants --*/
@@ -87,15 +91,16 @@ public:
/*-- Methods --*/ /*-- Methods --*/
/* /*
* (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 * (Package-private) Returns the mode indicator bits, which is an unsigned
* to 15). * 4-bit value (range 0 to 15).
*/ */
public: public:
int getModeBits() const; int getModeBits() const;
/* /*
* (Package-private) Returns the bit width of the character count field for a segment in * (Package-private) Returns the bit width of the character count field for
* this mode in a QR Code at the given version number. The result is in the range [0, 16]. * a segment in this mode in a QR Code at the given version number. The
* result is in the range [0, 16].
*/ */
public: public:
int numCharCountBits(int ver) const; int numCharCountBits(int ver) const;
@@ -112,22 +117,25 @@ public:
static QrSegment makeBytes(const std::vector<std::uint8_t> &data); static QrSegment makeBytes(const std::vector<std::uint8_t> &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: public:
static QrSegment makeNumeric(const char *digits); static QrSegment makeNumeric(const char *digits);
/* /*
* Returns a segment representing the given text string encoded in alphanumeric mode. * Returns a segment representing the given text string encoded in
* The characters allowed are: 0 to 9, A to Z (uppercase only), space, * alphanumeric mode. The characters allowed are: 0 to 9, A to Z (uppercase
* dollar, percent, asterisk, plus, hyphen, period, slash, colon. * only), space, dollar, percent, asterisk, plus, hyphen, period, slash,
* colon.
*/ */
public: public:
static QrSegment makeAlphanumeric(const char *text); static QrSegment makeAlphanumeric(const char *text);
/* /*
* Returns a list of zero or more segments to represent the given text string. The result * Returns a list of zero or more segments to represent the given text string.
* may use various segment modes and switch modes to optimize the length of the bit stream. * The result may use various segment modes and switch modes to optimize the
* length of the bit stream.
*/ */
public: public:
static std::vector<QrSegment> makeSegments(const char *text); static std::vector<QrSegment> makeSegments(const char *text);
@@ -149,9 +157,10 @@ public:
static bool isNumeric(const char *text); static bool isNumeric(const char *text);
/* /*
* Tests whether the given string can be encoded as a segment in alphanumeric mode. * Tests whether the given string can be encoded as a segment in alphanumeric
* A string is encodable iff each character is in the following set: 0 to 9, A to Z * mode. A string is encodable iff each character is in the following set: 0
* (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. * to 9, A to Z (uppercase only), space, dollar, percent, asterisk, plus,
* hyphen, period, slash, colon.
*/ */
public: public:
static bool isAlphanumeric(const char *text); static bool isAlphanumeric(const char *text);
@@ -177,16 +186,18 @@ private:
/* /*
* Creates a new QR Code segment with the given attributes and data. * 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, * The character count (numCh) must agree with the mode and the bit buffer
* but the constraint isn't checked. The given bit buffer is copied and stored. * length, but the constraint isn't checked. The given bit buffer is copied
* and stored.
*/ */
public: public:
QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt); QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt);
/* /*
* Creates a new QR Code segment with the given parameters and data. * 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, * The character count (numCh) must agree with the mode and the bit buffer
* but the constraint isn't checked. The given bit buffer is moved and stored. * length, but the constraint isn't checked. The given bit buffer is moved and
* stored.
*/ */
public: public:
QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt); QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt);
@@ -211,9 +222,10 @@ public:
public: public:
const std::vector<bool> &getData() const; const std::vector<bool> &getData() const;
// (Package-private) Calculates the number of bits needed to encode the given segments at // (Package-private) Calculates the number of bits needed to encode the given
// the given version. Returns a non-negative number if successful. Otherwise returns -1 if a // segments at the given version. Returns a non-negative number if successful.
// segment has too many characters to fit its length field, or the total bits exceeds INT_MAX. // Otherwise returns -1 if a segment has too many characters to fit its length
// field, or the total bits exceeds INT_MAX.
public: public:
static int getTotalBits(const std::vector<QrSegment> &segs, int version); static int getTotalBits(const std::vector<QrSegment> &segs, int version);
@@ -228,20 +240,24 @@ private:
/* /*
* A QR Code symbol, which is a type of two-dimension barcode. * A QR Code symbol, which is a type of two-dimension barcode.
* Invented by Denso Wave and described in the ISO/IEC 18004 standard. * 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. * Instances of this class represent an immutable square grid of dark and light
* The class provides static factory functions to create a QR Code from text or binary data. * cells. The class provides static factory functions to create a QR Code from
* The class covers the QR Code Model 2 specification, supporting all versions (sizes) * text or binary data. The class covers the QR Code Model 2 specification,
* from 1 to 40, all 4 error correction levels, and 4 character encoding modes. * 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: * Ways to create a QR Code object:
* - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary(). * - High level: Take the payload data and call QrCode::encodeText() or
* - Mid level: Custom-make the list of segments and call QrCode::encodeSegments(). * 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 * - Low level: Custom-make the array of data codeword bytes (including
* segment headers and final padding, excluding error correction codewords), * segment headers and final padding, excluding error correction codewords),
* supply the appropriate version number, and call the QrCode() constructor. * supply the appropriate version number, and call the QrCode() constructor.
* (Note that all ways require supplying the desired error correction level.) * (Note that all ways require supplying the desired error correction level.)
*/ */
class QrCode final { class QrCode final
{
/*---- Public helper enumeration ----*/ /*---- Public helper enumeration ----*/
@@ -249,11 +265,12 @@ class QrCode final {
* The error correction level in a QR Code symbol. * The error correction level in a QR Code symbol.
*/ */
public: public:
enum class Ecc { enum class Ecc
LOW = 0, // The QR Code can tolerate about 7% erroneous codewords {
MEDIUM, // The QR Code can tolerate about 15% erroneous codewords LOW = 0, // The QR Code can tolerate about 7% erroneous codewords
QUARTILE, // The QR Code can tolerate about 25% erroneous codewords MEDIUM, // The QR Code can tolerate about 15% erroneous codewords
HIGH, // The QR Code can tolerate about 30% 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). // Returns a value in the range 0 to 3 (unsigned 2-bit integer).
@@ -263,22 +280,24 @@ private:
/*---- Static factory functions (high level) ----*/ /*---- Static factory functions (high level) ----*/
/* /*
* Returns a QR Code representing the given Unicode text string at the given error correction * Returns a QR Code representing the given Unicode text string at the given
* level. As a conservative upper bound, this function is guaranteed to succeed for strings that * error correction level. As a conservative upper bound, this function is
* have 2953 or fewer UTF-8 code units (not Unicode code points) if the low error correction level * guaranteed to succeed for strings that have 2953 or fewer UTF-8 code units
* is used. The smallest possible QR Code version is automatically chosen for the output. The ECC * (not Unicode code points) if the low error correction level is used. The
* level of the result may be higher than the ecl argument if it can be done without increasing * smallest possible QR Code version is automatically chosen for the output.
* the version. * The ECC level of the result may be higher than the ecl argument if it can
* be done without increasing the version.
*/ */
public: public:
static QrCode encodeText(const char *text, Ecc ecl); static QrCode encodeText(const char *text, Ecc ecl);
/* /*
* Returns a QR Code representing the given binary data at the given error correction level. * Returns a QR Code representing the given binary data at the given error
* This function always encodes using the binary segment mode, not any text mode. The maximum * correction level. This function always encodes using the binary segment
* number of bytes allowed is 2953. The smallest possible QR Code version is automatically chosen * mode, not any text mode. The maximum number of bytes allowed is 2953. The
* for the output. The ECC level of the result may be higher than the ecl argument if it can be * smallest possible QR Code version is automatically chosen for the output.
* done without increasing the version. * The ECC level of the result may be higher than the ecl argument if it can
* be done without increasing the version.
*/ */
public: public:
static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl); static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl);
@@ -286,20 +305,22 @@ public:
/*---- Static factory functions (mid level) ----*/ /*---- Static factory functions (mid level) ----*/
/* /*
* Returns a QR Code representing the given segments with the given encoding parameters. * Returns a QR Code representing the given segments with the given encoding
* The smallest possible QR Code version within the given range is automatically * parameters. The smallest possible QR Code version within the given range is
* chosen for the output. Iff boostEcl is true, then the ECC level of the result * automatically chosen for the output. Iff boostEcl is true, then the ECC
* may be higher than the ecl argument if it can be done without increasing the * level of the result may be higher than the ecl argument if it can be done
* version. The mask number is either between 0 to 7 (inclusive) to force that * without increasing the version. The mask number is either between 0 to 7
* mask, or -1 to automatically choose an appropriate mask (which may be slow). * (inclusive) to force that mask, or -1 to automatically choose an
* This function allows the user to create a custom sequence of segments that switches * appropriate mask (which may be slow). This function allows the user to
* between modes (such as alphanumeric and byte) to encode text in less space. * create a custom sequence of segments that switches between modes (such as
* This is a mid-level API; the high-level API is encodeText() and encodeBinary(). * alphanumeric and byte) to encode text in less space. This is a mid-level
* API; the high-level API is encodeText() and encodeBinary().
*/ */
public: public:
static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl, int minVersion = 1, static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
int maxVersion = 40, int mask = -1, int minVersion = 1, int maxVersion = 40,
bool boostEcl = true); // All optional parameters int mask = -1,
bool boostEcl = true); // All optional parameters
/*---- Instance fields ----*/ /*---- Instance fields ----*/
@@ -319,9 +340,10 @@ private:
private: private:
Ecc errorCorrectionLevel; Ecc errorCorrectionLevel;
/* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). /* The index of the mask pattern used in this QR Code, which is between 0 and
* Even if a QR Code is created with automatic masking requested (mask = -1), * 7 (inclusive). Even if a QR Code is created with automatic masking
* the resulting object still has a mask value between 0 and 7. */ * requested (mask = -1), the resulting object still has a mask value between
* 0 and 7. */
private: private:
int mask; int mask;
@@ -332,8 +354,8 @@ private:
private: private:
std::vector<std::vector<bool>> modules; std::vector<std::vector<bool>> modules;
// Indicates function modules that are not subjected to masking. Discarded when constructor // Indicates function modules that are not subjected to masking. Discarded
// finishes. // when constructor finishes.
private: private:
std::vector<std::vector<bool>> isFunction; std::vector<std::vector<bool>> isFunction;
@@ -346,7 +368,8 @@ private:
* A mid-level API is the encodeSegments() function. * A mid-level API is the encodeSegments() function.
*/ */
public: public:
QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk); QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords,
int msk);
/*---- Public instance methods ----*/ /*---- Public instance methods ----*/
@@ -375,16 +398,18 @@ public:
int getMask() const; int getMask() const;
/* /*
* Returns the color of the module (pixel) at the given coordinates, which is false * Returns the color of the module (pixel) at the given coordinates, which is
* for light or true for dark. The top left corner has the coordinates (x=0, y=0). * false for light or true for dark. The top left corner has the coordinates
* If the given coordinates are out of bounds, then false (light) is returned. * (x=0, y=0). If the given coordinates are out of bounds, then false (light)
* is returned.
*/ */
public: public:
bool getModule(int x, int y) const; bool getModule(int x, int y) const;
/*---- Private helper methods for constructor: Drawing function modules ----*/ /*---- 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: private:
void drawFunctionPatterns(); void drawFunctionPatterns();
@@ -413,19 +438,23 @@ private:
private: private:
void setFunctionModule(int x, int y, bool isDark); 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: private:
bool module(int x, int y) const; bool module(int x, int y) const;
/*---- Private helper methods for constructor: Codewords and masking ----*/ /*---- Private helper methods for constructor: Codewords and masking ----*/
// Returns a new byte string representing the given data with the appropriate error correction // Returns a new byte string representing the given data with the appropriate
// codewords appended to it, based on this object's version and error correction level. // error correction codewords appended to it, based on this object's version
// and error correction level.
private: private:
std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data) const; std::vector<std::uint8_t>
addEccAndInterleave(const std::vector<std::uint8_t> &data) const;
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire // Draws the given sequence of 8-bit codewords (data and error correction)
// data area of this QR Code. Function modules need to be marked off before this is called. // onto the entire data area of this QR Code. Function modules need to be
// marked off before this is called.
private: private:
void drawCodewords(const std::vector<std::uint8_t> &data); void drawCodewords(const std::vector<std::uint8_t> &data);
@@ -437,39 +466,44 @@ private:
private: private:
void applyMask(int msk); void applyMask(int msk);
// Calculates and returns the penalty score based on state of this QR Code's current modules. // Calculates and returns the penalty score based on state of this QR Code's
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the // current modules. This is used by the automatic mask choice algorithm to
// lowest score. // find the mask pattern that yields the lowest score.
private: private:
long getPenaltyScore() const; long getPenaltyScore() const;
/*---- Private helper functions ----*/ /*---- Private helper functions ----*/
// Returns an ascending list of positions of alignment patterns for this version number. // Returns an ascending list of positions of alignment patterns for this
// Each position is in the range [0,177), and are used on both the x and y axes. // version number. Each position is in the range [0,177), and are used on both
// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. // the x and y axes. This could be implemented as lookup table of 40
// variable-length lists of unsigned bytes.
private: private:
std::vector<int> getAlignmentPatternPositions() const; std::vector<int> getAlignmentPatternPositions() const;
// Returns the number of data bits that can be stored in a QR Code of the given version number, // Returns the number of data bits that can be stored in a QR Code of the
// after all function modules are excluded. This includes remainder bits, so it might not be a // given version number, after all function modules are excluded. This
// multiple of 8. The result is in the range [208, 29648]. This could be implemented as a 40-entry // includes remainder bits, so it might not be a multiple of 8. The result is
// lookup table. // in the range [208, 29648]. This could be implemented as a 40-entry lookup
// table.
private: private:
static int getNumRawDataModules(int ver); static int getNumRawDataModules(int ver);
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any // Returns the number of 8-bit data (i.e. not error correction) codewords
// QR Code of the given version number and error correction level, with remainder bits discarded. // contained in any QR Code of the given version number and error correction
// This stateless pure function could be implemented as a (40*4)-cell lookup table. // level, with remainder bits discarded. This stateless pure function could be
// implemented as a (40*4)-cell lookup table.
private: private:
static int getNumDataCodewords(int ver, Ecc ecl); static int getNumDataCodewords(int ver, Ecc ecl);
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be // Returns a Reed-Solomon ECC generator polynomial for the given degree. This
// implemented as a lookup table over all possible parameter values, instead of as an algorithm. // could be implemented as a lookup table over all possible parameter values,
// instead of as an algorithm.
private: private:
static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree); static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree);
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. // Returns the Reed-Solomon error correction codeword for the given data and
// divisor polynomials.
private: private:
static std::vector<std::uint8_t> static std::vector<std::uint8_t>
reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data,
@@ -485,16 +519,17 @@ private:
private: private:
int finderPenaltyCountPatterns(const std::array<int, 7> &runHistory) const; int finderPenaltyCountPatterns(const std::array<int, 7> &runHistory) const;
// Must be called at the end of a line (row or column) of modules. A helper function for // Must be called at the end of a line (row or column) of modules. A helper
// getPenaltyScore(). // function for getPenaltyScore().
private: private:
int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength,
std::array<int, 7> &runHistory) const; std::array<int, 7> &runHistory) const;
// Pushes the given value to the front and drops the last value. A helper function for // Pushes the given value to the front and drops the last value. A helper
// getPenaltyScore(). // function for getPenaltyScore().
private: private:
void finderPenaltyAddHistory(int currentRunLength, std::array<int, 7> &runHistory) const; void finderPenaltyAddHistory(int currentRunLength,
std::array<int, 7> &runHistory) const;
// Returns true iff the i'th bit of x is set to 1. // Returns true iff the i'th bit of x is set to 1.
private: private:
@@ -533,19 +568,22 @@ private:
/*---- Public exception class ----*/ /*---- Public exception class ----*/
/* /*
* Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception * Thrown when the supplied data does not fit any QR Code version. Ways to
* include: * handle this exception include:
* - Decrease the error correction level if it was greater than Ecc::LOW. * - Decrease the error correction level if it was greater than Ecc::LOW.
* - If the encodeSegments() function was called with a maxVersion argument, then increase * - If the encodeSegments() function was called with a maxVersion argument,
* it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other * then increase it if it was less than QrCode::MAX_VERSION. (This advice does
* factory functions because they search all versions up to QrCode::MAX_VERSION.) * not apply to the other factory functions because they search all versions up
* - Split the text data into better or optimal segments in order to reduce the number of bits * to QrCode::MAX_VERSION.)
* required. * - 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 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. * - 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: public:
explicit data_too_long(const std::string &msg); 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. * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment.
*/ */
class BitBuffer final : public std::vector<bool> { class BitBuffer final : public std::vector<bool>
{
/*---- Constructor ----*/ /*---- Constructor ----*/
@@ -570,4 +609,4 @@ public:
void appendBits(std::uint32_t val, int len); void appendBits(std::uint32_t val, int len);
}; };
} // namespace qrcodegen } // namespace qrcodegen