硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5429|回复: 2
收起左侧

[emWin教程入门篇] 【STemWin教程】第14章 PNG图片显示

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2015-1-14 16:39:06 | 显示全部楼层 |阅读模式
特别说明:完整STemWin的1-60期教程和配套实例下载地址:链接
第14章      PNG图片显示

    本期主要讲STemWin支持的PNG图片的显示,官方支持的主要有两种显示方法,一种是从外部存储器读取数据到内部存储器,然后来显示图片,这种的显示速度要快些,另一种方法是直接从外部存储器读取数据并显示,这种办法的好处就是不要大的RAM需求,每次读取一些数据显示一次,坏处就是显示速度比较的慢。
    这里将2MB的外部SRAM做为emWin的动态内存,PNG的图片显示相当耗费RAM。
    有一点在这里提前得和大家说明,对于PNG的库,STemWin里面是不带的,需要自己添加,从SEGGER的官网下载,这个库是来自libpng,官网www.libpng.org
    14. 1  PNG图片支持
    14. 2 绘制已经加载到存储器的PNG图片
    14. 3 绘制无须加载到存储器的PNG图片
    14. 4 实验总结
14.1  PNG图片支持
    PNG(可移植的网络图形)格式是一种图像格式,它利用非专利的数据压缩方法提供无损的数据压缩Alpha混合。PNG 1.0版规范于1996年发布。到2003年末,PNG成为国际标准(ISO/IEC15948)
    emWin对PNG支持的实施基于来自GlennRanders-Pehrson、Guy Eric Schalnat和Andreas Dilger的“libpng”库,该库可在www.libpng.org下免费获得。emWin对该库的使用符合GUI\PNG\png.h中的版权通知,通知中允许使用该库,而没有任何限制。
    图形库首先对图形信息进行解码。如果必须绘制图像,解码流程将花费相当长的时间。如果在窗口管理器经常调用的callback例程中使用PNG文件,则解码流程可能花费相当长的时间。通过使用存储设备可缩短计算时间。最好的方法是先将图像绘制到存储设备中。在这种情况下,将只进行一次解压缩。
    从SEGGER官网下载的png如下,这里我们使用最新的5.18版本:
14.1.png
14.1.1      PNG格式图标转换
    某些情况下,将PNG文件作为C文件添加到项目中非常有用。对此,可完全按照前面介绍的“JPEG文件支持”下的相同方式来执行。此外,位图转换器能够加载PNG文件并将它们转换为C位图文件。下面举一个例子,跟大家演示下:比如我们要转换如下的PNG图标:
14.2.png
l  打开软件加载上面的图片
14.3.jpg


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


    实际运行代码如下(图片数据就不贴出来了,看本期教程配套的例子
  1. void MainTask(void)
  2. {   
  3.     GUI_Init();
  4.      GUI_PNG_Draw(_acmusic, sizeof(_acmusic), 20, 20);
  5.     while(1)
  6.     {
  7.         GUI_Delay(100);
  8.     }
  9. }
复制代码
    由于在Bin2C的小工具是来自MDK安装目录中,这个工具只是评估板,无法实现PNG图标的透明色效果。模拟器实际的显示效果如下:
14.5.png


14.1.2      PNG存储器方式显示
    为了区分上面将图片转换为C文件进行显示,这里将PNG图片存入到外部SD卡等存储器中进行加载显示。
    首先要注意PNG需要的动态内存大小。PNG解压缩大约需要21 Kb RAM用于与图像大小无关的解压缩和依赖大小的字节量。RAM要求可按以下方式计算:
        大约RAM要求= (X-Size + 1)* Y大小* 4 + 21Kbytes
    当前STemWin支持的PNG图片 API函数如下:
14.6.png
14.2  绘制已经加载到存储器的PNG图片
    将图片加载到存储器后进行显示比较的耗内存,所以这里就使用开发板外置的2MB SRAM做STemWin的动态内存空间,并通过相应的API函数申请动态内存来加载SD卡等外部存储器中的PNG图片。申请和释放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. *    函 数 名: _ShowPNG
  4. *    功能说明: 显示GIF片
  5. *    形    参:sFilename   要显示的图片名字
  6. *              usPOSX     显示位置X
  7. *              usPOSY     显示位置Y
  8. *    返 回 值: 无
  9. *********************************************************************************************************
  10. */
  11. static void _ShowPNG(const char * sFilename, uint16_t usPOSX, uint16_t usPOSY)
  12. {
  13.      GUI_HMEM hMem;
  14.      char *_acBuffer2;
  15.      /* 申请一块内存空间 并且将其清零 */
  16.     hMem = GUI_ALLOC_AllocZero(500000);
  17.      /* 将申请到内存的句柄转换成指针类型 */
  18.      _acBuffer2 = GUI_ALLOC_h2p(hMem);
  19.    
  20.      /* 打开文件 */        
  21.      result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
  22.      if (result != FR_OK)
  23.      {
  24.          return;
  25.      }
  26.      result = f_read(&file, _acBuffer2, file.fsize, &bw);
  27.      if (result != FR_OK)
  28.      {
  29.          return;
  30.      }
  31.      GUI_PNG_Draw(_acBuffer2, file.fsize, usPOSX, usPOSY);
  32.      GUI_ALLOC_Free(hMem);
  33.      f_close(&file);
  34. }
复制代码
l  主函数
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MainTask
  4. *    功能说明: GUI主函数
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void MainTask(void)
  10. {   
  11.      GUI_Init();
  12.      GUI_SetBkColor(GUI_BLUE);
  13.      GUI_Clear();
  14.    
  15.     /* 绘制已加载到存储器的PNG文件 */
  16.      _ShowPNG("1.png", 0, 0);
  17.      _ShowPNG("2.png", 100, 0);
  18.    
  19.      while(1)
  20.      {                 
  21.          GUI_Delay(100);
  22.      }
  23. }
复制代码
    实际显示效果如下:
14.7.png


    编译,链接工程的时候会出现大量如下的警告:
14.8.jpg


    这个是由于使用的PNG库和现在STemWin5.22版本不匹配造成的,PNG的库是用5.18版本的,最新的5.22版本官方还没有更新。
14.3  绘制无需加载到存储器的PNG图片
    绘制无需加载到存储器的PNG图片方式可以有效的解决内部动态内存不够的情况,不过缺点也很明显,图片的显示速度很慢。这种方式一般是每次读取一行像素的数据,然后进行显示。这个工程的实现主要分为如下三个部分:
Ø  使用芯片内部的SRAM作为动态内存
Ø  图片的加载以及显示函数
Ø  主函数
    下面把这三部分详细的讲解下:
l  使用芯片外部的SRAM作为动态内存,这部分函数与上面第11章的11.2小节一样,由于PNG比较的消耗内存,这里和BMP不同也需要使用动态内存。
l  图片的加以及显示函数。
  1. /*
  2. ********************************************************************************
  3. *
  4. *       _GetData
  5. *
  6. * Purpose:
  7. *   This routine is called by GUI_GIF_DrawEx(). The routine is responsible
  8. *   for setting the data pointer to a valid data location with at least
  9. *   one valid byte.
  10. *
  11. * Parameters:
  12. *   p           - Pointer to application defined data.
  13. *   NumBytesReq - Number of bytes requested.
  14. *   ppData      - Pointer to data pointer. This pointer should be set to
  15. *                 a valid location.
  16. *   StartOfFile - If this flag is 1, the data pointer should be set to the
  17. *                 beginning of the data stream.
  18. *
  19. * Return value:
  20. *   Number of data bytes available.
  21. *********************************************************************************
  22. */
  23. static int _GetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Off) {
  24.      static int FileAddress = 0;
  25.      FIL *file;
  26.      DWORD    NumBytesRead;
  27.      U8     * pData;
  28.      pData  = (U8 *)*ppData;
  29.      file = (FIL *)p;
  30.      //
  31.      // Set file pointer to the required position
  32.      //
  33.      if(Off == 1) FileAddress = 0;
  34.      else FileAddress = Off;
  35.      result =f_lseek(file, FileAddress);
  36.      //
  37.      // Read data into buffer
  38.      //
  39.      result = f_read(file, pData, NumBytesReq, &NumBytesRead);
  40.      //
  41.      // Return number of available bytes
  42.      //
  43.      return NumBytesRead;
  44. }
  45. /*
  46. *********************************************************************************************************
  47. *    函 数 名: _ShowPNG
  48. *    功能说明: 显示PNG图片
  49. *    形    参:sFilename 要显示的图片名字
  50. *             usPOSX    显示位置X
  51. *             usPOSY    显示位置Y
  52. *    返 回 值: 无
  53. *********************************************************************************************************
  54. */
  55. static void _ShowPNGEx(const char * sFilename, uint16_t usPOSX, uint16_t usPOSY)
  56. {   
  57.      /* 打开文件 */        
  58.      result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
  59.      if (result != FR_OK)
  60.      {
  61.          return;
  62.      }
  63.    
  64.      GUI_PNG_DrawEx(_GetData, &file, usPOSX, usPOSY);
  65.      f_close(&file);
  66. }
复制代码
l  主函数
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MainTask
  4. *    功能说明: GUI主函数
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void MainTask(void)
  10. {   
  11.      GUI_Init();
  12.      GUI_SetBkColor(GUI_BLUE);
  13.      GUI_Clear();
  14.    
  15.      /* 绘制无需加载到存储器的PNG文件 */
  16.      _ShowPNGEx("3.png", 0, 100);
  17.      _ShowPNGEx("4.png", 100,100);
  18.    
  19.      while(1)
  20.      {                 
  21.          GUI_Delay(100);
  22.      }
  23. }
复制代码
    实际显示效果如下:
14.9.png


14.4  实验总结
    有兴趣的可以了解一下PNG压缩方面的知识。如果只是API应用的话,这部分知识还是比较容易学会的。PNG图标用到的地方还是比较多的。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

45

主题

45

回帖

45

积分

初级会员

积分
45
发表于 2016-3-9 16:54:30 | 显示全部楼层
请问:把PNG图片C文件直接放程序中   怎么调用 显示?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107265
QQ
发表于 2016-3-10 00:30:16 | 显示全部楼层

回 pengzisheng 的帖子

pengzisheng:请问:把PNG图片C文件直接放程序中   怎么调用 显示? (2016-03-09 16:54) 
看下这个帖子里面的
14.1.1      PNG格式图标转换

里面有模拟器上面做的演示。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-23 18:11 , Processed in 0.254833 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表