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