How to draw a QR code with Qt in native C/C++

2019-01-21 20:09发布

QR in Qt

As a companion question to How to scan for QR codes with Qt, I want to know how to draw a QR code from native C/C++ code in my Qt5 based desktop app, but I could not find an example of how to do this.

I know QtQR exists, but it has dependencies on python-qrtools which in my opinion kind of defeats the purpose of using Qt in the first place. I want a nimble, efficient and dependency-free solution that will compile with my app wherever I decided to take it.

How can I do that?

2条回答
来,给爷笑一个
2楼-- · 2019-01-21 20:16

If you feel that Fukuchi's library is too large[0] for you, consider looking at Nayuki's C++ QR Code generator library[1]: https://github.com/nayuki/QR-Code-generator/tree/master/cpp

Nayuki's library requires C++11, and is portable without needing Autotools. Sample usage:

#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 files, ~7200 lines among the main .c and .h files (excluding build and test code).
[1]: Nayuki: 6 files, ~1400 lines among the main .cpp and .hpp files (excluding demo code).


EDIT 2016-12-08 by OP I decided, with permission, to add my own adaption to Qt. This code compiles and runs fine on my system, And I think it should be independent enough to work elsewhere without too many tweaks as well.

#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);
            }
        }
    }
}

For usage, please see this painter class.

查看更多
可以哭但决不认输i
3楼-- · 2019-01-21 20:18

UPDATE 3/3-2016: It has come to my attention that there is a small library project that does what my answer does but in a more "prepackaged" way. You can check it out here.

QR in Qt

There is a small QR-code generator library in pure C and without dependencies, called libqrencode.

Step 1: Install

Before you can use it, you will have to install it. On my Ubuntu 13.10 that meant typing the following in a shell:

sudo aptitude install libqrencode-dev

On other platforms you may have to build it from source by yourself. Simply download the tarball and follow the instructions from the source code download.

Step 2: Project file

Next, you will have to add the library to your project. In my Qt5.2.0 project file (myproject.pro or similar) that meant appending the following line:

LIBS += -lqrencode

This should be similar for most versions of Qt that I know.

Step 3: encode

Next one must write the code that actually uses the library to encode some input string to QR format. That is one line of code:

QRcode *qr=QRcode_encodeString("my string", 1, QR_ECLEVEL_L, QR_MODE_8,0);

NOTE: After experimenting with the parameters I have passed to this function, I have learned that one needs to be careful. Some combinations of parameters failed for no good reason. For example passing 0 as version or using QR_MODE_AN failed with "Invalid parameters". This might be bugs in the ancient version of the library that I am using You have been warned.

Step 4: render image

Finally, before cleaning up, you need to convert the output to bitmap so that it can be rendered on the screen. This is simpler than it sounds. Instead of listing a bunch of assumptions I will instead included my complete working minimalistic QRWidget implementation here. The interesting bits are in the overridden paintEvent() method.

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;
}

Summary In this little post I have summarized my experience with getting a QR code generator working with Qt.

查看更多
登录 后发表回答