本文为作者原创,如需转载请在醒目位置标明原始出处,并提供可访问的超链接。
效果
实现原理
emWin的GIF显示原理是用户程序调用GUI_GIF_DrawSub()绘制函数一帧一帧的解码和显示,并且每一次GUI_GIF_DrawSub()只解码一帧画面,这就导致一些高性能的MCU在显示一些小尺寸GIF时效果都会很差。
如果开始显示之前就把整个文件全部解码完,显示的时候只显示解码完的图像,就能显著改善GIF图的显示速度,利用emWin的内存设备可以实现这个功能。
具体实现原理:
- 把整个GIF源文件加载到RAM中
- 获取GIF图的总帧数和分辨率
- 创建大小等于分辨率、数量等于总帧数的内存设备,并把GIF的每一帧都绘制到对应的内存设备中,绘制完毕后删除存放在RAM中的GIF源文件
- 将内存设备按顺序写入显存
- 如果GIF图不再使用,则删除所有内存设备
由于解码过程在绘制到内存设备的时候已经完成了,真正显示的时候就可以非常快。
源码
static void ShowGIF_UseMemdev(const char *sFilename)
{
WM_HMEM hBuffMem;
WM_HMEM hMem;
GUI_MEMDEV_Handle *hMemgif;
GUI_GIF_INFO Gifinfo = { 0};
GUI_GIF_IMAGE_INFO Imageinfo = { 0};
taskENTER_CRITICAL();
result = f_open(&file, sFilename, FA_READ);
if ((result != FR_OK))
{
printf("文件打开失败!\r\n");
_acbuffer[0] = '\0';
}
hBuffMem = GUI_ALLOC_AllocZero(file.fsize);
_acbuffer = GUI_ALLOC_h2p(hBuffMem);
result = f_read(&file, _acbuffer, file.fsize, &f_num);
if (result != FR_OK)
{
printf("文件读取失败!\r\n");
}
f_close(&file);
taskEXIT_CRITICAL();
GUI_GIF_GetInfo(_acbuffer, file.fsize, &Gifinfo);
hMem = GUI_ALLOC_AllocZero(sizeof(GUI_MEMDEV_Handle) * Gifinfo.NumImages);
hMemgif = (GUI_MEMDEV_Handle *)GUI_ALLOC_h2p(hMem);
for(int i = 0; i < Gifinfo.NumImages; i++)
{
hMemgif[i] = GUI_MEMDEV_Create(0, 0, Gifinfo.xSize, Gifinfo.ySize);
GUI_MEMDEV_Select(hMemgif[i]);
GUI_GIF_GetImageInfo(_acbuffer, file.fsize, &Imageinfo, i);
GUI_GIF_DrawSub(_acbuffer, file.fsize, 0, 0, i);
}
GUI_ALLOC_Free(hBuffMem);
GUI_MEMDEV_Select(0);
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < Gifinfo.NumImages; i++)
{
GUI_MEMDEV_WriteAt(hMemgif[i], (LCD_GetXSize() - Gifinfo.xSize) / 2, (LCD_GetYSize() - Gifinfo.ySize) / 2);
GUI_Delay(Imageinfo.Delay * 10);
}
}
for(int i = 0;i < Gifinfo.NumImages; i++)
{
GUI_MEMDEV_Delete(hMemgif[i]);
}
GUI_ALLOC_Free(hMem);
}
测试
平台信息
- 测试硬件: 野火 H743 Pro 开发板
- 测试软件:野火emWin例程:GIF图片显示
- 软件平台:Keil5 V5.33
测试图片参数
文件体积:6.18MB
分辨率:762*324
总帧数:101帧
帧延时:70ms
测试效果
文章开头展示的效果图就是
参考资料
- emWin V6.14 官方文档(UM03001_emWin)