如何在原生 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 &amp;painter, const QRect &amp;area, const QByteArray &amp;data)。那么这个函数就可以在QWidgetQImageQGraphicsWidget上作画,避免重复代码。 你是对的。我想过这样做,但我想尽可能简化我的答案(它有点大)。以后可能会更新! 您可能希望 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 绘制二维码的主要内容,如果未能解决你的问题,请参考以下文章

如何在本机C ++中用QML绘制二维码[重复]

求tubor c C语言三维图形代码,越多越好

Qt__绘制系统

Qt QML 在Map中使用实现二维螺旋曲线(螺旋曲线二)

Qt QML 在Map中使用实现二维螺旋曲线(螺旋曲线二)

Qt QML 在Map中使用实现二维螺旋曲线(螺旋曲线二)