Как нарисовать QR-код с Qt на родном языке C / C++

QR в Qt

в качестве компаньона вопрос как сканировать QR-коды с помощью Qt, Я хочу знать, как нарисовать QR код из собственного кода C / C++ в моем настольном приложении на основе Qt5, но я не мог найти пример того, как это сделать.

Я знаю QtQR существует, но имеет зависимости от python-qrtools который, на мой взгляд, побеждает цель использования Qt в первую очередь. Я хочу юркий, эффективное и свободное от зависимостей решение, которое будет компилироваться с моим приложением везде, где я решил его взять.

Как я могу это сделать?

2 ответов


Если вы чувствуете, что библиотека Фукути слишком велика[0] для вас, рассмотреть глядя на библиотеку генератора QR-кода Наюки в C++[1]: https://github.com/nayuki/QR-Code-generator/tree/master/cpp

библиотека Наюки требует 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]: Фукучи: 20 файлов, ~7200 строк среди основных.с и. H файлы (за исключением сборки и тестирования код.)
[1]: Наюки: 6 файлов, ~1400 строк среди основных.cpp и .файлы ГЭС (за исключением демо-код).


редактировать 2016-12-08 по OP Я решил, с разрешения, добавить свою собственную адаптацию к 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);
            }
        }
    }
}

для использования, пожалуйста, см. Этот художник класса.


обновление 3/3-2016: мне стало известно, что есть небольшой библиотечный проект, который делает то, что делает мой ответ, но более "упакованным" способом. Вы можете проверить это здесь.

QR в Qt

существует небольшая библиотека генератора QR-кода в чистом C и без зависимостей, называемая libqrencode.

Шаг 1: Установите

прежде чем вы можете использовать его, вы будете иметь установить его. На моем Ubuntu 13.10 это означало ввод следующего в оболочке:

sudo aptitude install libqrencode-dev

на других платформах вам, возможно, придется создавать его из источника самостоятельно. Просто скачайте архив и следуйте инструкциям загрузка исходного кода.

Шаг 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.ГЭС

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

резюме В этом небольшом посте я обобщил свой опыт работы с генератором QR-кода, работающим с Qt.