首页 > 系统相关 >小内存场合LVGL截图为BMP格式保存至基于FATFS文件系统的SD卡

小内存场合LVGL截图为BMP格式保存至基于FATFS文件系统的SD卡

时间:2022-11-30 15:23:21浏览次数:67  
标签:__ addtogroup InfoHeader BMP ubmp LVGL uint32 SD

1. 引言

截图是很多应用场合都需要的一项功能,对于无外存等小内存场合,同时又无法读取像素点的情况,截图通常需要多个组件的配合。本文采用的STM32G4微控制器,使用的组件如下:

  • GUI图形库:LVGL;
  • 文件系统:FATFS。

其中,显示驱动采用ST7789,存储截图的介质为SD卡。另,为方便读写和查看,本文采用BMP编码。

2. 准备工作

  • ST7789驱动及LVGL移植:参见《ST7789驱动 》和《STM32移植LVGL驱动ST7789》;
  • SD驱动及FATFS移植:参见《SPI驱动SD卡及FATFS移植》;
  • BMP编码的相关代码实现:这里我们采用最适配的16位无颜色图RGB555格式的存储方式,注意!是RGB555格式,无像素掩码信息时Windows系统默认采用的时该格式,与GUI图形库常用的RGB565是不一样的,之前截图颜色总是有类似噪点的颜色偏差,后经“lvgl技术交流”群中@Def、大哥的指出才发现原来是因为颜色格式搞错了,详细信息可参阅微软的相关文档。为实现BMP编码,主要需要给出BMP文件头的定义和初始化方法,分ubmp.hubmp.c两个文件。

ubmp.h文件完整代码如下:

/**
 *******************************************************************************
 * @file    ubmp.h
 * @author  xixizhk
 *******************************************************************************
 * @version V2022 @ Nov 1, 2022 \n
 * Initial version, only 16bit BMP without compression supported.
 * @version V2022 @ Nov 29, 2022 \n
 * Specified for ONLY RGB555, with bugs fixed. @see:
 * https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/
 *******************************************************************************
 */


/* Define to prevent recursive inclusion **************************************/
#ifndef _UBMP_H
#define _UBMP_H

#ifdef __cplusplus
extern "C" {
#endif

/**
 *******************************************************************************
 * @addtogroup Includes
 * @{
 */

#include "stdint.h"

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Definitions
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Types
 * @{
 */

/**
 * @brief File header, 14 bytes, packed.
 */
typedef struct
{
    /* File type, "BM" (0x424D) for .bmp file. */
    uint16_t bfType;
    /* File size in byte, including all the header, etc.. */
    uint32_t bfFileSize;
    /* Reserved, 0. */
    uint16_t bfReserved1;
    /* Reserved, 0. */
    uint16_t bfReserved2;
    /* Offset of pixel data from the beginning of the file header, in byte. */
    uint32_t bfOffsetBytes;
} __attribute__((__packed__)) ubmp_file_header_t;

/**
 * @brief Information header, 40 bytes, packed.
 */
typedef struct
{
    /* Size of the information header in byte, 40 */
    uint32_t biHeaderSize;
    /* Width of the picture, in pixel. */
    uint32_t biWidth;
    /* Height of the picture, in pixel. */
    uint32_t biHeight;
    /* Planes of bit plane, 1. */
    uint16_t biPlanes;
    /* Number of bits for one pixel. */
    uint16_t biBitCount;
    /* Compression options. */
    uint32_t biCompression;
    /* Size of the pixel data in byte, NOT equal to biWidth * biHeight. */
    uint32_t biDataSize;
    /* Pixels per meter (X). */
    uint32_t biXPelsPerMeter;
    /* Pixels per meter (Y). */
    uint32_t biYPelsPerMeter;
    /* Used color, 0. */
    uint32_t biColorUsed;
    /* Important color, 0.*/
    uint32_t biColorImportant;
} __attribute__((__packed__)) ubmp_info_header_t;

/**
 * @brief Type definition for BMP handler.
 */
typedef struct
{
    /* File header. */
    ubmp_file_header_t FileHeader;
    /* Information header. */
    ubmp_info_header_t InfoHeader;
    /* Header size in byte. */
    uint32_t HeaderSize;
    /* Line size in byte. */
    uint32_t LineSize;
} __attribute__((__packed__)) ubmp_rgb555_handler;


/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Constants
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Variables
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Macros
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Functions
 * @{
 */

void ubmp_init_rgb555(ubmp_rgb555_handler* _ubmp, uint32_t _w, uint32_t _h);

/**
 * @}
 */


#ifdef __cplusplus
}
#endif


#endif /* _UBMP_H */

/**************************** ALL RIGHTS RESERVED *****************************/

ubmp.c文件完整代码如下:

/**
 *******************************************************************************
 * @file    ubmp.c
 * @author  xixizhk
 *******************************************************************************
 * @version V2022 @ Nov 1, 2022 \n
 * Initial version, only 16bit BMP without compression supported.
 * @version V2022 @ Nov 29, 2022 \n
 * Specified for ONLY RGB555, with bugs fixed. @see:
 * https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/
 *******************************************************************************
 */


/**
 *******************************************************************************
 * @addtogroup Includes
 * @{
 */

#include "ubmp.h"

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Definitions
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Types
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Constants
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Variables
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Macros
 * @{
 */

/**
 * @}
 */

/**
 *******************************************************************************
 * @addtogroup Functions
 * @{
 */

/**
 * @brief   Initialize a BMP handler for RGB555.
 * @param   _ubmp [Out]: point to the BMP handler.
 * @param   _w [In]: width of the picture in pixel. 
 * @param   _h [In]: height of the picture in pixel.
 * @retval  None.
 */
void ubmp_init_rgb555(ubmp_rgb555_handler* _ubmp, uint32_t _w, uint32_t _h)
{
    _ubmp->FileHeader.bfType = 0x4D42;
    _ubmp->FileHeader.bfReserved1 = 0;
    _ubmp->FileHeader.bfReserved2 = 0;
    _ubmp->FileHeader.bfOffsetBytes = 54;

    _ubmp->InfoHeader.biHeaderSize = 40;
    _ubmp->InfoHeader.biWidth = _w;
    _ubmp->InfoHeader.biHeight = _h;
    _ubmp->InfoHeader.biPlanes = 1;

    /* RGB555. */
    _ubmp->InfoHeader.biBitCount = 16;
    _ubmp->InfoHeader.biCompression = 0;
    
    _ubmp->InfoHeader.biXPelsPerMeter = 10000;
    _ubmp->InfoHeader.biYPelsPerMeter = 10000;
    _ubmp->InfoHeader.biColorUsed = 0;
    _ubmp->InfoHeader.biColorImportant = 0;

    _ubmp->LineSize = (((_w << 4) + 31) >> 5) << 2;
    _ubmp->InfoHeader.biDataSize = _ubmp->LineSize * _h;  /* Can also be 0. */
    _ubmp->FileHeader.bfFileSize = 54 + _ubmp->InfoHeader.biDataSize;

    _ubmp->HeaderSize = 54;
}

/**
 * @}
 */


/**************************** ALL RIGHTS RESERVED *****************************/

3. 实现方法

为保持截图数据的完整,建议采用类似“触发”的方式结合lvgl定时器实现截图。

  • Step 1:定义相关的变量:
static volatile uint8_t sstrigr = 0U;
static FATFS ssfs;
static FIL ssfile;
static FRESULT ssfres;
static UINT ssbn;
static char sspath[32];
static lv_res_t sslvres;
static uint8_t ssbuffer[1024];
static lv_obj_t* ssscreen;
static ubmp_rgb555_handler ss;
  • Step 2:实现截图函数:
/**
 * @brief   Callback function for snapshot.
 * @param   timer [In]: pointer to the timer.
 * @retval  None.
 */
static void ss_cb(lv_timer_t * timer)
{
  lv_img_dsc_t dsc;
  lv_coord_t y1, y2;
  uint16_t i, j, w, tmp;
  char diskletter[2] = "0";

  if (sstrigr != 1U)
  {
    return;
  }

  y1 = ssscreen->coords.y1;
  y2 = ssscreen->coords.y2;
  w = ssscreen->coords.x2 - ssscreen->coords.x1 + 1;
  ubmp_init_rgb555(&ss, w, y2 - y1 + 1);

  diskletter[0] = sspath[0];
  ssfres = f_mount(&ssfs, sspath, 1);
  ssfres = f_open(&ssfile, sspath, FA_CREATE_ALWAYS | FA_WRITE |FA_READ);
  ssfres = f_write(&ssfile, &ss, ss.HeaderSize, &ssbn);
  for (i = y2; i >= y1; i--)
  {
    ssscreen->coords.y1 = i;
    ssscreen->coords.y2 = i;
    sslvres = lv_snapshot_take_to_buf
    (
      ssscreen,
      LV_IMG_CF_TRUE_COLOR,
      &dsc,
      ssbuffer,
      sizeof(ssbuffer)
    );
    /* Convert to RGB555. */
    for (j = 0; j < w; j++)
    {
      tmp = *(((uint16_t* )ssbuffer) + j);
      *(((uint16_t* )ssbuffer) + j) = (tmp & 0x001F) + ((tmp & 0xFFC0) >> 1U);
    }
    for (j = 2 * w; j < ss.LineSize; j++)
    {
      ssbuffer[j] = 0;
    }
    ssbn = ss.LineSize;
    ssfres = f_write(&ssfile, ssbuffer, ssbn, &ssbn);
    if (i == 0U)
    {
      break;
    }
  }
  ssfres = f_close(&ssfile);
  ssfres = f_mount(0, diskletter, 1);

  ssscreen->coords.y1 = y1;
  ssscreen->coords.y2 = y2;
  
  sstrigr = 0U;
}
  • Step 3:新建LVGL定时器对象,并将上述ss_cb函数作为其回调:
lv_timer_create(ss_cb, 0, NULL);
  • Step 4:采用“触发”加信息传递的方式实现供外部调用的截图函数:
/**
 * @brief   Take the snapshot of specified screen to SD card.
 *          @note: screen with border NOT supported.
 * @param   _path [In]: path to save the snapshot.
 *          @note: format: diskletter + : + file name, eg: 0:ss.bmp.
 * @param   _src [In]: pointer to the screen object.
 * @retval  None.
 */
void snapshot(char* _path, lv_obj_t* _scr)
{
  uint8_t i;
  for (i = 0; i < sizeof(sspath) - 1; i++)
  {
    sspath[i] = _path[i];
  }
  sspath[sizeof(sspath) - 1] = '\0';
  ssscreen = _scr;
}

标签:__,addtogroup,InfoHeader,BMP,ubmp,LVGL,uint32,SD
From: https://www.cnblogs.com/zysgy/p/16937248.html

相关文章

  • PBlaze6 6530系列企业级SSD获得浪潮信息澎湃技术兼容性认证
    近日,北京忆恒创源科技股份有限公司(以下简称“Memblaze”)的PBlaze66530系列企业级NVMe完成与浪潮信息NF5280M6服务器平台的兼容性适配认证,获得澎湃技术认证授权证书。​澎湃......
  • ArcObjects SDK开发 008 从mxd地图文件说起
    1、Mxd文件介绍ArcGIS的地图文件为.mxd扩展名。Mxd文件的是有版本的,和ArcGIS的版本对应。可以在ArcMap中的File-SaveACopy,保存一个地图拷贝的时候选择Mxd文件的版本,支持......
  • 读写BMP文件
    读写BMP文件http://blog.csdn.net/dege169/article/details/6210971......
  • C生成曲线BMP
     C生成曲线BMP http://zhidao.baidu.com/question/222913503.html  屏幕截屏http://topic.csdn.net/u/20120822/13/e52e7b2a-e151-4985-9aa7-934d9f38c8de.html......
  • 能生成BMP
    能生成BMPhttp://bbs.bccn.net/thread-336164-1-1.html   为何该程序生成的BMP图像打不开?? 程序代码: #include<stdio.h>#include<time.h>#include<stdlib.......
  • ISIS lsdb或路由交互过程
    1、对于点对点网络:A<-------------------->B1)A,B交互CSNP报文,该报文中包含本地知道的所有链路状态信息,2)A发送PSNP报文,请求B发送的报文中链路状态的详细信息(相当OSPF......
  • 在ARM处理器的Linux系统上安装 .NET SDK(Core 3.1~7.0),并检测ARM内在函数的支持情况
    作者:目录一、尝试apt-get安装二、尝试snap安装三、使用dotnet-install脚本安装3.1脚本准备3.2安装最新长期支持(LTS)版.NET6.03.3安装最新版本.NE......
  • 创建PV报错Device /dev/sdX excluded by a filter
    报错如下:解决办法:在进行pvcreate创建PV时,可能会遇到Device/dev/sdXexcludedbyafilter报错,一般出现这个错误是在通过parted分区并删除相应的分区信息以后。遇到这种......
  • 华为云GaussDB 为企业数字化踩了一脚油门
    云数据库的运用给企业的发展带来了质的改变,无数的企业在云数据库的帮助下,成功地实现了数字化升级和飞跃。然而,数据库技术千千万,哪家才是企业高效作业的心头好?这个答案,GaussD......
  • ArcObjects SDK开发 007 自定义App-Command-Tool框架
    1、为什么再设计一套App-Command-Tool框架为什么我们要自己再设计一套App-Command框架,而不直接使用AOAPI中的AxControl-ICommand这套已经非常好的框架呢?1、宿主不同。我......