|

楼主 |
发表于 2017-1-13 15:56:24
|
显示全部楼层
19.3 PNG图片的API函数及其显示方法
当前emWin支持的API函数有如下6个:
从上面的表格中可以看出,emWin支持PNG文件显示主要有两种类型的函数,一类是以Ex结尾的函数,这种函数显示PNG图片是一边从外部存储器加载数据一边显示,显示速度相对较慢,适用于内存较小的场合。另一类是不以Ex结尾的函数,这种函数直接从指定的地址读取数据进行显示(注意,这里的地址需是总线式地址,比如外部SDRAM,外部SRAM,内部Flash和内部SRAM都可以),显示速度相对稍快。
本章教程会对这两种方式都进行说明:
(1)intGUI_PNG_Draw(const void * pFileData, int FileSize, int x0, int y0);
此函数直接从地址pFileData,读取PNG图片的数据,将图片显示到用户设置的位置(x0, y0)。
(2)intGUI_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代表宽度。
19.3.1 PNG库的移植方法
emWin的库中是不含有PNG库的,需要用户自行添加,添加也比较简单,只需用户把源码文件添加到工程里面就可以使用了。
PNG库的下载地址:www.segger.com/link/emwin_png.zip 。下载软件包后,解压出来的是如下四个版本(如果官方升级了,移植方法是一样的):
第1步:打开emWin_5.26文件夹,将PNG文件夹及其里面的源码文件全部复制到emWin工程的emWin文件夹里面(其它任意文件夹都是可以的,不限制)。
第2步:以MDK为例,将PNG的源码文件添加到MDK工程里面(IAR同样的设置),下面是部分源码文件的截图。
第3步:以MDK为例,添加PNG头文件的路径(IAR类似的设置),添加完毕后别忘了点击OK。
第4步:添加完毕后,验证是否已经添加成功,可以进行一次全编译,全编译后看到有100多个警告,这个是正常的,而使用IAR时警告很少。
至此,PNG的库就添加成功了。剩下就可以调用PNG的API函数了。
19.3.2 绘制已经加载到存储器的PNG图片
绘制加载到存储器的PNG图片主要是通过函数GUI_PNG_Draw来实现,下面我们分2步来说明如何将SD卡中的PNG图片显示到LCD上面。
第1步:将PNG图片复制到SD卡的根目录下,然后通过emWin的动态内存管理函数申请动态内存并将PNG文件加载进来, 这里我们用的是外部SDRAM做emWin的动态内存。
- 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.fsize);
-
- /* 将申请到内存的句柄转换成指针类型 */
- _acBuffer = GUI_ALLOC_h2p(hMem);
-
- /* 读取文件到动态内存 */
- result = f_read(&file, _acBuffer, file.fsize, &bw);
- if (result != FR_OK)
- {
- return;
- }
复制代码 第2步:将加载到emWin动态内存的PNG图片直接显示即可,然后结合第1步,完整的代码如下:
- /*
- *********************************************************************************************************
- * 函 数 名: _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.fsize);
-
- /* 将申请到内存的句柄转换成指针类型 */
- _acBuffer = GUI_ALLOC_h2p(hMem);
-
- /* 读取文件到动态内存 */
- result = f_read(&file, _acBuffer, file.fsize, &bw);
- if (result != FR_OK)
- {
- return;
- }
-
- /* 显示PNG图片 */
- GUI_PNG_Draw(_acBuffer, file.fsize, x, y);
-
- /* 释放动态内存hMem */
- GUI_ALLOC_Free(hMem);
-
- /* 关闭文件 */
- f_close(&file);
- }
复制代码 通过上面两步就完成了PNG图片的动态显示,用户要显示哪个图片,调用函数_ShowPNG2()即可,比如要显示1.png图片,可以调用_ShowPNG2("1.png"),这种方式显示PNG图片相对稍快些。实际显示效果参看本章节配套的实验例程说明。
19.3.3 绘制无需加载到存储器的PNG图片
绘制无需加载到存储器的PNG图片主要是通过函数GUI_PNG_DrawEx来实现,这种方式的优点是需要的内存小,但是显示速度稍慢。下面我们分2步来说明如何将SD卡中的PNG图片显示到LCD上面。
第1步:将PNG图片复制到SD卡的根目录下,然后直接调用函数GUI_GIF_DrawSubEx就可以显示。(注意,这里的_GetData函数是与前面BMP,JPEG和GIF图片的_GetData是不同的)
- /*
- *********************************************************************************************************
- * 函 数 名: _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图片速度稍慢,实际显示效果参看本章节配套的实验例程说明。
19.3.4 将PNG格式的图片转换成C文件
将PNG图片转换成C文件需要用到Bin2C.exe小软件,这个软件的下载和使用方法已经在第17章17.3.3小节讲解了,这里不再赘述。比如,我们将1.png图片(此图片在本章教程配套例子的V6-524_STemWin实验_PNG图片显示(RTOS)的Doc文件夹里面)转换成C文件,生成的代码如下:
- 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)即可。 |
|