C++ wxWidgets display and generate QR Code

Viewed 398

How can I setup and display a custom QR Code in wxWidgets, to encode and display a string?

(Self answered, feel free to contribute better answers)

1 Answers

Using the wxImagePanel example, and the nayuki/QR-Code-generator C++ library, you can pass a string and scale and the QR Code will generate and show.

The files created are:

wxImagePanel.hpp
wxImagePanel.cpp
wxQRCode.hpp
wxQRCode.cpp

First is my cut down wxImagePanel, a widget which lets you set and display images on a rectangular surface:

// wxImagePanel.hpp

#include <wx/wx.h>

class wxImagePanel : public wxPanel {
    private:
        wxBitmap image;
        void updateSize();

    public:
        wxImagePanel(wxFrame *parent, wxBitmap bitmap);
        wxImagePanel(wxFrame *parent);
        void paintNow();
        void paintEvent(wxPaintEvent &evt);
        void render(wxDC &dc);
        void setBitmap(wxBitmap bitmap);

        DECLARE_EVENT_TABLE()
};
// wxImagePanel.cpp

#include "wxImagePanel.hpp"

BEGIN_EVENT_TABLE(wxImagePanel, wxPanel)
EVT_PAINT(wxImagePanel::paintEvent)
END_EVENT_TABLE()

wxImagePanel::wxImagePanel(wxFrame *parent, wxBitmap bitmap): wxPanel(parent), image(bitmap) 
{
    updateSize();
};

wxImagePanel::wxImagePanel(wxFrame *parent): wxPanel(parent) {};

void wxImagePanel::updateSize() 
{
    SetMinSize(wxSize(image.GetWidth(), image.GetHeight()));
}

void wxImagePanel::paintEvent(wxPaintEvent &evt)
{
    wxPaintDC dc(this);
    render(dc);
}

void wxImagePanel::render(wxDC &dc) {
    int x = (GetSize().GetWidth() - image.GetWidth()) / 2;
    int y = (GetSize().GetHeight() - image.GetHeight()) / 2;
    dc.DrawBitmap(image, x, y, false);
}

void wxImagePanel::paintNow() {
    wxClientDC dc(this);
    render(dc);
}

void wxImagePanel::setBitmap(wxBitmap bitmap) {
    image = bitmap;
    updateSize();
    paintNow();
}

Then a QR Code class which subclasses the wxImagePanel and shows the code:

// wxQRCode.hpp

#include "wxImagePanel.hpp"
#include <string>

class wxQRCode : public wxImagePanel 
{
    public:
        wxQRCode(wxFrame *parent, std::string text, unsigned int scale);
        void setText(std::string text);
        void setScale(int scale);
        int getQRSize();

    private:
        void generateQRBitmap();
        std::string qrText;
        unsigned int bitmapScale;
};
// wxQRCode.cpp

#include "wxQRCode.hpp"
#include "QrCode.hpp" // qr code lib
using namespace qrcodegen;

wxQRCode::wxQRCode(wxFrame *parent, std::string text, unsigned int scale)
    : wxImagePanel(parent), qrText(text), bitmapScale(scale)
{
    generateQRBitmap();
};

int wxQRCode::getQRSize()
{
    QrCode qr = QrCode::encodeText(qrText.c_str(), QrCode::Ecc::LOW);
    return qr.getSize();
}

void wxQRCode::generateQRBitmap() 
{
    QrCode qr = QrCode::encodeText(qrText.c_str(), QrCode::Ecc::LOW);
    const int scale = bitmapScale;
    const int size = qr.getSize() * scale;
    const int byteWidth = (size + 7) / 8;
    char bitsChar[size*byteWidth];

    for (int y=0; y<size; y++) {
        for (int xByte=0; xByte<byteWidth; xByte++) {
            char bitChar = 0x00;
            if (qrText != "") { for (int xBit=0; xBit<8; xBit++) {
                    int x = xByte*8 + xBit;
                    int xModule = x / scale;
                    int yModule = y / scale;
                    bool black = qr.getModule(xModule, yModule);
                    bitChar += black << (xBit % 8);
                }}
            bitsChar[y * byteWidth + xByte] = bitChar;
        }
    }
    
    wxBitmap *bitmap = new wxBitmap(bitsChar, size, size, 1);
    setBitmap(*bitmap);
};

void wxQRCode::setText(std::string text) {
    qrText = text;
    if (text != "") {
        Show(true);
        generateQRBitmap();
        paintNow();
    } else {
        Show(false);
    }
};

void wxQRCode::setScale(int scale) {
    bitmapScale = scale;
    generateQRBitmap();
    paintNow();
};
Related