Adding logos or images as C array - martinberlin/cale-idf GitHub Wiki

I often get questions about this so I would like to publish a WiKi page explaining how I do. This library focuses mainly in driving the displays but does not provide a way to convert an image to a C array. It just has some examples about rendering a BMP or JPG downloaded from the internet.

1. Grabbing the logo and preparing the image

You can ask your client for their logo in vector format if they have one. Sometimes they don't so what I do is to get the image from the website or try to guess what font they use. Then you can just edit it in your preferred software, mine is Gimp, and just convert it to monochrome. In GIMP you do that going to top menu: Image -> Mode -> Indexed (And there select the monochrome option)

GIMP Screenshot

Make sure to scale it to the right size so it's displayed clearly and it fits your display dimensions. Make sure also that the image width is divisible per 8, since in monochrome mode 8 pixels fit one byte, and in our primitive image code we didn't calculate that. We are going to the very basics of sending a raw image buffer to an SPI display here.

2. Using an online converter tool

I use this simple tool to convert an image, like PNG for example, to a 8 bit per pixel monochrome array:

https://javl.github.io/image2cpp/

image2cpp Screenshot

There you can upload the PNG that we created before in point 1. This is a nice online tool that has some options: You can rotate the image, add different dithering option, and also scale it. But it is of course much better to do this in point 1 with your own software. Just mention it since sometimes it can be useful if you are in a hurry to get some results.

I use Arduino code output. At the end what we will do with this is to create a C or .h file with our image array:

// 'pcb_solder', 800x282px 
uint16_t pcb_solder_width = 800;
uint16_t pcb_solder_height = 282;
const char pcb_solder[28224] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ... // All first line WHITE
}

This will be the dimensions and the array that we are going to save in the display buffer where it can coexist with other things we rendered previously like fonts or geometric shapes. At some point I will add this in every display class since so far I didn't found a nice way to do it in a central place for all of them. Mind that some have only one buffer (BLACK) others 2 like BLACK/RED or similar. But this is how I added it for this particular 10.2" display:

// In the CPP class
void Depg1020bn::setRawBuf(uint32_t position, uint8_t value) {
  _mono_buffer[position] = ~ value;
}

// In the .h file as a public method
```C
void setRawBuf(uint32_t position, uint8_t value);

Very simple function right? It just receives a position and writes in the display buffer the byte received (value). Now that we have added to the class the possibility to receive a RAW buffer, then we will need to read the image array created before, and send it there! Let's get our hands dirty adding this function in our main_program.cpp

/**
 * @brief receives an image C array and sends it to the display buffer
 *        TODO: x is for the moment ignored, so it's always printed on x position: 0
 * 
 * @param image  C array created in https://javl.github.io/image2cpp/ (Needs also image_width image_height defined)
 * @param width  in px from the image
 * @param height 
 */
void image_draw(const char * image, uint16_t x, uint16_t y, uint16_t width, uint16_t height) {
    uint32_t buffer_pointer = 0;
    uint32_t epd_pointer = 0;
    uint16_t buffer_max_x = width/8;
    
    for (uint16_t posy = y; posy<y+height; posy++) {

        for (uint16_t posx = 0; posx<buffer_max_x; posx++) {
            display.setRawBuf(epd_pointer, image[buffer_pointer]);
            buffer_pointer++;
            epd_pointer++;
        }
        epd_pointer = (display.width()/8) * posy;
    }
}

// Using the image defined above we can then print it like this
image_draw(pcb_solder, 0, 10, pcb_solder_width, pcb_solder_height);

// After this we can call display.update() and the image should render in our display

If you like this small tutorial don't forget to add a nice ★ in the Cale repository.