web-dev-qa-db-ja.com

ネイティブC / C ++でQtを使用してQRコードを描画する方法

QtのQR

QtでQRコードをスキャンする方法 への付随的な質問として、Qt5ベースのデスクトップアプリでネイティブC/C++コードから QRコード を描画する方法を知りたい、しかし、私はこれを行う方法の例を見つけることができませんでした。

私は QtQR が存在することを知っていますが、 python-qrtools に依存しているため、そもそもQtを使用する目的を打ち負かしています。私は、どこにいようと決心したときにアプリでコンパイルできる、軽快で効率的で依存関係のないソリューションを求めています。

どうやってやるの?

23
Lennart Rolland

福地の図書館が大きすぎると感じたら[0] あなたのために、NayukiのC++ QRコードジェネレーターライブラリをご覧ください。[1]https://github.com/nayuki/QR-Code-generator/tree/master/cpp

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行(デモコードを除く)。


EDIT 2016-12-08 by 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);
            }
        }
    }
}

使用方法については、こちらをご覧ください Painter class。

8
Nayuki

2016年3月3日更新:私の答えは、より「事前にパッケージ化された」ものを実行する小さなライブラリプロジェクトがあることに気付きました。 " 仕方。 こちら で確認できます。

QtのQR

純粋なCに依存関係のない小さなQRコードジェネレーターライブラリがあり、 libqrencode と呼ばれます。

ステップ1:インストール

使用する前に、インストールする必要があります。私のUbuntu 13.10では、シェルに次のように入力する必要がありました。

Sudo aptitude install libqrencode-dev

他のプラットフォームでは、自分でソースからビルドする必要があります。 tarballをダウンロードして、 source code download の指示に従ってください。

ステップ2:プロジェクトファイル

次に、プロジェクトにライブラリを追加する必要があります。私のQt5.2.0プロジェクトファイル(myproject.proまたは同様のもの)では、次の行を追加する必要がありました。

LIBS += -lqrencode

これは私が知っているQtのほとんどのバージョンで似ているはずです。

ステップ3:エンコード

次に、実際にライブラリを使用して入力文字列をQR形式にエンコードするコードを記述する必要があります。それはコードの1行です:

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コードジェネレーターを取得した経験をまとめました。

30
Lennart Rolland