微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 第14章 PNG图片显示

第14章 PNG图片显示

时间:10-02 整理:3721RD 点击:

第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支持的实施基于来自Glenn Randers-Pehrson、Guy Eric Schalnat和Andreas Dilger的“libpng”库,该库可在www.libpng.org下免费获得。emWin对该库的使用符合GUI\PNG\png.h中的版权通知,通知中允许使用该库,而没有任何限制。

    图形库首先对图形信息进行解码。如果必须绘制图像,解码流程将花费相当长的时间。如果在窗口管理器经常调用的callback例程中使用PNG文件,则解码流程可能花费相当长的时间。通过使用存储设备可缩短计算时间。最好的方法是先将图像绘制到存储设备中。在这种情况下,将只进行一次解压缩。

    从SEGGER官网下载的png如下,这里我们使用最新的5.18版本:



14.1.1 PNG格式图标转换

    某些情况下,将PNG文件作为C文件添加到项目中非常有用。对此,可完全按照前面介绍的“JPEG文件支持”下的相同方式来执行。此外,位图转换器能够加载PNG文件并将它们转换为C位图文件。下面举一个例子,跟大家演示下:比如我们要转换如下的PNG图标:



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



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



实际运行代码如下(图片数据就不贴出来了,看本期教程配套的例子)

  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.1.2 PNG存储器方式显示

    为了区分上面将图片转换为C文件进行显示,这里将PNG图片存入到外部SD卡等存储器中进行加载显示。

    首先要注意PNG需要的动态内存大小。PNG解压缩大约需要21 Kb RAM用于与图像大小无关的解压缩和依赖大小的字节量。RAM要求可按以下方式计算:

    大约RAM要求= (X-Size + 1)* Y大小* 4 + 21Kbytes

当前STemWin支持的PNG图片 API函数如下:



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. 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. GUI_PNG_Draw(_acBuffer2, file.fsize, usPOSX, usPOSY);
  31. GUI_ALLOC_Free(hMem);
  32. f_close(&file);
  33. }

复制代码

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.     /* 绘制已加载到存储器的PNG文件 */
  15. _ShowPNG("1.png", 0, 0);
  16. _ShowPNG("2.png", 100, 0);
  17. while(1)
  18. {
  19. GUI_Delay(100);
  20. }

  21. }

复制代码

实际显示效果如下:



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



    这个是由于使用的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. GUI_PNG_DrawEx(_GetData, &file, usPOSX, usPOSY);

  64. f_close(&file);
  65. }

复制代码

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. /* 绘制无需加载到存储器的PNG文件 */
  15. _ShowPNGEx("3.png", 0, 100);
  16. _ShowPNGEx("4.png", 100,100);
  17. while(1)
  18. {
  19. GUI_Delay(100);
  20. }

  21. }

复制代码

实际显示效果如下:



14.4 实验总结

    有兴趣的可以了解一下PNG压缩方面的知识。如果只是API应用的话,这部分知识还是比较容易学会的。PNG图标用到的地方还是比较多的。


硬汉,你到这边也发啊,顶一下,安富莱的资料还是很适合像我这种新手的!

谢谢兄弟的支持!

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top