如何在原生 C/C++ 中使用 Qt 绘制二维码
Posted
技术标签:
【中文标题】如何在原生 C/C++ 中使用 Qt 绘制二维码【英文标题】:How to draw a QR code with Qt in native C/C++ 【发布时间】:2014-02-19 10:28:23 【问题描述】:Qt 中的二维码
作为How to scan for QR codes with Qt 的一个附带问题,我想知道如何在基于 Qt5 的桌面应用程序中从本机 C/C++ 代码绘制QR code,但我找不到如何执行此操作的示例。
我知道QtQR 存在,但它依赖于python-qrtools,在我看来,这首先违背了使用Qt 的目的。我想要一个灵活、高效且无依赖的解决方案,无论我决定使用它,它都能与我的应用程序一起编译。
我该怎么做?
【问题讨论】:
【参考方案1】:以下是我用来更新带有“文本”二维码的表单上的标签(qrCode)的 Qt 代码。标签设置为固定大小(在我的情况下,最小和最大宽度和高度 = 256),并且 scaledContents 为真。您可能会做一些比 RGB32 格式更有效的事情,但对于偶尔的更新来说确实没关系。
void MyClass::updateQrCode( QString text )
using namespace qrcodegen;
// Create the QR Code object
QrCode qr = QrCode::encodeText( text.toUtf8().data(), QrCode::Ecc::MEDIUM );
qint32 sz = qr.getSize();
QImage im(sz,sz, QImage::Format_RGB32);
QRgb black = qRgb( 0, 0, 0);
QRgb white = qRgb(255,255,255);
for (int y = 0; y < sz; y++)
for (int x = 0; x < sz; x++)
im.setPixel(x,y,qr.getModule(x, y) ? black : white );
ui->qrCode->setPixmap( QPixmap::fromImage(im.scaled(256,256,Qt::KeepAspectRatio,Qt::FastTransformation),Qt::MonoOnly) );
使用 Nayuki 库 - 仅来自此处的 QrCode.cpp 和 .hpp 文件:https://github.com/nayuki/QR-Code-generator/tree/master/cpp
通过这个简单的 .pri 文件(与 QrCode 文件保存在同一文件夹中)合并到我的项目中:
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/QrCode.hpp
SOURCES += $$PWD/QrCode.cpp
【讨论】:
【参考方案2】:如果你觉得 Fukuchi 的库对你来说太大[0],可以考虑看看 Nayuki 的 C++ 二维码生成器库[1]:https://github.com/nayuki/QR-Code-generator/tree/master/cpp p>
Nayuki 的库需要 C++11,并且无需 Autotools 即可移植。示例用法:
#include <string>
#include <vector>
#include "QrCode.hpp"
using namespace qrcodegen;
// Create the QR Code object
QrCode qr = QrCode::encodeText("Hello, world!", QrCode::Ecc::MEDIUM);
// Read the black & white pixels
for (int y = 0; y < qr.size; y++)
for (int x = 0; x < qr.size; x++)
int color = qr.getModule(x, y); // 0 for white, 1 for black
// You need to modify this part
draw_pixel_onto_QT(x, y, color);
[0]:Fukuchi:20 个文件,主要 .c 和 .h 文件中约 7200 行(不包括构建和测试代码)。[1]:Nayuki : 6 个文件,主要 .cpp 和 .hpp 文件中约 1400 行(不包括演示代码)。
由 OP 编辑 2016-12-08 经许可,我决定将我自己的改编添加到 Qt。这段代码在我的系统上编译并运行良好,而且我认为它应该足够独立,可以在其他地方工作而无需太多调整。
#include "QrCode.hpp"
void paintQR(QPainter &painter, const QSize sz, const QString &data, QColor fg)
// NOTE: At this point you will use the API to get the encoding and format you want, instead of my hardcoded stuff:
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(data.toUtf8().constData(), qrcodegen::QrCode::Ecc::LOW);
const int s=qr.getSize()>0?qr.getSize():1;
const double w=sz.width();
const double h=sz.height();
const double aspect=w/h;
const double size=((aspect>1.0)?h:w);
const double scale=size/(s+2);
// NOTE: For performance reasons my implementation only draws the foreground parts in supplied color.
// It expects background to be prepared already (in white or whatever is preferred).
painter.setPen(Qt::NoPen);
painter.setBrush(fg);
for(int y=0; y<s; y++)
for(int x=0; x<s; x++)
const int color=qr.getModule(x, y); // 0 for white, 1 for black
if(0!=color)
const double rx1=(x+1)*scale, ry1=(y+1)*scale;
QRectF r(rx1, ry1, scale, scale);
painter.drawRects(&r,1);
用法请看这个painter类。
【讨论】:
嗨!我将您的二维码集成到我的项目中,如果您愿意,我可以使用我制作的 Qt 特定代码编辑您的答案,这样它会更适合我的问题? 如果你有可以编译和运行的实际Qt代码,我会很高兴收到编辑! 我尝试使用您的库,并且我得到了二维码绘图,但是当我扫描它时,它无法识别,扫描仪什么也没有...... @Xsmael 请张贴您输入的文字和您生成的二维码的图片。你可以在这个线程上发表评论,给我发私信,或者开始一个新的 Stack Overflow 问题。我会测试和调试你的案例。 @FractalSpace 您需要在 C 中自己进行像素缩放。您可以从我的相关@987654323@ 和javascript function 中获取想法。【参考方案3】:2016 年 3 月 3 日更新: 我注意到有一个小型库项目可以完成我的回答,但以更“预先打包”的方式。您可以查看here。
Qt 中的二维码
有一个纯 C 语言的小型 QR 码生成器库,没有依赖项,称为 libqrencode。
第 1 步:安装
在您可以使用它之前,您必须先安装它。在我的 Ubuntu 13.10 上,这意味着在 shell 中输入以下内容:
sudo aptitude install libqrencode-dev
在其他平台上,您可能必须自己从源代码构建它。只需下载压缩包并按照source code download 的说明进行操作即可。
第 2 步:项目文件
接下来,您必须将库添加到您的项目中。在我的 Qt5.2.0 项目文件(myproject.pro 或类似文件)中,这意味着附加以下行:
LIBS += -lqrencode
这对于我知道的大多数 Qt 版本来说应该是相似的。
第 3 步:编码
接下来必须编写实际使用该库的代码,将某些输入字符串编码为 QR 格式。那是一行代码:
QRcode *qr=QRcode_encodeString("my string", 1, QR_ECLEVEL_L, QR_MODE_8,0);
注意:在试验了我传递给这个函数的参数后,我了解到需要小心。一些参数组合无缘无故地失败了。例如传递 0 作为版本或使用 QR_MODE_AN 失败并出现“无效参数”。这可能是我正在使用的旧版本库中的错误您已被警告。
第 4 步:渲染图像
最后,在清理之前,您需要将输出转换为位图,以便可以在屏幕上渲染。这比听起来简单。我不会列出一堆假设,而是在这里包含我完整的工作简约 QRWidget 实现。有趣的部分在被覆盖的 paintEvent() 方法中。
QRWidget.hpp
#ifndef QRWIDGET_HPP
#define QRWIDGET_HPP
#include <QWidget>
class QRWidget : public QWidget
Q_OBJECT
private:
QString data;
public:
explicit QRWidget(QWidget *parent = 0);
void setQRData(QString data);
protected:
void paintEvent(QPaintEvent *);
;
#endif // QRWIDGET_HPP
QRWidget.cpp
#include "QRWidget.hpp"
#include <QPainter>
#include <QDebug>
#include <qrencode.h>
QRWidget::QRWidget(QWidget *parent) :
QWidget(parent),
data("Hello QR")//Note: The encoding fails with empty string so I just default to something else. Use the setQRData() call to change this.
void QRWidget::setQRData(QString data)
this->data=data;
update();
void QRWidget::paintEvent(QPaintEvent *pe)
QPainter painter(this);
//NOTE: I have hardcoded some parameters here that would make more sense as variables.
QRcode *qr = QRcode_encodeString(data.toStdString().c_str(), 1, QR_ECLEVEL_L, QR_MODE_8, 0);
if(0!=qr)
QColor fg("black");
QColor bg("white");
painter.setBrush(bg);
painter.setPen(Qt::NoPen);
painter.drawRect(0,0,width(),height());
painter.setBrush(fg);
const int s=qr->width>0?qr->width:1;
const double w=width();
const double h=height();
const double aspect=w/h;
const double scale=((aspect>1.0)?h:w)/s;
for(int y=0;y<s;y++)
const int yy=y*s;
for(int x=0;x<s;x++)
const int xx=yy+x;
const unsigned char b=qr->data[xx];
if(b &0x01)
const double rx1=x*scale, ry1=y*scale;
QRectF r(rx1, ry1, scale, scale);
painter.drawRects(&r,1);
QRcode_free(qr);
else
QColor error("red");
painter.setBrush(error);
painter.drawRect(0,0,width(),height());
qDebug()<<"QR FAIL: "<< strerror(errno);
qr=0;
总结 在这篇小文章中,我总结了使用 Qt 使用 QR 码生成器的经验。
【讨论】:
最好实现函数paintQrCode(QPainter &painter, const QRect &area, const QByteArray &data)
。那么这个函数就可以在QWidget
或QImage
或QGraphicsWidget
上作画,避免重复代码。
你是对的。我想过这样做,但我想尽可能简化我的答案(它有点大)。以后可能会更新!
您可能希望 QRcode *qr = QRcode_encodeString(data.toStdString().c_str(), 1, QR_ECLEVEL_L, QR_MODE_8, 0);
成为 QRcode *qr = QRcode_encodeString(data.toStdString().c_str(), 1, QR_ECLEVEL_L, QR_MODE_8, 1);
具有不区分大小写的二维码
请注意:该库是 LGPL,对于很多用途(例如在 ios 应用程序中的使用)来说限制太多。以上是关于如何在原生 C/C++ 中使用 Qt 绘制二维码的主要内容,如果未能解决你的问题,请参考以下文章