你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【安富莱STemWin教程】第13章 GIF图片显示

[复制链接]
baiyongbin2009 发布时间:2015-1-15 14:22
本帖最后由 baiyongbin2009 于 2015-1-15 14:23 编辑

特别说明:完整STemWin的1-60期教程和配套实例下载地址:链接
第13章      GIF图片显示

    本期主要讲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图片
13.1.jpg

l  打开软件加载上面的图片
13.2.jpg

l  加载后点击Convert即可,点击后没有任何现象,直接去图片所在的文件夹找即可
13.3.jpg

实际运行代码如下(图片数据就不贴出来了,看本期教程配套的例子)
  1. GUI_GIF_INFO InfoGif1;
  2. GUI_GIF_IMAGE_INFO InfoGif2;

  3. void MainTask(void)
  4. {   
  5.      int i = 0;

  6.      GUI_Init();

  7.      GUI_GIF_GetInfo(_ac4, sizeof(_ac4), &InfoGif1); (1)
  8.      while(1)
  9.      {
  10.          if(i < InfoGif1.NumImages)
  11.          {
  12.               GUI_GIF_GetImageInfo(_ac4, sizeof(_ac4), &InfoGif2, i);(2)
  13.               GUI_GIF_DrawSub(_ac4, (3)
  14.                             sizeof(_ac4),
  15.                             (LCD_GetXSize() - InfoGif1.xSize)/2,
  16.                             (LCD_GetYSize() - InfoGif1.ySize)/2,
  17.                             i++);
  18.               /* 这个函数要注意,主要是设置每个GIF子图像的时间间隔的。*/
  19.          GUI_Delay(InfoGif2.Delay*10);                      (4)
  20.          }
  21.          else
  22.          {

  23.               i = 0;
  24.          }
  25.      }
  26. }
复制代码
1.     这个函数用于获取GIF图像的信息。获取的信息填充到结构体GUI_GIF_INFO中,此结构体的定义如下:

13.4.png
    这个里面有个错误:不是XSize和YSize,而是xSize和ySize(这个错误一直没有更正
2.     获取GIF图像的信息,获取的信息填充给结构体GUI_GIF_IMAGE_INFO,结构体的定义如下:

13.5.png
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)

    13.6.jpg
     解决办法如下:
    第一步:点击Project –>settings选择C/C++,在Project Options中加入/Zm1000(要从末尾进行加入,也就是/c后面,点击OK后会自动的加到/c前面)
13.7.jpg

    为什么改,大家可以看下msdn中的说明:http://msdn.microsoft.com/zh-cn/library/bdscwf1c。这个不属于咱们要介绍的范围,有兴趣的可以在网上搜索上面的错误信息进行了解。
实际显示效果如下:
13.8.png

13.1.2      GIF存储器方式显示
    对于GIF格式的图片,一般用存储方式显示即可,只有显示的图片不是很复杂,这种方式显示速度也比较快。当前STemWin支持的GIF图片 API函数如下:

13.9.png


收藏 1 评论13 发布时间:2015-1-15 14:22

举报

13个回答
沐紫 回答时间:2015-1-15 14:23:57
教程真多,貌似天天过来发,坚持这么久不容易,点个赞
baiyongbin2009 回答时间:2015-1-15 14:26:07
本帖最后由 baiyongbin2009 于 2015-1-15 14:27 编辑

13.2  绘制已经加载到存储器的GIF图片
    将图片加载到存储器后进行显示比较的耗内存,所以这里就使用开发板外置的2MB SRAM做STemWin的动态内存空间,并通过相应的API函数申请动态内存来加载SD卡等外部存储器中的GIF图片。申请和释放STemWin动态内存的方法如下:
  1. /* 申请一块内存空间 并且将其清零 */
  2. hMem = GUI_ALLOC_AllocZero(100000);
  3. /* 将申请到内存的句柄转换成指针类型 */
  4. _acBuffer2 = GUI_ALLOC_h2p(hMem);
  5. /* 释放申请的动态内存  */
  6. GUI_ALLOC_Free(hMem);
复制代码
    这里还用上面的图片作为显示对象。先把这个图片放到SD卡中,然后通过程序把这个图片数据全部的加载到SRAM中,最后在屏上进行显示。这个工程的实现主要分为如下三个部分:
Ø  SRAM和SD卡及其文件系统的初始化
Ø  图片的加载以及显示函数
Ø  主函数
    下面把这三部分详细的讲解下:
l  SRAM和SD卡及其文件系统的初始化,这部分函数与上面第11章的11.2小节一样。
l  图片的加载以及显示函数
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: _ShowGIF
  4. *    功能说明: 显示GIF片
  5. *    形    参:sFilename 要显示的图片名字
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void _ShowGIF(const char * sFilename)
  10. {
  11.      GUI_HMEM hMem;
  12.      char *_acBuffer2;
  13.      uint8_t i;

  14.      /* 申请一块内存空间 并且将其清零 */
  15.     hMem = GUI_ALLOC_AllocZero(1024*1024);
  16.      /* 将申请到内存的句柄转换成指针类型 */
  17.      _acBuffer2 = GUI_ALLOC_h2p(hMem);

  18.    
  19.      /* 打开文件 */        
  20.      result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
  21.      if (result != FR_OK)
  22.      {
  23.          return;
  24.      }

  25.      result = f_read(&file, _acBuffer2, file.fsize, &bw);
  26.      if (result != FR_OK)
  27.      {
  28.          return;
  29.      }
  30.    
  31.    GUI_GIF_GetInfo(_acBuffer2, file.fsize, &InfoGif1);

  32.    while(1)
  33.    {
  34.          if(i < InfoGif1.NumImages)
  35.          {
  36.              GUI_GIF_GetImageInfo(_acBuffer2, file.fsize, &InfoGif2, i);
  37.              GUI_GIF_DrawSub(_acBuffer2,
  38.                               file.fsize,
  39.                               (LCD_GetXSize() - InfoGif1.xSize)/2,
  40.                                  (LCD_GetYSize() - InfoGif1.ySize)/2,
  41.                               i++);
  42.                      
  43. //            GUI_GIF_DrawSubScaled(_acBuffer2, (1)
  44. //                                  file.fsize,
  45. //                                  (LCD_GetXSize() - InfoGif1.xSize*3)/2,
  46. //                                     (LCD_GetYSize() - InfoGif1.ySize*3)/2,
  47. //                                  i++,
  48. //                                  3,
  49. //                                1);
  50.             
  51.               GUI_X_Delay(InfoGif2.Delay*10);                  
  52.          }
  53.          else
  54.          {
  55.              i = 0;
  56.          }
  57.      }

  58. //   GUI_ALLOC_Free(hMem);
  59. //   f_close(&file);
  60. }
复制代码
1.    根据需要,大家可以选择以一定的放缩比例显示GIF图片。
l  主函数
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MainTask
  4. *    功能说明: GUI主函数
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void MainTask(void)
  10. {   
  11.      GUI_Init();

  12.      /* 设置皮肤函数 */
  13.      PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
  14.      FRAMEWIN_SetDefaultSkin(FRAMEWIN_SKIN_FLEX);
  15.      PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
  16.      BUTTON_SetDefaultSkin(BUTTON_SKIN_FLEX);
  17.      CHECKBOX_SetDefaultSkin(CHECKBOX_SKIN_FLEX);
  18.      DROPDOWN_SetDefaultSkin(DROPDOWN_SKIN_FLEX);
  19.      SCROLLBAR_SetDefaultSkin(SCROLLBAR_SKIN_FLEX);
  20.      SLIDER_SetDefaultSkin(SLIDER_SKIN_FLEX);
  21.      HEADER_SetDefaultSkin(HEADER_SKIN_FLEX);
  22.      RADIO_SetDefaultSkin(RADIO_SKIN_FLEX);

  23.      while(1)
  24.      {                 
  25.           _ShowGIF("4.gif");   
  26.      }

  27. }
复制代码
实际现象效果如下:
13.10.png

放大三倍后的显示效果如下:
13.11.png

baiyongbin2009 回答时间:2015-1-15 14:29:45
13.3   绘制无需加载到存储器的GIF图片
    绘制无需加载到存储器的GIF图片方式可以有效的解决内部动态内存不够的情况,不过缺点也很明显,图片的显示速度很慢。这种方式一般是每次读取一行像素的数据,然后进行显示。这个工程的实现主要分为如下三个部分:
Ø  使用芯片内部的SRAM作为动态内存
Ø  图片的加载以及显示函数
Ø  主函数
    下面把这三部分详细的讲解下:
l  使用芯片外部的SRAM作为动态内存,这部分函数与上面第11章的11.2小节一样,由于GIF比较的消耗内存,这里和BMP不同也需要使用动态内存。
l  图片的加以及显示函数。
  1. static char _acBuffer[0x2000];
  2. GUI_GIF_INFO InfoGif1;
  3. GUI_GIF_IMAGE_INFO InfoGif2;

  4. /*
  5. ********************************************************************************
  6. *
  7. *       _GetData
  8. *
  9. * Purpose:
  10. *   This routine is called by GUI_GIF_DrawEx(). The routine is responsible
  11. *   for setting the data pointer to a valid data location with at least
  12. *   one valid byte.
  13. *
  14. * Parameters:
  15. *   p           - Pointer to application defined data.
  16. *   NumBytesReq - Number of bytes requested.
  17. *   ppData      - Pointer to data pointer. This pointer should be set to
  18. *                 a valid location.
  19. *   StartOfFile - If this flag is 1, the data pointer should be set to the
  20. *                 beginning of the data stream.
  21. *
  22. * Return value:
  23. *   Number of data bytes available.
  24. *********************************************************************************
  25. */
  26. static int _GetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Off) {
  27.      static int FileAddress = 0;
  28.      UINT NumBytesRead;
  29.      FIL *PicFile;

  30.      PicFile = (FIL *)p;

  31.      /*
  32.      * Check buffer size
  33.      */
  34.      if (NumBytesReq > sizeof(_acBuffer)) {
  35.      NumBytesReq = sizeof(_acBuffer);
  36.      }


  37.      /*
  38.      * Set file pointer to the required position
  39.      */
  40.      if(Off == 1) FileAddress = 0;
  41.      else FileAddress = Off;
  42.      result =f_lseek(PicFile, FileAddress);


  43.      /*
  44.      * Read data into buffer
  45.      */
  46.      result = f_read(PicFile, _acBuffer, NumBytesReq, &NumBytesRead);

  47.      /*
  48.      * Set data pointer to the beginning of the buffer
  49.      */
  50.      *ppData = (const U8 *)_acBuffer;

  51.      /*
  52.      * Return number of available bytes
  53.      */
  54.      return NumBytesRead;
  55. }

  56. /*
  57. *********************************************************************************************************
  58. *    函 数 名: _ShowGIFEx
  59. *    功能说明: GIF图片显示
  60. *    形    参:sFilename 文件名
  61. *    返 回 值: 无
  62. *********************************************************************************************************
  63. */
  64. static void _ShowGIFEx(const char * sFilename)
  65. {   
  66.      OS_ERR err;
  67.      uint8_t i;

  68.      /* 打开文件 */        
  69.      result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
  70.      if (result != FR_OK)
  71.      {
  72.          return;
  73.      }
  74.    
  75.    GUI_GIF_GetInfoEx(_GetData, &file,&InfoGif1);

  76.    while(1)
  77.    {
  78.          if(i < InfoGif1.NumImages)
  79.          {
  80.               //OSSchedLock(&err);            
  81.              GUI_GIF_GetImageInfoEx(_GetData, &file, &InfoGif2, i );
  82.              GUI_GIF_DrawSubEx(_GetData,
  83.               &file,
  84.                                 (LCD_GetXSize() - InfoGif1.xSize)/2,
  85.                                  (LCD_GetYSize() - InfoGif1.ySize)/2,
  86.                                 i++);
  87.             
  88.              //OSSchedUnlock(&err);           
  89.               GUI_X_Delay(InfoGif2.Delay*10);                  
  90.          }
  91.          else
  92.          {
  93.              i = 0;
  94.          }
  95.      }

  96. //   f_close(&file);
  97. }
复制代码
l  主函数
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MainTask
  4. *    功能说明: GUI主函数
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void MainTask(void)
  10. {   
  11.      GUI_Init();

  12.      /* 设置皮肤函数 */
  13.      PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
  14.      FRAMEWIN_SetDefaultSkin(FRAMEWIN_SKIN_FLEX);
  15.      PROGBAR_SetDefaultSkin(PROGBAR_SKIN_FLEX);
  16.      BUTTON_SetDefaultSkin(BUTTON_SKIN_FLEX);
  17.      CHECKBOX_SetDefaultSkin(CHECKBOX_SKIN_FLEX);
  18.      DROPDOWN_SetDefaultSkin(DROPDOWN_SKIN_FLEX);
  19.      SCROLLBAR_SetDefaultSkin(SCROLLBAR_SKIN_FLEX);
  20.      SLIDER_SetDefaultSkin(SLIDER_SKIN_FLEX);
  21.      HEADER_SetDefaultSkin(HEADER_SKIN_FLEX);
  22.      RADIO_SetDefaultSkin(RADIO_SKIN_FLEX);
  23.    
  24.      while(1)
  25.      {                 
  26.          _ShowGIFEx("2.gif");  
  27.      }

  28. }
复制代码
实际显示效果如下:
13.12.png

这个图片比较大,有2.5MB左右,所以刷新速度比较慢,第一次运行需要断电后重启进行显示。
13.4  实验总结
    有兴趣的可以了解一下GIF压缩方面的知识。如果只是API应用的话,这部分知识还是比较容易学会的。GIF动态图片用到的场合也比较多。

baiyongbin2009 回答时间:2015-1-15 14:30:53
沐紫 发表于 2015-1-15 14:23
教程真多,貌似天天过来发,坚持这么久不容易,点个赞

谢谢支持!!
youxiaoxiang 回答时间:2015-3-12 14:49:31
你好,我通过你的教程显示出了GIF图片,但是不会动。请问是什么问题呢,图片是有显示的
大浪10010 回答时间:2015-3-12 15:22:08
真不错,,,
baiyongbin2009 回答时间:2015-3-12 15:25:26
youxiaoxiang 发表于 2015-3-12 14:49
你好,我通过你的教程显示出了GIF图片,但是不会动。请问是什么问题呢,图片是有显示的 ...

找个比较小的gif图片再试试,看看是否是动态内存不够。
寂寞如她 回答时间:2015-3-12 17:28:50
好帖,必须顶
youxiaoxiang 回答时间:2015-3-13 10:38:53
baiyongbin2009 发表于 2015-3-12 15:25
找个比较小的gif图片再试试,看看是否是动态内存不够。

我现在找了一个320*240的GIF图,大概是90K大小,放在模拟器上显示很流畅,但是板子上就差很多,刷新很慢,有办法吗
wyxy163@126.com 回答时间:2015-3-14 13:43:55
提示: 作者被禁止或删除 内容自动屏蔽
wyxy163@126.com 回答时间:2015-3-14 13:44:19
提示: 作者被禁止或删除 内容自动屏蔽
有时浑身不舒服 回答时间:2016-9-20 11:16:41
楼主,在第一段代码里,_ac4是什么?编译也出错了,我就想知道gif转换成的c文件怎用使用?mainTask函数里没有用到啊
zbber 回答时间:2016-9-20 12:13:51
谢谢分享 赞一个

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版