anunpanya / ESP8266_QRcode

102 stars 53 forks source link

Using different QR version #3

Open peterkorolev opened 7 years ago

peterkorolev commented 7 years ago

Hi!

Is it possible to use a lower version of QR code? With lower resolution/memory

anunpanya commented 7 years ago

@peterkorolev It's possible, but must find a pattern version of QR Code is smaller than this.

millenseer commented 6 years ago

He probably means "lower ECC". I have the same issue, the generated QR has a lot of redundancy and uses very small pixes (one pixel QR = 1 pixel OLED). I'd need lower ECC version which might generate QRs with 1 Pixel QR = 4 Pixel OLED: The original Arduino qrence library does offer generation between ECC 1 and 4. I need to look that up.

ben-mkiv commented 4 years ago

this lib works pretty fine for me: https://github.com/nayuki/QR-Code-generator/tree/master/c

allows to autopick the lowest possible version and auto adjusts ECC

put the qrcodegen.c / qrcodegen.h files from the project above in the same directory as the following 2 files and it should work (only tested on esp32 with esp-idf and arduino-esp32 lib)

qrencode.h

#include "OLEDDisplay.h"
#include "qrcodegen.h"

// https://www.qrcode.com/en/about/version.html QR version overview
#define QRENCODE_VERSION_MIN (1)
#define QRENCODE_VERSION_MAX (7) // should work up to 11 (61 x 61)

class QREncode
{
private:
    String QRBuffer = "";
    uint8_t code[qrcodegen_BUFFER_LEN_FOR_VERSION(QRENCODE_VERSION_MAX)];
    int resolution = 0;
    char maxScale = 0;

    void create(OLEDDisplay *display, String message);
    void render(OLEDDisplay *display, int x, int y);

public:
    void render(OLEDDisplay *display, String message, int x, int y){
        create(display, message);
        render(display, x, y);
    }
};

qrencode.cpp

#include "qrencode.h"

void QREncode::create(OLEDDisplay *display, String message) {
    // dont reencode code if nothing changed
    if(message.equals(QRBuffer))
        return;

    QRBuffer = message;
    uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(QRENCODE_VERSION_MAX)];

    resolution = 0;
    maxScale = 1;

    if(qrcodegen_encodeText(message.c_str(), &buffer[0], &code[0], qrcodegen_Ecc_LOW, QRENCODE_VERSION_MIN, QRENCODE_VERSION_MAX, qrcodegen_Mask_AUTO, true)){
        resolution = qrcodegen_getSize(code);

        while((maxScale + 1) * resolution < display->height())
            maxScale++;

        printf("QR created, size: %d, scale factor: %d", resolution, maxScale);
    }
    else {
        printf((char *) "failed to create QR code");
    }
}

void QREncode::render(OLEDDisplay *display, int x, int y) {
    int renderResolution = resolution * maxScale;
    int offsetX = x + (display->height() - renderResolution) / 2;
    int offsetY = y + (display->height() - renderResolution) / 2;

    display->fillRect(offsetX - 2, offsetY - 2, renderResolution + 4, renderResolution + 4);

    // draw QR Code
    for (char x = 0; x < renderResolution; x++) {
        for (char y = 0; y < renderResolution; y++) {
            display->setPixelColor(offsetX + x, offsetY + y, qrcodegen_getModule(code, x / maxScale, y / maxScale) ? BLACK : WHITE);
        }
    }
}
nayuki commented 4 years ago

@ben-mkiv Pretty good answer, but a few corrections:

ben-mkiv commented 4 years ago

Thanks @nayuki, i've edited my post according to your suggestions.

I've included the c file because it didn't compile for me with just the header (using CLion with ESP-IDF, so i probably just have to make it it's own component or fiddle with the CMake config)