0

So I have a project where I send text to an Arduino, which is then printed out as a QR code on a thermal printer that can take a bitmap image with a given width and height.

Is there a way I can "scale up" the "image," making it so one pixel is scaled up to 4 or 8 pixels?

Additionally, would it be possible to add a "quiet zone" of sorts on the left side of the image, as I am not able to offset/justify it to the middle.

QR Code lib: https://github.com/ricmoo/QRCode

Thermal printer lib: https://github.com/adafruit/Adafruit-Thermal-Printer-Library

  • Trying to splice in the QRPrint library causes the ESP32 to crash over and over. – Tony Sesek Aug 25 at 4:19
  • Which Arduino? Most of them wouldn't have enough RAM for that. – Nick Gammon Aug 25 at 8:49
  • @NickGammon I am using an ESP32, which has an Arduino core. :) – Tony Sesek Aug 25 at 20:02
1

You didn't tell use the size of your QRCode, nor the type of Arduino you are using. So I am just going to guess that your problem is that you may have enough RAM to store the raw QRCode, but not enough to store a scaled bitmap version.

The Adafruit tutorial for their thermal printer library suggests printing bitmaps with the method:

printBitmap(width, height, tablename)

where tablename is an array holding the bitmap data. This will obviously not work if you don't have enough RAM to store the array. Fortunately, there is an overloaded method:

void Adafruit_Thermal::printBitmap(int w, int h, Stream *fromStream)

that allows you to stream the image data instead of preparing it in RAM. You can create a stream that delivers arbitrary data by writing a class that derives from Stream. Here is a tentative, untested implementation, that delivers a scaled-up QRCode one pixel at a time:

// Stream a scaled QRCode one pixel at a time.
class QRCodeStream : public Stream
{
public:
    QRCodeStream(const QRCode &code, uint8_t scale = 1)
    : qrcode(code), scale(scale) {}

    // Output: writing to this stream is a no-op.
    size_t write(uint8_t) {}
    void flush() {}

    // Input delivers the QRCode pixels.
    int available();
    int peek();
    int read();
private:
    QRCode &qrcode;
    uint8_t scale;
    bool done = false;
    uint8_t code_x = 0;  // coordinates of the QRCode module
    uint8_t code_y = 0;
    uint8_t pix_x = 0;  // pixel coordinates within the module
    uint8_t pix_y = 0;
};

int QRCodeStream::available()
{
    // For simplicity, pretend the bytes come one at a time.
    if (done) return 0;
    else return 1;
}

int QRCodeStream::peek()
{
    if (done) return -1;
    if (qrcode_getModule(&qrcode, code_x, code_y)) {
        return 0;  // black
    } else {
        return 255;  // white
    }
}

int QRCodeStream::read()
{
    if (done) return -1;
    int data = peek();

    // Move to the next pixel.
    if (++pix_x >= scale) {
        pix_x = 0;
        if (++code_x >= qrcode.size) {
            code_x = 0;
            if (++pix_y >= scale) {
                pix_y = 0;
                if (++code_y >= qrcode.size) {
                    done = true;
                }
            }
        }
    }

    return data;
}

This would be used as

printer.printBitmap(width, height, QRCodeStream(qrcode, scale));

Note that QRCodeStream delivers the image data as 8-bit gray scale, where each pixel is returned as one byte, either 0 (for black) or 255 (for white). This is likely not the format expected by the thermal printer library, which seems to expect 1-bit black and white data, with 8 pixels packed in each byte. You will have to adapt the code for the right format, which will likely be tedious, but not overly complex. I leave that “as an exercise to the reader”.

  • Apologies. I am using an ESP32, and the Arduino IDE reports a Max Mem of 327680 bytes. And I am aiming for a Version 3 QR Code at minimum :) – Tony Sesek Aug 25 at 20:04
  • And here is the results of scales 1-3: i.imgur.com/7gBl0c1.jpg - Not sure if it's due to the format of the code itself, or something else... – Tony Sesek Aug 25 at 20:23
  • @TonySesek: Looks like it's working, but every pixel gets converted to a line of 8 pixels because of the 1-bit vs. 8-bits format difference. – Edgar Bonet Aug 25 at 21:12
  • Ohh, my brain skipped over the important part of your postscript, my bad. Alright, that shouldn't be too bad. Maybe I can make another stream to take the stream, haha. – Tony Sesek Aug 25 at 21:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.