I’ve been working with LVGL for a few months now and I’ve got to say it’s extremely well documented which has made my life really easy.
In the project I’m working on, I’m supposed to take a snapshot of the screen when we press a particular button. I read the blog by @beibean.
But i’m unable to get a screenshot. I’m sure it’s something on my end. I don’t have any experience with Binary files and am kinda new to this, so might have made some stupid mistake.
It’d be great if you could help me figure out how the functions get called and how it gets saved.
What MCU/Processor/Board and compiler are you using?
STM32L4R5 and STM32CubeIDE
What LVGL version are you using?
v7.2.0
What do you want to achieve?
Save the snapshot of the screen as a image file.
What have you tried so far?
I’ve created a callback function that is called whenever we want to take a snapshot. I’ve also created a function that writes every pixel received form VDB to file and one that converts the pixel to the required format, as mentioned in the blog.
Write a 122 bytes BMP fileheader, describing the pixelformat
Temporarily swap the flush_cb
Invalidate the screen
Capture the refreshes to the file also and also update the TFT
Set back the original flush_cb
Close the file
/** Take Screenshot.
* Flush buffer into a binary file.
* @note: data pixel should be formated to uint16_t RGB as set by Bitmap header.
* @param[in] pFileName Output binary file name.
**/
void guiTakeScreenshot(const char * pFileName)
{
uint8_t header[128];
gui_get_bitmap_header(header, sizeof(header));
pFileOut = HASP_FS.open(pFileName, "w"); // 1. Open a stream for writing
if(pFileOut) {
size_t len = pFileOut.write(header, 122);
if(len == 122) {
// 2. Write a 122 bytes BMP fileheader, describing the pixelformat
Log.verbose(TAG_GUI, F("Bitmap header written"));
// 3. Temporarily swap the flush_cb
/* Get current callback */
lv_disp_t * disp = lv_disp_get_default();
void (*flush_cb)(struct _disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
flush_cb = disp->driver.flush_cb; /* store callback */
/* Set the screenshot callback */
disp->driver.flush_cb = gui_screenshot_to_file;
/* 4. Refresh screen to call the screenshot callback */
lv_obj_invalidate(lv_scr_act());
/* 5. Captures the refreshes to the stream, also also update the tft */
lv_refr_now(NULL);
/* 6. Restore callback */
disp->driver.flush_cb = flush_cb; /* restore callback */
Log.verbose(TAG_GUI, F("Bitmap data flushed to %s"), pFileName);
} else {
Log.error(TAG_GUI, F("Data written does not match header size"));
}
pFileOut.close(); // 7. Close file
} else {
Log.warning(TAG_GUI, F("%s cannot be opened"), pFileName);
}
}
This is the outline of the code, the actual implementation for gui_get_bitmap_header and gui_screenshot_to_file can be found on my github.
This can also be used with a httpClient, so the screenshot can be sent to a web browser as .bmp without converting any pixels. The BMP header describes the pixel format, so any application should be able to read it.
I have used this method to output the screen on STM32F407 to a webclient over ethernet.
I went through your Github Repo and implemented something similar on Codeblocks. Everything seems fine but I’m getting an error when I try and convert the Binary file to JPG using any online convertor. Any idea why? If it seems stupid, please spare with me, I’m extremely new to all this.
From this datasheet it seems to be an IL9341. readGRAM function is part of the MCUFRIEND_kbv library for Arduino.
I am pretty sure that you have the same function with the driver from ST library.