Compress ili9341 images (Tool)

Status
Not open for further replies.

Adriano

Member
When I begun using teensy, the memory was "infinite" compared to the 2kb of RAM and 16kb or Flash on Arduinos.

If you don't want a SD to draw some images on the ili9341, you can save them on the Flash, inside your program.
At this point, you see that even 256kb are not so much, anymore :p

A 565 image covering the entire display need 320x240x2 = 150kb. So you have just 100kb for your code.

So I wrote a simple "compressor" to groups the pixels with the same color and use only 1 byte (not 2) if the color of 2 pixels are similar.

How does it work?
After converting an image to a 565 (2 bytes color) array with a tool, you can import the code to your sketch.
The ili-function is drawRect(x,y,w,h,buffer).
If the array is compressed, you can call a function that will decompress the buffer and send it to the ili library.

ATTENTION
The compressed array is smaller (normally 30%) but there are 2 negative points:
1. You need 4kB RAM for the temporary buffer (this is normally never a problem on the infinite Teensy-RAM :p)
2. Decompressing and multiple draw calls will slow down the rendering speed.

On a 320x100 pixel image, you can save up to 30% on size (70kb to 50kb), but will loose 30% in speed (38ms instead of 25ms).

I am not an expert on compressing Algorithmus... So probably it is not the best out there. But it is working and I want to share my work :)

To use the converter, you can check my webpage (it is pure JavaScript, nothing will be uploaded to the server):
http://www.petrucci.ch/arduino/tft.php

And add this code to your sketch:
Code:
// You have to init the display with ILI9341_t3 tft(CS, DC); -> tft is used as variable inside the function
// Call this function with drawCompressedImage(x,y, w, h, compressed_buffer, sizeof(compressed_buffer) / sizeof(unsigned short));

void drawCompressedImage(int x, int y, int w, int h, const uint16_t *pic, uint16_t arraySize)
{
  int lines = 4096 / w;
  int yOffset = 0;
  uint16_t _buffer[lines * w];
  uint16_t j = 0;
  uint16_t p = 0;
  uint16_t c, c1;
  c = ~pic[0];

  auto addPixel = [&](const uint16_t &color) { _buffer[p++] = color; if(p >= lines * w) {tft.writeRect(x, yOffset+y, w, lines, _buffer); yOffset += lines; p = 0;} };
  auto changedBits = [](const uint16_t &value) { return ((value & 0x60)<<6) | ((value & 0x1c)<<3) | ((value & 0x03)<<0); };

  while(j < arraySize) {
    c1 = c;
    c = pic[j++];

    addPixel(c);

    if(c1 == c) {
      do {
        for(h=0;h<(pic[j]>>8);h++) 
          addPixel(c);
      } while((pic[j++] & 0x00ff) == 0xfe);
    }
    else if((c & 0xe71c) == (c1 & 0xe71c)) {
      while(1) {
        if((pic[j] & 0xff00) == 0xff00) {j++;break;}
        c ^= changedBits((pic[j] & 0xff00) >> 8);
        addPixel(c);
      
        if((pic[j] & 0x00ff) == 0x00ff) {j++;break;}
        c ^= changedBits(pic[j] & 0x00ff);
        addPixel(c);
 
        if(++j >= arraySize) break;
      }
    }
  }
  if(p>0)
    tft.writeRect(x, yOffset+y, w, p/w, _buffer); 
}
 
Last edited:
This page contains the following errors:

error on line 71 at column 41: xmlParseEntityRef: no name
Below is a rendering of the page up to the first error.

Capture.PNG
 
Status
Not open for further replies.
Back
Top