55 lines
1.8 KiB
C++
55 lines
1.8 KiB
C++
|
|
#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);
|
||
|
|
}
|
||
|
|
}
|