完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
转stemwin教程
本期主要讲emWin支持的GIF图片的显示,官方支持的主要有两种显示方法,一种是从外部存储器读取数据到内部存储器,然后来显示图片,这种的显示速度要快些,另一种方法是直接从外部存储器读取数据并显示,这种办法的好处就是不要大的RAM需求,每次读取一些数据显示一次,坏处就是显示速度比较的慢。 这里将2MB的外部SRAM做为emWin的动态内存。 13. 1 GIF图片支持 13. 2 绘制已经加载到存储器的GIF图片 13. 3 绘制无须加载到存储器的GIF图片 13. 4 实验总结 13.1 GIF图片支持 20世纪80年代,CompuServeInformation Service开发出了GIF文件格式(图形交换格式)。 它设计用于跨数据网络传输图像。GIF标准支持隔行扫描、透明、应用定义数据、动画以及原始文本渲染。emWin将忽略原始文本或应用特定数据等不受支持的数据。GIF文件使用LZW (Lempel-Zif-Welch)文件压缩方法来压缩图像数据。这种压缩方法运行起来不会丢失数据。输出图像与输入图像完全相同。 图形库首先对图形信息进行解码。如果必须绘制图像,解码流程将花费相当长的时间。如果在窗口管 理器经常调用的callback例程中使用GIF文件,则解码流程可能花费相当长的时间。通过使用存储设备可缩短计算时间。最好的方法是先将图像绘制到存储设备中。在这种情况下,将只进行一次解压缩。 emWin的GIF解压缩例程大约需要16千字节动态分配的RAM进行解压缩。绘制图像后,将释放用于解压缩的RAM。 |
|
相关推荐
|
|
13.1.1 GIF格式图标转换
某些情况下,将GIF文件作为C文件添加到项目中非常有用。对此,可完全按照前面介绍的“JPEG文件支持”下的相同方式来执行。下面举一个例子方便大家理解。比如我们要转换下面的GIF图片 l 打开软件加载上面的图片 l 加载后点击Convert即可,点击后没有任何现象,直接去图片所在的文件夹找即可 |
|
|
|
|
|
实际运行代码如下(图片数据就不贴出来了,看本期教程配套的例子)
复制代码 GUI_GIF_INFO InfoGif1; GUI_GIF_IMAGE_INFO InfoGif2; void MainTask(void) { int i = 0; GUI_Init(); GUI_GIF_GetInfo(_ac4, sizeof(_ac4), &InfoGif1); (1) while(1) { if(i < InfoGif1.NumImages) { GUI_GIF_GetImageInfo(_ac4, sizeof(_ac4), &InfoGif2, i);(2) GUI_GIF_DrawSub(_ac4, (3) sizeof(_ac4), (LCD_GetXSize() - InfoGif1.xSize)/2, (LCD_GetYSize() - InfoGif1.ySize)/2, i++); /* 这个函数要注意,主要是设置每个GIF子图像的时间间隔的。*/ GUI_Delay(InfoGif2.Delay*10); (4) } else { i = 0; } } } |
|
|
|
|
|
1. 这个函数用于获取GIF图像的信息。获取的信息填充到结构体GUI_GIF_INFO中,此结构体的定义如下:
这个里面有个错误:不是XSize和YSize,而是xSize和ySize(这个错误一直没有更正)。 2. 获取GIF图像的信息,获取的信息填充给结构体GUI_GIF_IMAGE_INFO,结构体的定义如下: 3. 绘制GIF的每个子图像。 |
|
|
|
|
|
4. 这里延迟时间参数InfoGif2.Delay要乘以10,主要是因为系统的滴答时钟节拍是1ms,而GIF图像的时钟节拍是以10ms为单位的。所以这里要乘以10。
5. 模拟器编译会出现以下错误信息(fatal error C1076:compiler limit : internal heap limit reached; use /Zm to specify a higher limit) 解决办法如下: 第一步:点击Project –>settings选择C/C++,在Project Options中加入/Zm1000(要从末尾进行加入,也就是/c后面,点击OK后会自动的加到/c前面) |
|
|
|
|
|
为什么改,大家可以看下msdn中的说明:http://msdn.microsoft.com/zh-cn/library/bdscwf1c。这个不属于咱们要介绍的范围,有兴趣的可以在网上搜索上面的错误信息进行了解。
实际显示效果如下: |
|
|
|
|
|
13.1.2 GIF存储器方式显示
对于GIF格式的图片,一般用存储方式显示即可,只有显示的图片不是很复杂,这种方式显示速度也比较快。当前STemWin支持的GIF图片 API函数如下: |
|
|
|
|
|
13.2 绘制已经加载到存储器的GIF图片
将图片加载到存储器后进行显示比较的耗内存,所以这里就使用开发板外置的2MB SRAM做STemWin的动态内存空间,并通过相应的API函数申请动态内存来加载SD卡等外部存储器中的GIF图片。申请和释放STemWin动态内存的方法如下: 复制代码 /* 申请一块内存空间 并且将其清零 */ hMem = GUI_ALLOC_AllocZero(100000); /* 将申请到内存的句柄转换成指针类型 */ _acBuffer2 = GUI_ALLOC_h2p(hMem); /* 释放申请的动态内存 */ GUI_ALLOC_Free(hMem); 这里还用上面的图片作为显示对象。先把这个图片放到SD卡中,然后通过程序把这个图片数据全部的加载到SRAM中,最后在屏上进行显示。这个工程的实现主要分为如下三个部分: Ø SRAM和SD卡及其文件系统的初始化 Ø 图片的加载以及显示函数 Ø 主函数 下面把这三部分详细的讲解下: l SRAM和SD卡及其文件系统的初始化,这部分函数与上面第11章的11.2小节一样。 l 图片的加载以及显示函数 |
|
|
|
|
|
/*
********************************************************************************************************* * 函 数 名: _ShowGIF * 功能说明: 显示GIF片 * 形 参:sFilename 要显示的图片名字 * 返 回 值: 无 ********************************************************************************************************* */ static void _ShowGIF(const char * sFilename) { GUI_HMEM hMem; char *_acBuffer2; uint8_t i; /* 申请一块内存空间 并且将其清零 */ hMem = GUI_ALLOC_AllocZero(1024*1024); /* 将申请到内存的句柄转换成指针类型 */ _acBuffer2 = GUI_ALLOC_h2p(hMem); /* 打开文件 */ result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS); if (result != FR_OK) { return; } result = f_read(&file, _acBuffer2, file.fsize, &bw); if (result != FR_OK) { return; } GUI_GIF_GetInfo(_acBuffer2, file.fsize, &InfoGif1); while(1) { if(i < InfoGif1.NumImages) { GUI_GIF_GetImageInfo(_acBuffer2, file.fsize, &InfoGif2, i); GUI_GIF_DrawSub(_acBuffer2, file.fsize, (LCD_GetXSize() - InfoGif1.xSize)/2, (LCD_GetYSize() - InfoGif1.ySize)/2, i++); // GUI_GIF_DrawSubScaled(_acBuffer2, (1) // file.fsize, // (LCD_GetXSize() - InfoGif1.xSize*3)/2, // (LCD_GetYSize() - InfoGif1.ySize*3)/2, // i++, // 3, // 1); GUI_X_Delay(InfoGif2.Delay*10); } else { i = 0; } } // GUI_ALLOC_Free(hMem); // f_close(&file); } |
|
|
|
|
|
1. 根据需要,大家可以选择以一定的放缩比例显示GIF图片。
l 主函数 复制代码 /* ********************************************************************************************************* * 函 数 名: MainTask * 功能说明: GUI主函数 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void MainTask(void) { GUI_Init(); /* 设置皮肤函数 */ PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX); FRAMEWIN_SetDefaultSkin(FRAMEWIN_SKIN_FLEX); PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX); BUTTON_SetDefaultSkin(BUTTON_SKIN_FLEX); CHECKBOX_SetDefaultSkin(CHECKBOX_SKIN_FLEX); DROPDOWN_SetDefaultSkin(DROPDOWN_SKIN_FLEX); SCROLLBAR_SetDefaultSkin(SCROLLBAR_SKIN_FLEX); SLIDER_SetDefaultSkin(SLIDER_SKIN_FLEX); HEADER_SetDefaultSkin(HEADER_SKIN_FLEX); RADIO_SetDefaultSkin(RADIO_SKIN_FLEX); while(1) { _ShowGIF("4.gif"); } } |
|
|
|
|
|
13.3 绘制无需加载到存储器的GIF图片
绘制无需加载到存储器的GIF图片方式可以有效的解决内部动态内存不够的情况,不过缺点也很明显,图片的显示速度很慢。这种方式一般是每次读取一行像素的数据,然后进行显示。这个工程的实现主要分为如下三个部分: Ø 使用芯片内部的SRAM作为动态内存 Ø 图片的加载以及显示函数 Ø 主函数 下面把这三部分详细的讲解下: l 使用芯片外部的SRAM作为动态内存,这部分函数与上面第11章的11.2小节一样,由于GIF比较的消耗内存,这里和BMP不同也需要使用动态内存。 l 图片的加以及显示函数。 复制代码 static char _acBuffer[0x2000]; GUI_GIF_INFO InfoGif1; GUI_GIF_IMAGE_INFO InfoGif2; /* ******************************************************************************** * * _GetData * * Purpose: * This routine is called by GUI_GIF_DrawEx(). The routine is responsible * for setting the data pointer to a valid data location with at least * one valid byte. * * Parameters: * p - Pointer to application defined data. * NumBytesReq - Number of bytes requested. * ppData - Pointer to data pointer. This pointer should be set to * a valid location. * StartOfFile - If this flag is 1, the data pointer should be set to the * beginning of the data stream. * * Return value: * Number of data bytes available. ********************************************************************************* */ static int _GetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Off) { static int FileAddress = 0; UINT NumBytesRead; FIL *PicFile; PicFile = (FIL *)p; /* * Check buffer size */ if (NumBytesReq > sizeof(_acBuffer)) { NumBytesReq = sizeof(_acBuffer); } /* * Set file pointer to the required position */ if(Off == 1) FileAddress = 0; else FileAddress = Off; result =f_lseek(PicFile, FileAddress); /* * Read data into buffer */ result = f_read(PicFile, _acBuffer, NumBytesReq, &NumBytesRead); /* * Set data pointer to the beginning of the buffer */ *ppData = (const U8 *)_acBuffer; /* * Return number of available bytes */ return NumBytesRead; } /* ********************************************************************************************************* * 函 数 名: _ShowGIFEx * 功能说明: GIF图片显示 * 形 参:sFilename 文件名 * 返 回 值: 无 ********************************************************************************************************* */ static void _ShowGIFEx(const char * sFilename) { OS_ERR err; uint8_t i; /* 打开文件 */ result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS); if (result != FR_OK) { return; } GUI_GIF_GetInfoEx(_GetData, &file,&InfoGif1); while(1) { if(i < InfoGif1.NumImages) { //OSSchedLock(&err); GUI_GIF_GetImageInfoEx(_GetData, &file, &InfoGif2, i ); GUI_GIF_DrawSubEx(_GetData, &file, (LCD_GetXSize() - InfoGif1.xSize)/2, (LCD_GetYSize() - InfoGif1.ySize)/2, i++); //OSSchedUnlock(&err); GUI_X_Delay(InfoGif2.Delay*10); } else { i = 0; } } // f_close(&file); } |
|
|
|
|
|
主函数
复制代码 /* ********************************************************************************************************* * 函 数 名: MainTask * 功能说明: GUI主函数 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void MainTask(void) { GUI_Init(); /* 设置皮肤函数 */ PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX); FRAMEWIN_SetDefaultSkin(FRAMEWIN_SKIN_FLEX); PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX); BUTTON_SetDefaultSkin(BUTTON_SKIN_FLEX); CHECKBOX_SetDefaultSkin(CHECKBOX_SKIN_FLEX); DROPDOWN_SetDefaultSkin(DROPDOWN_SKIN_FLEX); SCROLLBAR_SetDefaultSkin(SCROLLBAR_SKIN_FLEX); SLIDER_SetDefaultSkin(SLIDER_SKIN_FLEX); HEADER_SetDefaultSkin(HEADER_SKIN_FLEX); RADIO_SetDefaultSkin(RADIO_SKIN_FLEX); while(1) { _ShowGIFEx("2.gif"); } } |
|
|
|
|
|
13.4 实验总结
有兴趣的可以了解一下GIF压缩方面的知识。如果只是API应用的话,这部分知识还是比较容易学会的。GIF动态图片用到的场合也比较多。 |
|
|
|
|
|
《DNESP32S3使用指南-IDF版_V1.6》第二章 常用的C语言知识点
377 浏览 0 评论
【RA-Eco-RA2E1-48PIN-V1.0开发板试用】(第三篇)ADC采集+PWM输出
536 浏览 0 评论
《DNK210使用指南 -CanMV版 V1.0》第四十五章 人脸识别实验
540 浏览 0 评论
950 浏览 0 评论
如何用OpenCV的相机捕捉视频进行人脸检测--基于米尔NXP i.MX93开发板
1403 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
11760 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 08:02 , Processed in 0.892850 second(s), Total 100, Slave 83 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号