Framebuffer截屏保存为PNG图片
产品做说明书,或开发过程中有时的沟通,常有截屏的需求!一般的UI开发库中也有这个基本的功能,截屏功能! 其实比较简单,把FrameBuffer中的内存拷出来,写到PNG图片即可!
调试时,把RGB的顺序搞反了,保存的图片,色彩总是不对,见下面代码的for代码,libpng中有一个接口设置RGB顺序了: png_set_bgr 。 在不同的平台获取的数据可能不同,需要根据实际情况调整! 这里UI也是32位的RGBA,Framebuffer也是设置成为32的RGBA方式!
开发中如果色彩不对,可以在UI里设置一个区域的颜色的R,G,B值都写好,在下面的拷贝内存中这个位置的RGB值分别打印现来,应该就很快定位问题!
PUPANVR这个工程里,添加了 view/TViewScreenSnap.h里实现了这个功能! 代码位置: https://gitee.com/jhting/pupanvr/blob/develop/app/appmain/view/TViewScreenSnap.cpp 代码是在LVGL的UI中做的,在fbdev.c中改了一下几个函数!
void fbdev_get_sizes(uint32_t *width, uint32_t *height, uint32_t *line_length);
char* fbdev_get_framebufferMapAddr();
上面只是改了一下 fbdev_get_sizes, 添加了 fbdev_get_framebufferMapAddr 获取打开的地址!这样不用再去open一个framebuffer设备了!
截屏代码实现如下:
bool TViewScreenSnap::screenSnap(const char* pngFileName)
{
unsigned int width = 0;
unsigned int height = 0;
unsigned int line_length = 0;
unsigned int bit_depth = 8;
unsigned int i = 0;
unsigned int k = 0;
unsigned char *rawDataBuffer = NULL;
FILE *fp = NULL;
char* framebufferDevAddr = fbdev_get_framebufferMapAddr();
if(!framebufferDevAddr)
{
return false;
}
fbdev_get_sizes(&width, &height, &line_length);
if(width == 0 || height == 0 || line_length == 0)
{
return false;
}
png_structp png_ptr;
png_infop info_ptr;
fp = fopen(pngFileName, "wb");
if(!fp)
{
printf("screenSnap open file %s failure!\n", pngFileName);
return false;
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL)
{
printf("png_create_write_struct failure!\n");
fclose(fp);
return false;
}
rawDataBuffer = (unsigned char*)malloc(line_length);
if(!rawDataBuffer)
{
fclose(fp);
png_destroy_write_struct(&png_ptr, NULL);
return false;
}
/* Allocate/initialize the image information data. REQUIRED */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL)
{
fclose(fp);
free(rawDataBuffer);
png_destroy_write_struct(&png_ptr, NULL);
return false;
}
/* Set error handling. REQUIRED if you aren't supplying your own
* error handling functions in the png_create_write_struct() call.
*/
if (setjmp(png_jmpbuf(png_ptr)))
{
/* If we get here, we had a problem writing the file */
fclose(fp);
free(rawDataBuffer);
png_destroy_write_struct(&png_ptr, &info_ptr);
return false;
}
//png_set_swap_alpha(png_ptr);
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_packing(png_ptr);
//frame BGRA -> RGBA
png_set_bgr(png_ptr);
png_write_info(png_ptr, info_ptr);
unsigned char* pRawRowData = (unsigned char*)framebufferDevAddr;
for(k = 0; k < height; k++)
{
#if 1
memcpy(rawDataBuffer, framebufferDevAddr + k * line_length, line_length);
#else
pRawRowData = (unsigned char*)(framebufferDevAddr + k * line_length);
for(i = 0; i < line_length; i = i + 4)
{
//frame BGRA -> RGBA
rawDataBuffer[i + 0] = pRawRowData[i + 2]; //R
rawDataBuffer[i + 1] = pRawRowData[i + 1]; //G
rawDataBuffer[i + 2] = pRawRowData[i + 0]; //B
rawDataBuffer[i + 3] = pRawRowData[i + 3]; //A
}
#endif
png_write_row(png_ptr, rawDataBuffer);
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(rawDataBuffer);
fclose(fp);
return true;
}
效果图!
|