Take screenshot - save bmp file

Dear all,

I'm trying to take a screen shot of my (edited: corrected numbers) 3.5" 480320 TFT display with ILI9488 controller or the 2.8" 320240 TFT display with ILI9341 controller, and save it as .bmp or similar (uncompressed) bitmap file for later download to the computer. I'm not dead set on .bmp, it's just the first thing that comes to mind. I don't know much about image formats in general.

I'm using the TFT_eSPI library connected to a nodeMCU, 4 MB memory of which up to 3 MB as SPIFFS for image storage.

The library allows me to grab pixels from the display (16-bit colour, 565 format), so copying the display's memory and storing it to the SPIFFS storage is easy to do. Uncompressed this would result in some 340 kB per image, so that would allow me to store 8 images on the internal memory. Maybe I can upgrade to a 16 MB ESP8266 for a capacity of 44 :slight_smile:

Anyway. The main problem is turning it into a proper file that later can be opened easily on the computer. I've looked up the bmp format and it seems to be quite easy to implement, if needed.

Thanks in advance for all suggestions.

My questions regarding this endeavour:
Is there a library available that can do such a screen grab? That'd save me a lot of time.
If not: is there a way to read more than one pixel at a time? Now I'll have to send some 6 or 8 bytes to read back two. SPI is fast but less overhead is always better.
Any library or reference code that I can use for writing bmp files?
Suggestions for other (easier?) image formats are welcome, too. The image has lots of solid colours so compression would give huge space savings, but not interested in trying to implement that myself.

You can read the screen with TFT_eSPI methods:

           // Read the colour of a pixel at x,y and return value in 565 format 
  uint16_t readPixel(int32_t x0, int32_t y0);

           // The next functions can be used as a pair to copy screen blocks (or horizontal/vertical lines) to another location
           // Read a block of pixels to a data buffer, buffer is 16 bit and the array size must be at least w * h
  void     readRect(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint16_t *data);
...
           // This next function has been used successfully to dump the TFT screen to a PC for documentation purposes
           // It reads a screen area and returns the RGB 8 bit colour values of each pixel
           // Set w and h to 1 to read 1 pixel's colour. The data buffer must be at least w * h * 3 bytes
  void     readRectRGB(int32_t x0, int32_t y0, int32_t w, int32_t h, uint8_t *data);

You can either write a RAW file to SD card / SPIFFS
or write a properly formatted BMP file.

If you write a BMP file you can use your PC to convert it into a compressed JPG. 95% quality JPEG images are indistinguishable from the full fat image. Yet are MUCH smaller. You can get lots of JPGs in SPIFFS or even in the application memory.

David.

p.s. Some advice. ILI9341 is 240x320. I have never seen a 480x360 screen of any type. We all make typos. If you don't correct them it does not inspire confidence in your programming ability.

Thanks for the reply, I didn't spot those functions. That's going to help a lot! I still have some 50k RAM free, can use most of that for buffer. Or maybe even make changes to that function so I can dump the whole thing straight to SPIFFS instead of storing in memory.

And obviously I've been mixing up numbers again... I am using two screens for this project; 480x320 ILI9488 and 320x240 ILI9341.

Read one row at a time. Save as 565 colour or as RGB (666).
Write to disk (SD or SPIFFS)

The library returns 565 colours so I'm going to stick to that - 16 bpp is a big enough file already :slight_smile: 3 MB is not much space if you're working with uncompressed images.

One row at a time sounds the most sensible, considering bmp writes from bottom to top and the display normally acts top to bottom.

One thing I can not find (yet) is how to define 565 format for the bmp. From the Wikipedia description of the format it seems that it defaults to 555 with one bit unused.

I've started with this piece of code, trying to amend it to 565 format and read line by line the image from the display. That'd require a 480*2 = 960 byte buffer, which easily fits in the available RAM.

Yes, your StackOverflow algorithm looks about right. Write BMP to SPIFFS.
Then display BMP from SPIFFS with one of Bodmer's examples.

You can write 16-bit colours to BMP. I support them. But no other library seems to support 16-bit, 8-bit, 4-bit, 1-bit formats.

I strongly recommend that you write a regular 24-bit colour BMP. Most libraries only support this format.
IrfanView, Paint, ... etc will automatically write 24-bit BMP.

Eventually you will end up converting to JPG (on the PC)
This will mean you can store many images in Flash or SPIFFS.

David.

I’m going the other way around.

The image of interest is what I have rendered on the display (basically a graph of measurement results), that I want to store on SPIFFS so it can later be copied to a PC.

The image as stored on the SPIFFS will not be displayed on the attached TFT display.

Go on. It is easier to write the graph values as text. Then your PC can process them in a Spreadsheet or whatever.

Displaying a RAW image on your PC is unwise.
Use a standard format e.g. .BMP
Then PC programs know how to handle them

I suggested displaying from SPIFFS only as a verification that you had formatted the file ok.

David.

One option is to store as 16 bit in normal raster format then get the PC to encode the final image in the format you want. This is the approach taken by the screen capture sketch here.

I saw that sketch (or some other work of you involving screen shots and processing) - but I want to use the project independent from the PC, hence the attempt of storing locally.

Running into a serious issue with the SPIFFS... the first 2-3 images write quite fast, but after that it slows down pretty badly. Probably have to go the route as suggested in #7 after all. I was thinking about it, the main disadvantage is that it requires extra work on the PC side.