|
楼主 |
发表于 2017-1-11 17:46:22
|
显示全部楼层
17.3 JPEG图片的API函数及其显示方法
当前emWin支持的API函数有如下6个:
从上面的表格中可以看出,emWin支持JPEG文件显示主要有两种类型的函数,一类是以Ex结尾的函数,这种函数显示JPEG图片是一边从外部存储器加载数据一边显示,显示速度相对较慢,适用于内存较小的场合。另一类是不以Ex结尾的函数,这种函数直接从指定的地址读取数据进行显示(注意,这里的地址需是总线式地址,比如外部SDRAM,外部SRAM,内部Flash和内部SRAM都可以),显示速度相对较快。
本章教程会对这两种方式都进行说明:
1、intGUI_JPEG_Draw(const void * pFileData, int DataSize, int x0, int y0);
此函数直接从地址pFileData读取JPEG文件数据,将图片显示到用户设置的位置(x0, y0)。
2、intGUI_JPEG_DrawEx(GUI_GET_DATA_FUNC * pfGetData, void * p, int x0, int y0);
此函数通过其回调函数pfGetData实现边读取图片数据边显示的功能,将图片显示到用户设置的位置(x0, y0)。
另外还有一个知识点需要初学者了解,emWin解码一张JPEG图片需要多少RAM?这主要有两部分组成,JPEG解码本身需要大约33KB的RAM,外加图片的不同长度对RAM需求的影响,具体公式如下:
大约RAM大小 = 图像的X大小* 80字节 + 33KB。
不同长度的JPEG图片的RAM需求取决于JPEG图片压缩类型,比如下面三种压缩类型:
JPEG图片解码所需的内存由emWin动态分配。绘制JPEG图像后,将释放整个RAM。这里举一个例子:比如要显示800*480的JPEG图片大约需要800*80 字节+ 33KB ,即97KB的内存。
17.3.1 绘制已经加载到存储器的JPEG图片
绘制加载到存储器的JEPG图片主要是通过函数GUI_JPEG_Draw来实现,下面我们分3步来说明如何将SD卡中的JPEG图片显示到LCD上面。
第1步:将JPEG图片复制到SD卡的根目录下,然后通过emWin的动态内存管理函数申请动态内存并将JPEG文件加载进来, 这里我们用的是外部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 0;
- }
-
- /* 申请一块内存空间 并且将其清零 */
- hMem = GUI_ALLOC_AllocZero(file.fsize);
-
- /* 将申请到内存的句柄转换成指针类型 */
- _acBuffer = GUI_ALLOC_h2p(hMem);
-
- /* 读取文件到动态内存 */
- result = f_read(&file, _acBuffer, file.fsize, &bw);
- if (result != FR_OK)
- {
- return 0;
- }
复制代码 第2步:将加载到emWin动态内存的JPEG图片绘制到内存设备里面,关于内存设备,我们在第15章已经专门讲解了。绘制到内存设备后,再调用内存设备的API函数绘制此JPEG图片,此时的绘制速度将大大加快。然后结合第1步,完整的代码如下:
- /*
- *********************************************************************************************************
- * 函 数 名: _ShowJPEG2
- * 功能说明: 显示JPEG图片
- * 形 参: sFilename 要读取的文件名
- * x 要显示的x轴坐标位置
- * y 要显示的y轴坐标位置
- * 返 回 值: 返回绘制了JPEG图片的内存设备句柄。
- *********************************************************************************************************
- */
- GUI_HMEM _ShowJPEG2(const char *sFilename, int x, int y)
- {
- char *_acBuffer;
- GUI_HMEM hMem;
- GUI_MEMDEV_Handle hMemJPEG;
-
- /* 打开文件 */
- result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
- if (result != FR_OK)
- {
- return 0;
- }
-
- /* 申请一块内存空间 并且将其清零 */
- hMem = GUI_ALLOC_AllocZero(file.fsize);
-
- /* 将申请到内存的句柄转换成指针类型 */
- _acBuffer = GUI_ALLOC_h2p(hMem);
-
- /* 读取文件到动态内存 */
- result = f_read(&file, _acBuffer, file.fsize, &bw);
- if (result != FR_OK)
- {
- return 0;
- }
-
- GUI_JPEG_GetInfo(_acBuffer, file.fsize, &JpegInfo);
-
- /* 创建内存设备,并将JPEG图片绘制到此内存设备里面,此内存设备要在主程序中用到
- 所以退出此函数前,不要释放。
- */
- hMemJPEG = GUI_MEMDEV_CreateEx(0, 0, JpegInfo.XSize, JpegInfo.YSize, GUI_MEMDEV_HASTRANS);
- GUI_MEMDEV_Select(hMemJPEG);
- GUI_JPEG_Draw(_acBuffer, file.fsize, x, y);
- GUI_MEMDEV_Select(0);
-
- /* 释放动态内存hMem */
- GUI_ALLOC_Free(hMem);
-
- /* 关闭文件 */
- f_close(&file);
-
- return hMemJPEG;
- }
复制代码 第3步:通过函数GUI_MEMDEV_WriteAt绘制内存设备中的图片,比如我们要绘制的图片1.jpg文件已经存储到了SD卡根目录下,显示方法如下:
- GUI_MEMDEV_Handle hMemJPEG;
-
-
- /* 加载JPEG图片到内存设备 */
- hMemBMP = _ShowJPEG2("1.bmp", 0, 0);
-
- /* 用到JPEG图片的时候,调用此函数即可 */
- GUI_MEMDEV_WriteAt(hMemBMP, 0, 0);
复制代码 通过上面三步就完成了JPEG图片的绘制操作,这种方式绘制JPEG图片速度非常快,后面有用到此JPEG图片的地方调用函数GUI_MEMDEV_WriteAt即可。实际显示效果参看本章节配套的实验例程说明。
17.3.2 绘制无需加载到存储器的JPEG图片
绘制无需加载到存储器的JPEG图片主要是通过函数GUI_JPEG_DrawEx来实现,这种方式的优点是需要的内存小,但是显示速度很慢,用于STM32F429系列不实用,实际项目中不推荐,用户知道怎么使用即可。下面我们分2步来说明如何将SD卡中的JPEG图片显示到LCD上面。
第1步:将JPEG图片复制到SD卡的根目录下,然后直接调用函数GUI_JPEG_DrawEx就可以显示。
- /*
- *********************************************************************************************************
- * 函 数 名: _GetData
- * 功能说明: 被函数GUI_BMP_DrawEx调用
- * 形 参:p FIL类型数据
- * NumBytesReq 请求读取的字节数
- * ppData 数据指针
- * Off 如果Off = 1,那么将重新从起始位置读取
- * 返 回 值: 返回读取的字节数
- *********************************************************************************************************
- */
- int _GetData(void * p, const U8 ** ppData, unsigned NumBytesReq, U32 Off)
- {
- static int FileAddress = 0;
- UINT NumBytesRead;
- FIL *PicFile;
-
- PicFile = (FIL *)p;
-
- /*
- * 检测缓存大小
- */
- if (NumBytesReq > sizeof(acBuffer)) {
- NumBytesReq = sizeof(acBuffer);
- }
-
- /*
- * 设置读取位置
- */
- if(Off == 1) FileAddress = 0;
- else FileAddress = Off;
- result =f_lseek(PicFile, FileAddress);
-
- /*
- * 读取数据到缓存
- */
- result = f_read(PicFile, acBuffer, NumBytesReq, &NumBytesRead);
-
- /*
- * 让指针ppData指向读取的数据
- */
- *ppData = (const U8 *)acBuffer;
-
- /*
- * 返回读取的字节数
- */
- return NumBytesRead;
- }
-
-
- /*
- *********************************************************************************************************
- * 函 数 名: _ShowJPEG1
- * 功能说明: 显示JPEG图片
- * 形 参: sFilename 要读取的文件名
- * 返 回 值: 无
- *********************************************************************************************************
- */
- void _ShowJPEG1(const char *sFilename)
- {
- /* 打开文件 */
- result = f_open(&file, sFilename, FA_OPEN_EXISTING | FA_READ | FA_OPEN_ALWAYS);
- if (result != FR_OK)
- {
- return;
- }
-
- /* 绘制JPEG图片 */
- GUI_JPEG_DrawEx(_GetData, &file, 0, 0);
-
- /* 关闭文件 */
- f_close(&file);
- }
复制代码 第2步:用户要显示指定的文件1.jpg,调用函数_ShowJPEG1("1.jpg")即可显示。
通过上面2步就完成了JPEG图片的绘制操作,这种方式绘制JPEG图片速度比较慢,项目应用中不推荐这种方式。实际显示效果参看本章节配套的实验例程说明。
17.3.3 将JPEG格式的图片转换成C文件
由于JPEG图片比较小,使用emWin的小软件Bin2C.exe转换成C文件并将其添加到MDK或者IAR工程中也是非常合适的。
小软件Bin2C.exe可以在SEGGER官网下载,地址:https://www.segger.com/downloads/emwin 。
不过下载后此软件是这样的:
对于初学者来说,这种命令行的形式使用很不方便,所以要使用MDK安装目录里面自带的,以MDK5.21版本为例,Bin2C.exe文件在路径:
C:\\Keil_v521\\ARM\\PACK\\Keil\\MDK-Middleware\\7.2.0\\emWin\\Tool。打开后是这种形式的:
下面我们讲解下这个软件如何使用:
第1步:打开此软件,点击Select file添加JPEG图片1.jpg,此图片的分辨率400*240。
第2步:加载后点击Convert即可,点击后没有任何现象,直接去图片所在的文件夹找即可,第1步中加载的文件1.jpg是来自桌面,转换后生成的1.c文件也是在桌面。
通过上面两步就完成了JPEG图片的转换,1.c文件中的代码如下:
- static const unsigned char _ac1[103357UL + 1] = {
- 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- /* 其余数据省略 */
-
- }
复制代码 下面是在模拟器上实际运行的例子(完整版例子是本章教程配套的:V6-521_STemWin实验_JPEG图片显示(模拟器)):
- #include "GUI.h"
- #include "stdio.h"
-
-
- static const unsigned char _ac1[103357UL + 1] = {
- 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- /* 其余数据省略 */
-
- }
-
- /*********************************************************************
- *
- * MainTask
- */
- void MainTask(void) {
- GUI_MEMDEV_Handle hMemJPEG;
- GUI_JPEG_INFO JpegInfo;
-
- /* emWin初始化 */
- GUI_Init();
-
- GUI_JPEG_GetInfo(_ac1, sizeof(_ac1), &JpegInfo);
-
- /* 将JPEG图片绘制到内存设备中 */
- hMemJPEG = GUI_MEMDEV_CreateEx(0, 0, JpegInfo.XSize, JpegInfo.YSize, GUI_MEMDEV_HASTRANS);
- GUI_MEMDEV_Select(hMemJPEG);
- GUI_JPEG_Draw(_ac1, sizeof(_ac1), 0, 0);
- GUI_MEMDEV_Select(0);
-
- /* 显示JPEG图片 */
- GUI_MEMDEV_WriteAt(hMemJPEG, 0, 0);
-
- while (1)
- {
- GUI_Delay(10);
- }
- }
复制代码 emWin显示大小设置为400*240,实际显示效果如下: |
|