前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【第3版emWin教程】第23章 emWin6.x的PNG图片显示

【第3版emWin教程】第23章 emWin6.x的PNG图片显示

作者头像
Simon223
发布2021-07-08 15:49:08
6650
发布2021-07-08 15:49:08
举报
文章被收录于专栏:安富莱嵌入式技术分享

教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429

第23章 emWin6.x的PNG图片显示

本期主要讲emWin支持的PNG图片显示,官方支持的主要有两种显示方法,一种方法是直接从外部存储器读取数据并显示,这种方法的好处就是不需要大的RAM,每次读取一些数据显示一次,缺点就是显示速度稍慢。另一种是从外部存储器读取整个图片到RAM(比如内部SRAM,外部SRAM或者外部SDRAM),然后再显示图片,这种方法的显示速度要稍快些。一般情况下,PNG图片主要是用来做图标使用,图标都比较小,所以两种方法区别不大,后者稍快些。

23.1 初学者重要提示

23.2 PNG图片基础知识

23.3 PNG图片的API函数及其显示方法

23.4 实验例程说明(RTOS)

23.5 实验例程说明(裸机)

23.6 总结

23.1 初学者重要提示

1、 emWin库中是不包含PNG的,需要用户自己添加PNG库,对于初学者来说,这点要特别注意。

2、 PNG图片显示的所有API函数在emWin手册中都有讲解,下图是中文版手册里面API函数的位置

下图是英文版手册里面API函数的位置:

3、 本章教程使用的外部存储器是SD卡,实际项目中使用任何其它类型的存储器都可以的,支不支持文件系统都没有关系的,使用方法与本章教程一样,用户要做的就是把图片从外部存储器读出即可。

23.2 PNG图片基础知识

关于PNG图片格式方面的知识,推荐大家看wiki百科上面的介绍:

推荐初学者了解一下PNG图片的格式,如果没有了解也是没有任何关系的,直接调用emWin的API函数就可以显示PNG图片了。

----------------------------------------------------------------------------------------------------------

下面这点小知识还是要知道的:

便携式网络图形(Portable Network Graphics,PNG)是一种无损压缩的位图图形格式,支持索引、灰度、RGB三种颜色方案以及Alpha通道等特性。PNG的开发目标是改善并替换GIF作为适合网络传输的格式而且不需专利许可,所以被广泛应用于互联网及其它方面上。PNG另一个非正式的名称来源为递归缩写:“PNG is Not GIF”。

PNG图片的特性:

  • 支持256色调色板技术以产生小体积文件。
  • 最高支持48位真彩色图像以及16位灰度图像。
  • 支持Alpha通道的透明/半透明特性。
  • 支持图像亮度的Gamma校准信息。
  • 支持存储附加文本信息,以保留图像名称、作者、版权、创作时间、注释等信息。
  • 使用无损压缩。
  • 渐近显示和流式读写,适合在网络传输中快速显示预览效果后再展示全貌。
  • 使用CRC防止文件出错。
  • 最新的PNG标准允许在一个文件内存储多幅图像。

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

23.3 PNG图片的API函数及其显示方法

当前emWin支持的API函数有如下6个:

从上面的表格中可以看出,emWin支持PNG文件显示主要有两种类型的函数,一类是以Ex结尾的函数,这种函数显示PNG图片是一边从外部存储器加载数据一边显示,显示速度相对较慢,适用于内存较小的场合。另一类是不以Ex结尾的函数,这种函数直接从指定的地址读取数据进行显示(注意,这里的地址需是总线式地址,比如外部SDRAM,外部SRAM,内部Flash和内部SRAM都可以),显示速度相对稍快。

本章教程会对这两种方式都进行说明:

  • int GUI_PNG_Draw(const void * pFileData, int FileSize, int x0, int y0);

此函数直接从地址pFileData,读取PNG图片的数据,将图片显示到用户设置的位置(x0, y0)。

  • int GUI_PNG_GetXSizeEx(GUI_GET_DATA_FUNC * pfGetData, void * p);

此函数通过其回调函数pfGetData读取PNG图片的数据,从而实现边读取图片数据边显示的功能,将图片显示到用户设置的位置(x0, y0)。

另外还有一个知识点需要初学者了解,emWin解码一张PNG图片需要多少RAM?这主要有两部分组成,PNG解码本身需要大约21KB的RAM,外加图片的长度和宽度对RAM需求的影响,具体公式如下:

大约RAM要求= (xSize + 1)* ySize* 4 + 21Kbytes。 xSize代表长度,ySize代表宽度。

23.3.1 PNG库的移植方法

emWin的库中是不含有PNG库的,需要用户自行添加,添加也比较简单,只需用户把源码文件添加到工程里面就可以使用了。

PNG库的下载地址:www.segger.com/link/emwin_png.zip 。下载软件包后,解压出来的是如下四个版本(如果官方升级了,移植方法是一样的):

  • 第1步:打开V616文件夹,将PNG文件夹及其里面的源码文件全部复制到emWin工程的emWin文件夹里面(其它任意文件夹都是可以的,不限制)。
  • 第2步:以MDK为例,将PNG的源码文件添加到MDK工程里面(IAR同样的设置),下面是部分源码文件的截图。
  • 第3步:以MDK为例,添加PNG头文件的路径(IAR类似的设置),添加完毕后别忘了点击OK。
  • 第4步:添加完毕后,验证是否已经添加成功,可以进行一次全编译,全编译后看到有几十个警告,这个是正常的,而使用IAR时警告很少。

至此,PNG的库就添加成功了。剩下就可以调用PNG的API函数了。

23.3.2 绘制已经加载到存储器的PNG图片

绘制加载到存储器的PNG图片主要是通过函数GUI_PNG_Draw来实现,下面我们分2步来说明如何将SD卡中的PNG图片显示到LCD上面。

  • 第1步:将PNG图片复制到SD卡的根目录下,然后通过emWin的动态内存管理函数申请动态内存并将PNG文件加载进来, 这里我们用的是外部SDRAM做emWin的动态内存。
代码语言:javascript
复制
char *_acBuffer;
    GUI_HMEM hMem;

    /* 打开文件 */        
    result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
    if (result != FR_OK)
    {
        return;
    }
     
    /* 申请一块内存空间 并且将其清零 */
    hMem = GUI_ALLOC_AllocZero(file.obj.objsize);
    
    /* 将申请到内存的句柄转换成指针类型 */
    _acBuffer = GUI_ALLOC_h2p(hMem);

    /* 读取文件到动态内存 */
    result = f_read(&file, _acBuffer, file.obj.objsize, &bw);
    if (result != FR_OK)
    {
        return;
    }
  • 第2步:将加载到emWin动态内存的PNG图片直接显示即可,然后结合第1步,完整的代码如下:
代码语言:javascript
复制
/*
*********************************************************************************************************
*    函 数 名: _ShowPNG2
*    功能说明: 显示PNG图片,使用函数GUI_PNG_Draw
*    形    参: sFilename  要读取的文件名
*                     x  要显示的x轴坐标位置
*                     y  要显示的y轴坐标位置
*    返 回 值: 无
*********************************************************************************************************
*/
void _ShowPNG2(const char *sFilename, int x, int y) 
{
    char *_acBuffer;
    GUI_HMEM hMem;
    

    /* 打开文件 */        
    result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
    if (result != FR_OK)
    {
        return;
    }
     
    /* 申请一块内存空间 并且将其清零 */
    hMem = GUI_ALLOC_AllocZero(file.obj.objsize);
    
    /* 将申请到内存的句柄转换成指针类型 */
    _acBuffer = GUI_ALLOC_h2p(hMem);

    /* 读取文件到动态内存 */
    result = f_read(&file, _acBuffer, file.obj.objsize, &bw);
    if (result != FR_OK)
    {
        return;
    }
    
    /* 显示PNG图片 */
    GUI_PNG_Draw(_acBuffer, file.obj.objsize, x, y);

    /* 释放动态内存hMem */
    GUI_ALLOC_Free(hMem);
    
    /* 关闭文件 */
    f_close(&file);
}

通过上面两步就完成了PNG图片的动态显示,用户要显示哪个图片,调用函数_ShowPNG2()即可,比如要显示1.png图片,可以调用_ShowPNG2("1.png"),这种方式显示PNG图片相对稍快些。实际显示效果参看本章节配套的实验例程说明。

23.3.3 绘制无需加载到存储器的PNG图片

绘制无需加载到存储器的PNG图片主要是通过函数GUI_PNG_DrawEx来实现,这种方式的优点是需要的内存小,但是显示速度稍慢。下面我们分2步来说明如何将SD卡中的PNG图片显示到LCD上面。

  • 第1步:将PNG图片复制到SD卡的根目录下,然后直接调用函数GUI_GIF_DrawSubEx就可以显示。(注意,这里的_GetData函数是与前面BMP,JPEG和GIF图片的_GetData是不同的)
代码语言:javascript
复制
/*
*********************************************************************************************************
*    函 数 名: _GetData
*    功能说明: 被函数GUI_PNG_DrawEx调用
*    形    参: p             FIL类型数据
*             NumBytesReq   请求读取的字节数
*             ppData        数据指针
*             Off           如果Off = 1,那么将重新从其实位置读取                 
*    返 回 值: 返回读取的字节数
*********************************************************************************************************
*/
static int _GetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Off) 
{
    static int FileAddress = 0;
    FIL *file;
    UINT    NumBytesRead;
    U8     * pData;

    pData  = (U8 *)*ppData;
    file = (FIL *)p;
    
    //
    // 设置数据读取位置
    //
    if(Off == 1) FileAddress = 0;
    else FileAddress = Off;
    result =f_lseek(file, FileAddress);
    
    //
    // 读取数据到缓存
    //
    result = f_read(file, pData, NumBytesReq, &NumBytesRead);

    //
    // 返回读取大小
    //
    return NumBytesRead;

}

/*
*********************************************************************************************************
*    函 数 名: _ShowPNG1
*    功能说明: 显示PNG图片,使用函数GUI_PNG_DrawEx
*    形    参: sFilename 要显示的图片名字
*                     x  要显示的x轴坐标位置
*                     y  要显示的y轴坐标位置
*    返 回 值: 无
*********************************************************************************************************
*/
static void _ShowPNG1(const char * sFilename, int x, int y) 
{    

    /* 打开文件 */        
    result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
    if (result != FR_OK)
    {
        return;
    }
    
    /* 显示PNG图片 */
    GUI_PNG_DrawEx(_GetData, &file, x, y);

    /* 关闭文件 */
    f_close(&file);
}
  • 第2步:用户要显示指定的文件1.png,调用函数_ShowPNG1("1.png")即可显示。

通过上面2步就完成了PNG图片的动态显示,这种方式显示PNG图片速度稍慢,实际显示效果参看本章节配套的实验例程说明。

23.3.4 将PNG格式的图片转换成C文件

使用这种方法可以方便的将较小的PNG格式图片存到内部Flash。将PNG图片转换成C文件需要用到Bin2C.exe小软件。比如,我们将1.png图片(此图片在本章教程配套例子的的Doc文件夹里面)转换成C文件,生成的代码如下:

代码语言:javascript
复制
static const unsigned char _ac1[12721UL + 1] = {
  0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x08, 0x06, 0x00, 0x00, 0x00, 0xE2, 0x98, 0x77, 0x38, 0x00, 0x00, 0x20, 0x00, 0x49, 0x44, 0x41,
  0x54, 0x78, 0x9C, 0xDD, 0xBD, 0x79, 0x94, 0x5C, 0xD7, 0x7D, 0xDF, 0xF9, 0xB9, 0xF7, 0x2D, 0xB5, 0x74, 0xF5, 0xDE, 0x68, 0x00, 0x8D, 0x46, 0x03, 0xC4, 0x4A, 0x82, 0x20, 0x08, 0x82, 0x20, 0x09, 0xAE, 0xA2, 0x25, 0x93, 0x12, 0x29, 0x5B, 0x92,
  0x65, 0x91, 0x11, 0x6D, 0x29, 0x56, 0x9C, 0x4C, 0x1
/* 其余数据省略 */
}

用户显示时调用函数GUI_PNG_Draw(_ac1, sizeof(_ac1), 0, 0)即可。

23.4 实验例程说明(RTOS)

配套例子:

V7-524_emWin6.x实验_PNG图片显示(RTOS)

实验目的:

  1. 学习emWin的PNG图片显示。
  2. emWin功能的实现在MainTask.c文件里面。

实验内容:

1、K1按键按下,串口或者RTT打印任务执行情况(串口波特率115200,数据位8,奇偶校验位无,停止位1)。

2、(1) 凡是用到printf函数的全部通过函数App_Printf实现。

(2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。

3、默认上电是通过串口打印信息,如果使用RTT打印信息:

MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可

#define Enable_RTTViewer 1

4、各个任务实现的功能如下:

App Task Start 任务 :启动任务,这里用作BSP驱动包处理。

App Task MspPro任务 :消息处理,这里用作LED闪烁。

App Task UserIF 任务 :按键消息处理。

App Task COM 任务 :暂未使用。

App Task GUI 任务 :GUI任务。

μCOS-III任务调试信息(按K1按键,串口打印):

RTT 打印信息方式:

程序设计:

任务栈大小分配:

μCOS-III任务栈大小在app_cfg.h文件中配置:

#define APP_CFG_TASK_START_STK_SIZE 512u

#define APP_CFG_TASK_MsgPro_STK_SIZE 2048u

#define APP_CFG_TASK_COM_STK_SIZE 512u

#define APP_CFG_TASK_USER_IF_STK_SIZE 512u

#define APP_CFG_TASK_GUI_STK_SIZE 2048u

任务栈大小的单位是4字节,那么每个任务的栈大小如下:

App Task Start 任务 :2048字节。

App Task MspPro任务 :8192字节。

App Task UserIF 任务 :2048字节。

App Task COM 任务 :2048字节。

App Task GUI 任务 :8192字节。

系统栈大小分配:

μCOS-III的系统栈大小在os_cfg_app.h文件中配置:

#define OS_CFG_ISR_STK_SIZE 512u

系统栈大小的单位是4字节,那么这里就是配置系统栈大小为2KB

emWin动态内存配置:

GUIConf.c文件中的配置如下:

代码语言:javascript
复制
#define EX_SRAM   1/*1 used extern sram, 0 used internal sram */

#if EX_SRAM
#define GUI_NUMBYTES  (1024*1024*24)
#else
#define GUI_NUMBYTES  (100*1024)
#endif

通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:

#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小24MB。

#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。

默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。

emWin界面显示效果:

800*480分辨率界面效果。

23.5 实验例程说明(裸机)

配套例子:

V7-523_emWin6.x实验_PNG图片显示(裸机)

实验目的:

  1. 学习emWin的PNG图片显示。
  2. emWin功能的实现在MainTask.c文件里面。

emWin界面显示效果:

800*480分辨率界面效果。

emWin动态内存配置:

GUIConf.c文件中的配置如下:

代码语言:javascript
复制
#define EX_SRAM   1/*1 used extern sram, 0 used internal sram */

#if EX_SRAM
#define GUI_NUMBYTES  (1024*1024*24)
#else
#define GUI_NUMBYTES  (100*1024)
#endif

通过宏定义来配置使用内部SRAM还是外部的SDRAM做为emWin的动态内存,当配置:

#define EX_SRAM 1 表示使用外部SDRAM作为emWin动态内存,大小24MB。

#define EX_SRAM 0 表示使用内部SRAM作为emWin动态内存,大小100KB。

默认情况下,本教程配套的所有emWin例子都是用外部SDRAM作为emWin动态内存。

23.6 总结

本章节主要为大家讲解了PNG图片的绘制,PNG图片在实际项目中用的比较少。对于初学者来说,会使用即可,以后用到了再深入研究。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-07-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第23章 emWin6.x的PNG图片显示
    • 23.1 初学者重要提示
      • 23.2 PNG图片基础知识
        • 23.3 PNG图片的API函数及其显示方法
          • 23.3.1 PNG库的移植方法
          • 23.3.2 绘制已经加载到存储器的PNG图片
          • 23.3.3 绘制无需加载到存储器的PNG图片
          • 23.3.4 将PNG格式的图片转换成C文件
        • 23.4 实验例程说明(RTOS)
          • 23.5 实验例程说明(裸机)
            • 23.6 总结
            相关产品与服务
            对象存储
            对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档