Files
crosspoint-reader-mod/src/util/QrUtils.cpp

55 lines
1.8 KiB
C++
Raw Normal View History

#include "QrUtils.h"
#include <qrcode.h>
#include <algorithm>
#include <memory>
#include "Logging.h"
void QrUtils::drawQrCode(const GfxRenderer& renderer, const Rect& bounds, const std::string& textPayload) {
// Dynamically calculate the QR code version based on text length
// Version 4 holds ~114 bytes, Version 10 ~395, Version 20 ~1066, up to 40
// qrcode.h max version is 40.
// Formula: approx version = size / 26 + 1 (very rough estimate, better to find best fit)
const size_t len = textPayload.length();
int version = 4;
if (len > 114) version = 10;
if (len > 395) version = 20;
if (len > 1066) version = 30;
if (len > 2110) version = 40;
// Make sure we have a large enough buffer on the heap to avoid blowing the stack
uint32_t bufferSize = qrcode_getBufferSize(version);
auto qrcodeBytes = std::make_unique<uint8_t[]>(bufferSize);
QRCode qrcode;
// Initialize the QR code. We use ECC_LOW for max capacity.
int8_t res = qrcode_initText(&qrcode, qrcodeBytes.get(), version, ECC_LOW, textPayload.c_str());
if (res == 0) {
// Determine the optimal pixel size.
const int maxDim = std::min(bounds.width, bounds.height);
int px = maxDim / qrcode.size;
if (px < 1) px = 1;
// Calculate centering X and Y
const int qrDisplaySize = qrcode.size * px;
const int xOff = bounds.x + (bounds.width - qrDisplaySize) / 2;
const int yOff = bounds.y + (bounds.height - qrDisplaySize) / 2;
// Draw the QR Code
for (uint8_t cy = 0; cy < qrcode.size; cy++) {
for (uint8_t cx = 0; cx < qrcode.size; cx++) {
if (qrcode_getModule(&qrcode, cx, cy)) {
renderer.fillRect(xOff + px * cx, yOff + px * cy, px, px, true);
}
}
}
} else {
// If it fails (e.g. text too large), log an error
LOG_ERR("QR", "Text too large for QR Code version %d", version);
}
}