web-dev-qa-db-fra.com

Comment dessiner un code QR avec Qt en C / C ++ natif

QR en Qt

Comme une question complémentaire à Comment numériser des codes QR avec Qt , je veux savoir comment dessiner un code QR à partir du code C/C++ natif dans mon application de bureau basée sur Qt5 , mais je n'ai pas pu trouver d'exemple sur la façon de procéder.

Je sais que QtQR existe, mais il a des dépendances sur python-qrtools qui, à mon avis, défait en quelque sorte le but d'utiliser Qt en premier lieu. Je veux une solution agile, efficace et sans dépendance qui se compilera avec mon application où que je décide de la prendre.

Comment puis je faire ça?

23
Lennart Rolland

Si vous pensez que la bibliothèque de Fukuchi est trop grande[0] pour vous, pensez à consulter la bibliothèque du générateur de code QR C++ de Nayuki[1]: https://github.com/nayuki/QR-Code-generator/tree/master/cpp

La bibliothèque de Nayuki nécessite C++ 11 et est portable sans avoir besoin d'Autotools. Exemple d'utilisation:

#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 fichiers, ~ 7200 lignes parmi les principaux fichiers .c et .h (à l'exclusion du code de génération et de test).
[1]: Nayuki: 6 fichiers, ~ 1400 lignes parmi les principaux fichiers .cpp et .hpp (hors code de démonstration).


EDIT 2016-12-08 par OP J'ai décidé, avec permission, d'ajouter ma propre adaptation à Qt. Ce code se compile et fonctionne bien sur mon système, et je pense qu'il devrait être suffisamment indépendant pour fonctionner ailleurs sans trop de modifications également.

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

Pour l'utilisation, veuillez consulter cette classe Painter .

8
Nayuki

MISE À JOUR 3/3-2016: Il est venu à mon attention qu'il y a un petit projet de bibliothèque qui fait ce que ma réponse fait mais dans un plus "préemballé " façon. Vous pouvez le vérifier ici .

QR en Qt

Il existe une petite bibliothèque de générateur de code QR en C pur et sans dépendances, appelée libqrencode .

Étape 1: installer

Avant de pouvoir l'utiliser, vous devrez l'installer. Sur mon Ubuntu 13.10, cela signifiait taper ce qui suit dans un shell:

Sudo aptitude install libqrencode-dev

Sur d'autres plateformes, vous devrez peut-être le créer vous-même à partir des sources. Téléchargez simplement l'archive tar et suivez les instructions du téléchargement du code source .

Étape 2: Fichier de projet

Ensuite, vous devrez ajouter la bibliothèque à votre projet. Dans mon fichier de projet Qt5.2.0 (myproject.pro ou similaire), cela signifiait ajouter la ligne suivante:

LIBS += -lqrencode

Cela devrait être similaire pour la plupart des versions de Qt que je connais.

Étape 3: encoder

Ensuite, il faut écrire le code qui utilise réellement la bibliothèque pour coder une chaîne d'entrée au format QR. C'est une ligne de code:

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

REMARQUE: Après avoir expérimenté les paramètres que j'ai passés à cette fonction, j'ai appris qu'il fallait être prudent. Certaines combinaisons de paramètres ont échoué sans raison valable. Par exemple, passer 0 comme version ou utiliser QR_MODE_AN a échoué avec "Paramètres non valides". Il peut s'agir de bogues dans l'ancienne version de la bibliothèque que j'utilise. Vous avez été averti.

Étape 4: rendre l'image

Enfin, avant de nettoyer, vous devez convertir la sortie en bitmap afin qu'elle puisse être rendue à l'écran. C'est plus simple qu'il n'y paraît. Au lieu d'énumérer un tas d'hypothèses, je vais plutôt inclure ici mon implémentation QRWidget minimaliste complète. Les bits intéressants se trouvent dans la méthode paintEvent () substituée.

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

Résumé Dans ce petit article, j'ai résumé mon expérience avec l'utilisation d'un générateur de code QR avec Qt.

30
Lennart Rolland