这个文件主要是写了一些图片、文字的渲染,主要调用fonts、encoding、picfrm这几个文件中的函数
所有函数的简单分析
/* PT_VideoMem预先分配好的内存,刷到fb上,最终调用的是memcpy,在fb.c中,提供的一个ShowPage函数 */
void FlushVideoMemToDev(PT_VideoMem ptVideoMem)
/* 查看某一个文件是否支持bmp或者jpg格式,0不支持,1支持*/
int isPictureFileSupported(char *strFileName)
/**************************************************************************************************/
/* 获取ICON_PATH地址下,获取bmp格式的图标的数据,这里注意是bmp格式
* 注意这里传进来的ptPixelDatas,是个指针,其是在上一层函数中分配的
* 这个函数里未分配内存,而又写了一个和这个函数相似的函数来释放内存,写的有点乱
*/
int GetPixelDatasForIcon(char *strFileName, PT_PixelDatas ptPixelDatas)
/* 这个名字改成 FreePixelDatas 比较好,毕竟就是释放一个T_PixelDatas结构体
* 并不在乎是不是图标的PT_PixelDatas
* 而名字这样写,搞的像和上面那个函数对应似的,好像内存是在上面的函数中分配的
* free(ptPixelDatas->aucPixelDatas); 最终也是调用的这个函数,不懂为啥要写这么多,不会搞混么
*/
void FreePixelDatasForIcon(PT_PixelDatas ptPixelDatas)
/**************************************************************************************************/
/* 从一个文件中获取像素数据,入参和GetPixelDatasForIcon一毛子一样
* GetPixelDatasForIcon函数是单单获得BMP文件的数据
* 这个函数是找一个可以使用的解释器获得数据,不明白有这个了,为啥还要上面那个函数
*/
int GetPixelDatasFrmFile(char *strFileName, PT_PixelDatas ptPixelDatas)
/* 不懂这里为啥又有一个 */
void FreePixelDatasFrmFile(PT_PixelDatas ptPixelDatas)
/**************************************************************************************************/
/* ptVideoMem这块内存中的(x,y)点设置成dwColor颜色 */
static int SetColorForPixelInVideoMem(int iX, int iY, PT_VideoMem ptVideoMem, unsigned int dwColor)
/* 把ptVideoMem中 从(iTopLeftX,iTopLeftY)到(iBotRightX,iBotRighY)这个范围内设置成颜色dwColor */
void ClearRectangleInVideoMem(int iTopLeftX, int iTopLeftY, int iBotRightX, int iBotRightY, PT_VideoMem ptVideoMem, unsigned int dwColor)
/* 判断ptFontBitMap里的字符是不是在指定的区域内 */
static int isFontInArea(int iTopLeftX, int iTopLeftY, int iBotRightX, int iBotRightY, PT_FontBitMap ptFontBitMap)
/* 这两个函数其实就是调用了一下InvertButton 把数据反转了一下*/
void PressButton(PT_Layout ptLayout)
void ReleaseButton(PT_Layout ptLayout)
三个关键函数详解
MergeOneFontToVideoMem函数
/* 把一个字符,显示到ptVideoMem里,字符里有位置的信息 */
static int MergeOneFontToVideoMem(PT_FontBitMap ptFontBitMap, PT_VideoMem ptVideoMem)
{
int i;
int x, y;
int bit;
int iNum;
unsigned char ucByte;
if (ptFontBitMap->iBpp == 1) /* 如果字体数据里面,一个像素用一位来表示,即一个字节就表示了8个像素*/
{
for (y = ptFontBitMap->iYTop; y < ptFontBitMap->iYMax; y++) /* 一行一行的 */
{
/* 第 y - ptFontBitMap->iYTop + 1 行数据距离原点的偏移量
* 比如,这个"字"的第1行像素的起始位置(这个就是字符数据的起始位置),是 0 * ptFontBitMap->iPitch = 0
* 比如,这个"字"的第4行像素的起始位置,距离字符数据原点的偏移量是: 3 * ptFontBitMap->iPitch
* ptFontBitMap->iPitch也有说明,是第N行到第N+1行数据之间的偏移量,就是一行像素占用多少字节
*/
i = (y - ptFontBitMap->iYTop) * ptFontBitMap->iPitch;
/* 一行里,x的坐标从最左边移动到最右边,一个像素一个像素的画,而8个像素,使用字符数据中的一个字节 */
for (x = ptFontBitMap->iXLeft, bit = 7; x < ptFontBitMap->iXMax; x++)
{
/* bit==7 时表示字符数据中已经取完1个字节的数据了(也就是说已经用完8位,即描画了8个像素点了)
* 这里要将字符数据中下一个字节取出来,描画下一次的 8个像素
*/
if (bit == 7)
{
ucByte = ptFontBitMap->pucBuffer[i++];
}
/* 从最高位开始取,一次取1位,如果是1的话,就代表是需要画出的一个点*/
/* 从这里也可以看出来,字符数据的一个字符,高位在左边,地位在右边*/
if (ucByte & (1<<bit))
{ /* 这里就给这个像素点上褐色的点,注意这里传进去的数据是32位 */
iNum = SetColorForPixelInVideoMem(x, y, ptVideoMem, COLOR_FOREGROUND);
}
else
{
/* 如果不是1,就去这个坐标把背景色打上去,也就是说不画点 */
// g_ptDispOpr->ShowPixel(x, y, 0); /* 黑 */
iNum = SetColorForPixelInVideoMem(x, y, ptVideoMem, COLOR_BACKGROUND);
}
/* 在描点的时候出错了 */
if (iNum == -1)
{
return -1;
}
/* 进入下一个字节 */
bit--;
/* 7.6.5.4.3.2.1.0 刚好是执行8次,即一个字节*/
if (bit == -1)
{
bit = 7;
}
}
}
}
/* 如果字符数据是8bpp的,即一个字符表示一个像素点 */
else if (ptFontBitMap->iBpp == 8)
{
/* 如上,从上到下,从左到右一行一行的来 */
for (y = ptFontBitMap->iYTop; y < ptFontBitMap->iYMax; y++)
for (x = ptFontBitMap->iXLeft; x < ptFontBitMap->iXMax; x++)
{
//g_ptDispOpr->ShowPixel(x, y, ptFontBitMap->pucBuffer[i++]);
/* 只有在这一个字节的数据==0时,才不需要画点 */
if (ptFontBitMap->pucBuffer[i++])
{
iNum = SetColorForPixelInVideoMem(x, y, ptVideoMem, COLOR_FOREGROUND);
}
else
{
iNum = SetColorForPixelInVideoMem(x, y, ptVideoMem, COLOR_BACKGROUND);
}
if (iNum == -1)
{
return -1;
}
}
}
/* 只支持字体数据 1bpp 和 8bpp 的*/
else
{
DBG_PRINTF("ShowOneFont error, can't support %d bpp\n", ptFontBitMap->iBpp);
return -1;
}
return 0;
}
MergerStringToCenterOfRectangleInVideoMem函数
/* 把一个字符串pucTextString,显示到ptVideoMem内存中的 (iTopLeftX,iTopLeftY) (iBotRightX,iBotRightY)这个区域内 */
int MergerStringToCenterOfRectangleInVideoMem(int iTopLeftX, int iTopLeftY, int iBotRightX, int iBotRightY, unsigned char *pucTextString, PT_VideoMem ptVideoMem)
{
int iLen;
int iError;
unsigned char *pucBufStart;
unsigned char *pucBufEnd;
unsigned int dwCode;
T_FontBitMap tFontBitMap; /* 存放字符串中一个字符的信息 */
int bHasGetCode = 0;
int iMinX = 32000, iMaxX = -1;
int iMinY = 32000, iMaxY = -1;
int iStrTopLeftX , iStrTopLeftY; /* 字符串左上角的坐标 */
int iWidth, iHeight;
/* 先设置第一个字的原点为(0,0)
* 这里有一个问题先存疑,(iCurOriginX,iCurOriginY)是以左下角为坐标原点
* 而这里都设置成了(0,0),那么在freetype.c中计算的左上角坐标就不是正整数了
* 这里没问题,可以这么写,最大和最小的Y坐标都是负数,大减小就是正数了
*/
tFontBitMap.iCurOriginX = 0;
tFontBitMap.iCurOriginY = 0;
/* 字符串开始的地址 */
pucBufStart = pucTextString;
/* 字符串结束的地址,*/
pucBufEnd = pucTextString + strlen((char *)pucTextString);
/* 清除这个区域 */
ClearRectangleInVideoMem(iTopLeftX, iTopLeftY, iBotRightX, iBotRightY, ptVideoMem, COLOR_BACKGROUND);
/* 先计算字符串显示的总体宽度、高度 */
while (1)
{
/* 使用ASCII或者GBK,取出字符的编码
* 如果字符是英文,那么就使用一个字节,返回1,并把其编码放到dwCode中
* 如果字符是中文,那么就用两个字节,返回2,并把编码放到dwCode中
*/
iLen = GetCodeFrmBuf(pucBufStart, pucBufEnd, &dwCode);
if (0 == iLen)
{
/* 就是没有获得编码,要么是字符串完了,要么是这个字符串里没有字符 */
/* 如果bHasGetCode在这里时等于0,那就代表这个地址指向的地方没有字符串,直接返回错误*/
if (!bHasGetCode)
{
//DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
}
else
{
break;
}
}
bHasGetCode = 1;
/* 此时,pucBufStart指向了下一个字符 */
pucBufStart += iLen;
/* 获得字符的位图, 位图信息里含有字符显示时的左上角、右下角坐标,在freetype.c中的函数里设置 */
iError = GetFontBitmap(dwCode, &tFontBitMap);
if (0 == iError)
{
/* 在这里比较,获得最大的框 */
/* 这iMinX是在第一个字符中得到的 */
if (iMinX > tFontBitMap.iXLeft)
{
iMinX = tFontBitMap.iXLeft;
}
/* iMaxY是在最后一个字符中得到的 */
if (iMaxX < tFontBitMap.iXMax)
{
iMaxX = tFontBitMap.iXMax;
}
/* 关于Y坐标,是可能在任何一个字符中得到的,因为每个字符的高度都不确定,不一定那个字符高哪个字符低
* 这里面都是负值,因为一开始把左下角的原点定在了(0,0),freetype.c中是从左下角往上算的
* 但是对于后面是没有影响的
*/
if (iMinY > tFontBitMap.iYTop)
{
iMinY = tFontBitMap.iYTop;
}
/* 源码写错了 iMaxY < tFontBitMap.iXMax */
if (iMaxY < tFontBitMap.iYMax)
{
iMaxY = tFontBitMap.iYMax;
}
/* 前一个字符里的“下个字符的原点”,就是下一个字符用的原点 */
tFontBitMap.iCurOriginX = tFontBitMap.iNextOriginX;
tFontBitMap.iCurOriginY = tFontBitMap.iNextOriginY;
}
else
{
DBG_PRINTF("GetFontBitmap for calc width/height error!\n");
}
}
/* 算出整个字符串所占用的长宽,这里iMaxY、iMinY都是负数,可能iMaxY是0,而两个一减就都是正数了,所以没问题 */
iWidth = iMaxX - iMinX;
iHeight = iMaxY - iMinY;
/* 如果字符串过长,那么就显示一部分 */
if (iWidth > iBotRightX - iTopLeftX)
{
iWidth = iBotRightX - iTopLeftX;
}
/* 如果字符串过高,就不显示了*/
if (iHeight > iBotRightY - iTopLeftY)
{
DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
//DBG_PRINTF("iHeight = %d, iBotRightY - iTopLeftX = %d - %d = %d\n", iHeight, iBotRightY, iTopLeftY, iBotRightY - iTopLeftY);
return -1;
}
//DBG_PRINTF("iWidth = %d, iHeight = %d\n", iWidth, iHeight);
/* 2.确定第1个字符的原点
* 2.1 先计算左上角坐标
*/
iStrTopLeftX = iTopLeftX + (iBotRightX - iTopLeftX - iWidth) / 2;
iStrTopLeftY = iTopLeftY + (iBotRightY - iTopLeftY - iHeight) / 2;
/* 2.2 再计算第1个字符原点坐标,左下角的坐标
* iMinX - 原来的iCurOriginX(0) = iStrTopLeftX - 新的iCurOriginX
* iMinY - 原来的iCurOriginY(0) = iStrTopLeftY - 新的iCurOriginY
*/
/* 这里减iMinX是因为,当原点是(0,0)时,字符串最左边是在iMinX
* 而如果把字符串的最左边设置成iStrTopLeftX时,那么字符串的的最左边是在iStrTopLeftX+iMinX这个地方了,就相当于字符串右移了
* 那就不是我们想让它出现的位置了,所以这里提前减去iMinX,作为左下角原点X坐标
*/
tFontBitMap.iCurOriginX = iStrTopLeftX - iMinX;
/* 首先,iMinY在上面来说是个负数,这里减去一个负数,相当于加一个数
* iStrTopLeftY是左上角的坐标,需要加上一个值编程左下角的坐标
* 这里为什么加 |iMinY| ,而不加上面算出的高度iHeight,我认为原因和上面算横坐标是一样的
* freetype给出的字体像素数据,是以左下角为原点来说的,但并不是说其给的元素像素都是在第一象限,即xy坐标都是正的
* 像比如字母g,它的y坐标有负值
* 所以如果这里直接加一个高度iHeight,那么其真实的高度又会超出iStrTopLeftY+iHeight,就超出了我们设想的那个框
*/
tFontBitMap.iCurOriginY = iStrTopLeftY - iMinY;
pucBufStart = pucTextString;
bHasGetCode = 0;
while (1)
{
/* 从字符串中逐个取出字符 */
iLen = GetCodeFrmBuf(pucBufStart, pucBufEnd, &dwCode);
if (0 == iLen)
{
/* 字符串结束
* 其实这个地方bHasGetCode 已经不需要判断了,能执行到这说明字符串肯定不是空的 */
if (!bHasGetCode)
{
DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return -1;
}
else
{
break;
}
}
/* 执行这个while之前,没有bHasGetCode=0,所以这一句也是没有意义的 */
bHasGetCode = 1;
pucBufStart += iLen;
/* 获得字符的位图
* 由左下角原点,算出其他点的位置,比如左上角的原点,bpp,pitch,iXmax,iYmax等,都是在这个函数里算的
* 调用这个函数之前只需要算出左下角的原点就行
*/
iError = GetFontBitmap(dwCode, &tFontBitMap);
if (0 == iError)
{
//DBG_PRINTF("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
/* 显示一个字符 */
if (isFontInArea(iTopLeftX, iTopLeftY, iBotRightX, iBotRightY, &tFontBitMap))
{
if (MergeOneFontToVideoMem(&tFontBitMap, ptVideoMem))
{
DBG_PRINTF("MergeOneFontToVideoMem error for code 0x%x\n", dwCode);
return -1;
}
}
else
{
return 0;
}
/* 这个结构体把原点设置成下一个字符的原点 */
tFontBitMap.iCurOriginX = tFontBitMap.iNextOriginX;
tFontBitMap.iCurOriginY = tFontBitMap.iNextOriginY;
}
else
{
DBG_PRINTF("GetFontBitmap for drawing error!\n");
}
}
return 0;
}
InvertButton函数
/* 把某一块图层的数据全部取反,ptLayout携带着需要取反的那一块空间的xy坐标 */
static void InvertButton(PT_Layout ptLayout)
{
int iY;
int i;
int iButtonWidthBytes;
unsigned char *pucVideoMem;
/* 获得默认的显示设备 */
PT_DispOpr ptDispOpr = GetDefaultDispDev();
/* 获得默认显示设备的显存 */
pucVideoMem = ptDispOpr->pucDispMem;
/* 算出需要取反的空间的起始地址 */
pucVideoMem += ptLayout->iTopLeftY * ptDispOpr->iLineWidth + ptLayout->iTopLeftX * ptDispOpr->iBpp / 8; /* 图标在Framebuffer中的地址 */
/* 一行需要给多少字节的数据取反 */
iButtonWidthBytes = (ptLayout->iBotRightX - ptLayout->iTopLeftX + 1) * ptDispOpr->iBpp / 8;
/* 一行一行的来 */
for (iY = ptLayout->iTopLeftY; iY <= ptLayout->iBotRightY; iY++)
{
/* 每一行中,一个字节一个字节的来 */
for (i = 0; i < iButtonWidthBytes; i++)
{
pucVideoMem[i] = ~pucVideoMem[i]; /* 取反 */
}
/* 取完一行,开始下一行 */
pucVideoMem += ptDispOpr->iLineWidth;
}
}