Linux LVGL Framebuffer截屏保存为PNG图片

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;
}

效果图!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/jhting/article/details/123171749