数码相框-主界面MainPage页面规划
定义页面布局
/**
* 主页面布局数组
*
* 该数组定义了主页面上各图标的位置和对应的图像文件名。数组中的每个元素代表一个图标,
* 其中各个字段含义如下:
* - iTopLeftX: 图标左上角X轴坐标
* - iTopLeftY: 图标左上角Y轴坐标
* - iBotRightX: 图标右下角X轴坐标
* - iBotRightY: 图标右下角Y轴坐标
* - strIconName: 图标对应的图像文件名(BMP格式)
*
* 数组末尾以NULL作为结束标记。
*/
static T_Layout g_atMainPageLayout[] = {
// 浏览模式图标
{0, 0, 0, 0, "browse_mode.bmp"},
// 连播模式图标
{0, 0, 0, 0, "continue_mod.bmp"},
// 设置图标
{0, 0, 0, 0, "setting.bmp"},
// 数组结束标记
{0, 0, 0, 0, NULL},
};
图标计算
图标计算:
-
图标高度与总体高度的比例: 一个图标的高度为2单位,总高度为4个基本单位(图标间隔)加上3个图标高度(每个图标高度为2单位),即:总高度 = 4 + 3 * 2 = 10 单位
-
因此,一个图标的高度占总高度的比例为:图标高度占比 = 图标高度 / 总高度 = 2 / 10
-
图标与屏幕分辨率的比例关系: 图标的分辨率为256×128像素,宽高比为2:1。这意味着图标的宽度始终为其高度的两倍。
-
计算图标在屏幕上的实际尺寸: 设屏幕的垂直分辨率(y轴方向)为
yres
像素。根据图标高度占比,一个图标的实际高度应为:- 图标高度 = 图标高度占比 × 屏幕垂直分辨率 = (2/10) × yres 像素。
- 由于图标的宽高比为2:1,其宽度为:图标宽度 = 2 × 图标高度 = 2 × ((2/10) × yres) 像素 = (4/10) × yres 像素。
iIconHeight = iYres * 2 / 10; // 计算图标高度
iIconWidth = iIconHeight * 2; // 根据高度计算宽度
iIconX = (iXres - iIconWidth)/2; // 计算图标X坐标
iIconY = iYres / 10; // 计算图标顶部Y坐标,从1/10的间隔开始画图
对文件的映射操作
定义文件映射结构体:
#ifndef _FILE_H
#define _FILE_H
// 定义文件映射结构体
typedef struct FileMap {
char strFileName[128]; // 文件名
int iFd; // 文件描述符
int iFileSize; // 文件大小
unsigned char *pucFileMapMem; // 文件映射内存指针
}T_FileMap, *PT_FileMap;
// 映射文件到内存
// @param ptFileMap 指向T_FileMap结构的指针,包含待映射文件的相关信息
// @return 成功返回0,失败返回非0
int MapFile(PT_FileMap ptFileMap);
// 从内存取消文件映射
// @param ptFileMap 指向T_FileMap结构的指针,包含待取消映射文件的相关信息
void UnMapFile(PT_FileMap ptFileMap);
#endif /* _FILE_H */
将文件映射到内存中:
/**
* MapFile - 将文件映射到内存中
* @param ptFileMap: 指向文件映射结构体的指针,包含文件名和后续映射操作所需的信息
* @return: 成功返回0,失败返回-1
*
* 本函数的主要功能是打开指定文件,并将其映射到内存中,以便于直接在内存中对文件进行读写操作。
* 具体步骤包括:打开文件、获取文件状态信息以获取文件大小、调用mmap系统函数将文件映射到内存。
*/
int MapFile(PT_FileMap ptFileMap)
{
int iFd;
struct stat tStat;
/* 打开文件,以读写方式 */
iFd = open(ptFileMap->strFileName, O_RDWR);
if (iFd == -1) // 打开文件失败
{
DBG_PRINTF("can't open %s\n", ptFileMap->strFileName);
return -1;
}
ptFileMap->iFd = iFd;
fstat(iFd, &tStat); // 获取文件状态信息
ptFileMap->iFileSize = tStat.st_size; // 设置文件大小
// 将文件映射到内存,设置为可读写,并与文件共享
ptFileMap->pucFileMapMem = (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, iFd, 0);
if (ptFileMap->pucFileMapMem == (unsigned char *)-1) // 映射失败
{
DBG_PRINTF("mmap error!\n");
return -1;
}
return 0; // 成功
}
取消文件映射:
/**
* MapFile - 将文件映射到内存中
* @param ptFileMap: 指向文件映射结构体的指针,包含文件名和后续映射操作所需的信息
* @return: 成功返回0,失败返回-1
*
* 本函数的主要功能是打开指定文件,并将其映射到内存中,以便于直接在内存中对文件进行读写操作。
* 具体步骤包括:打开文件、获取文件状态信息以获取文件大小、调用mmap系统函数将文件映射到内存。
*/
int MapFile(PT_FileMap ptFileMap)
{
int iFd;
struct stat tStat;
/* 打开文件,以读写方式 */
iFd = open(ptFileMap->strFileName, O_RDWR);
if (iFd == -1) // 打开文件失败
{
DBG_PRINTF("can't open %s\n", ptFileMap->strFileName);
return -1;
}
ptFileMap->iFd = iFd;
fstat(iFd, &tStat); // 获取文件状态信息
ptFileMap->iFileSize = tStat.st_size; // 设置文件大小
// 将文件映射到内存,设置为可读写,并与文件共享
ptFileMap->pucFileMapMem = (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, iFd, 0);
if (ptFileMap->pucFileMapMem == (unsigned char *)-1) // 映射失败
{
DBG_PRINTF("mmap error!\n");
return -1;
}
return 0; // 成功
}
从图标中获取像素数据
/**
* 为图标获取像素数据
*
* 本函数负责从指定的文件中获取图标像素数据,首先会检查文件是否存在于指定路径下,并且是BMP格式,
* 然后获取图标显示的分辨率及每像素位深度(Bpp),最后提取像素数据。
*
* @param strFileName 要处理的图标文件名(不含路径)
* @param ptPixelDatas 指向PT_PixelDatas结构体的指针,用于接收像素数据
* @return 成功返回0,失败返回-1
*/
int GetPixelDatasForIcon(char *strFileName, PT_PixelDatas ptPixelDatas)
{
T_FileMap tFileMap;
int iError;
int iXres, iYres, iBpp;
// 构造图标文件的完整路径 图标存在/etc/digitpic/icons/
snprintf(tFileMap.strFileName, 128, "%s/%s", ICON_PATH, strFileName);
tFileMap.strFileName[127] = '\0';
// 将文件映射到内存
iError = MapFile(&tFileMap);
if (iError)
{
DBG_PRINTF("MapFile %s error!\n", strFileName);
return -1;
}
// 检查文件是否为BMP格式
iError = g_tBMPParser->isSupport(tFileMap.pucFileMapMem);
if (iError == 0)
{
DBG_PRINTF("%s is not bmp file\n", strFileName);
return -1;
}
// 获取图标显示的分辨率及每像素位深度
GetDispResolution(&iXres, &iYres, &iBpp);
ptPixelDatas->iBpp = iBpp;
// 从文件内存映射中提取像素数据
iError = g_tBMPParser->GetPixelDatas(tFileMap.pucFileMapMem, ptPixelDatas);
if (iError)
{
DBG_PRINTF("GetPixelDatas for %s error!\n", strFileName);
return -1;
}
return 0;
}
显示主页面
/**
* 显示主页面
*
* @param atLayout 页面布局信息
*
* 本函数负责根据提供的页面布局信息,在屏幕上显示主页面。主要步骤包括:
* 1. 获取用于显示主页面的显存;
* 2. 若显存中的页面图片状态不是已生成,则计算图标大小和位置,绘制图标,并更新显存中的页面图片状态;
* 3. 将显存中的图像刷新到设备屏幕上;
* 4. 释放显存资源。
*/
static void ShowMainPage(PT_Layout atLayout)
{
PT_VideoMem ptVideoMem; // 用于存储视频内存的指针
T_PixelDatas tOriginIconPixelDatas; // 原始图标像素数据
T_PixelDatas tIconPixelDatas; // 处理后的图标像素数据
int iIconWidth; // 图标宽度
int iIconHeight; // 图标高度
int iIconX; // 图标X轴坐标
int iIconY; // 图标Y轴坐标
int iXres, iYres, iBpp; // 屏幕分辨率和位深度
int iError; // 错误码
/* 1. 获得显存 */
ptVideoMem = GetVideoMem(ID("main"), 1);
if (ptVideoMem == NULL)
{
DBG_PRINTF("can't get video mem for main page!\n");
return;
}
/* 2. 描画数据 */
if (ptVideoMem->ePicState != PS_GENERATED)
{
GetDispResolution(&iXres, &iYres, &iBpp); // 获取屏幕分辨率
iIconHeight = iYres * 2 / 10; // 计算图标高度
iIconWidth = iIconHeight * 2; // 根据高度计算宽度
iIconX = (iXres - iIconWidth)/2; // 计算图标X坐标
iIconY = iYres / 10; // 计算图标顶部Y坐标,从1/10的间隔开始画图
// 初始化图标像素数据结构
tIconPixelDatas.iBpp = iBpp;
tIconPixelDatas.iWidth = iIconWidth;
tIconPixelDatas.iHeight = iIconHeight;
tIconPixelDatas.iLineBytes = iIconWidth * iBpp / 8;
tIconPixelDatas.iTotalBytes = tIconPixelDatas.iLineBytes * iIconHeight;
tIconPixelDatas.aucPixelDatas = malloc(tIconPixelDatas.iTotalBytes);
if (tIconPixelDatas.aucPixelDatas == NULL)
{
free(tIconPixelDatas.aucPixelDatas);
return;
}
// 遍历布局中的所有图标
while (atLayout->strIconName)
{
// 设置图标在屏幕上的位置
atLayout->iTopLeftX = iIconX;
atLayout->iTopLeftY = iIconY;
atLayout->iBotRightX = iIconX + iIconWidth - 1;
atLayout->iBotRightY = iIconY + iIconHeight - 1;
iError = GetPixelDatasForIcon(atLayout->strIconName, &tOriginIconPixelDatas); // 获取图标像素数据
if (iError)
{
DBG_PRINTF("GetPixelDatasForIcon error!\n");
return;
}
PicZoom(&tOriginIconPixelDatas, &tIconPixelDatas); // 缩放图标
PicMerge(iIconX, iIconY, &tIconPixelDatas, &ptVideoMem->tPixelDatas); // 将图标合并到显存中的图像
FreePixelDatasForIcon(&tOriginIconPixelDatas); // 释放原始图标像素数据
atLayout++; // 移动到下一个图标
iIconY += iYres * 3 / 10; // 调整图标Y轴坐标,为下一个图标留出空间
}
free(tIconPixelDatas.aucPixelDatas); // 释放图标像素数据的内存
ptVideoMem->ePicState = PS_GENERATED; // 设置图片状态为已生成
}
/* 3. 刷到设备上去 */
FlushVideoMemToDev(ptVideoMem);
/* 4. 解放显存 */
PutVideoMem(ptVideoMem);
}
释放显存区
/**
* 释放图标像素数据
* @param ptPixelDatas 指向像素数据的指针
*
* 该函数通过调用g_tBMPParser的FreePixelDatas方法,来释放图标相关的像素数据资源。
*/
void FreePixelDatasForIcon(PT_PixelDatas ptPixelDatas)
{
g_tBMPParser->FreePixelDatas(ptPixelDatas); // 调用BMP解析器的函数释放像素数据
}
/**
* 释放BMP图像的像素数据内存
* @param ptPixelDatas 指向包含像素数据的结构体的指针
* @return 始终返回0
*/
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas)
{
// 释放存储像素数据的内存
free(ptPixelDatas->aucPixelDatas);
return 0;
}