目录
前言
前面我们实现了显示系统框架和输入系统框架,链接:
接下来我们来实现文字系统框架。
一、文字数据结构抽象
描述字符的方式:
- 1.位置、大小
- 2.点阵
点阵可以从固定大小的点阵字体文件中获得,也可以从Freetype的矢量字体文件中获得,所以我们需要抽象出一个结构体用来描述这些字符,一个结构体描述一个文字的位图,一个结构体描述一个字库操作。
1.描述一个文字的位图
2.描述一个字库操作
使用点阵绘制文字时:每个文字的大小一样,前后文件互不影响,使用Freetype绘制文字时:大小可能不同,前面文字会影响后面文字,例如:
对于单个Freetype字符,格式如下:
所以我们要抽象出一个结构体FontBitMap,能描述一个“字符”:位置、大小、位图,我们还要抽象出一个结构体FontOpr,能描述字体的操作,比如Freetype的操作、固定点阵字体的操作。
3.font_manager.h
#ifndef _FONT_MANAGER_H
#define _FONT_MANAGER_H
#include <common.h>
typedef struct FontBitMap {
Region tRegion;
int iCurOriginX;
int iCurOriginY;
int iNextOriginX;
int iNextOriginY;
unsigned char *pucBuffer;
}FontBitMap,*PFontBitMap;
typedef struct FontOpr {
char *name;
int (*FontInit)(char *aFineName);
int (*SetFontSize)(int iFontSize);
int (*GetFontBitMap)(unsigned int dwCode, PFontBitMap ptFontBitMap);
int (*GetStringRegionCar)(char *str, PRegionCartesian ptRegionCar);
struct FontOpr *ptNext;
}FontOpr,*PFontOpr;
void RegisterFont(PFontOpr ptFontOpr);
void FontSystemRegister(void);
int SelectAndInitFont(char *aFontOprName, char *aFontFileName);
int SetFontSize(int iFontSize);
int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap);
#endif
二、实现Freetype封装
首先我们需要安装和交叉编译工具链 freetype,编译时链接到 freetype 库,Freetype详细介绍可看:
位图推导:
1.freetype.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <font_manager.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
static FT_Face g_tFace;
static int g_iDefaultFontSize = 12;
static int FreeTypeFontInit(char *aFineName)
{
FT_Library library;
int error;
error = FT_Init_FreeType( &library ); /* initialize library */
if (error)
{
printf("FT_Init_FreeType err\n");
return -1;
}
error = FT_New_Face(library, aFineName, 0, &g_tFace ); /* create face object */
if (error)
{
printf("FT_New_Face err\n");
return -1;
}
FT_Set_Pixel_Sizes(g_tFace, g_iDefaultFontSize, 0);
return 0;
}
static int FreeTypeSetFontSize(int iFontSize)
{
FT_Set_Pixel_Sizes(g_tFace, iFontSize, 0);
return 0;
}
static int FreeTypeGetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{
int error;
FT_Vector pen;
FT_GlyphSlot slot = g_tFace->glyph;
pen.x = ptFontBitMap->iCurOriginX * 64; /* 单位: 1/64像素 */
pen.y = ptFontBitMap->iCurOriginY * 64; /* 单位: 1/64像素 */
/* 转换:transformation */
FT_Set_Transform(g_tFace, 0, &pen);
/* 加载位图: load glyph image into the slot (erase previous one) */
error = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER);
if (error)
{
printf("FT_Load_Char error\n");
return -1;
}
ptFontBitMap->pucBuffer = slot->bitmap.buffer;
ptFontBitMap->tRegion.iLeftUpX = slot->bitmap_left;
ptFontBitMap->tRegion.iLeftUpY = ptFontBitMap->iCurOriginY*2 - slot->bitmap_top;
ptFontBitMap->tRegion.iWidth = slot->bitmap.width;
ptFontBitMap->tRegion.iHeigh = slot->bitmap.rows;
ptFontBitMap->iNextOriginX = ptFontBitMap->iCurOriginX + slot->advance.x / 64;
ptFontBitMap->iNextOriginY = ptFontBitMap->iCurOriginY;
return 0;
}
static struct FontOpr g_tFreetypeOpr = {
.name = "freetype",
.FontInit = FreeTypeFontInit,
.SetFontSize = FreeTypeSetFontSize,
.GetFontBitMap = FreeTypeGetFontBitMap,
};
void FreetypeRegister(void)
{
RegisterFont(&g_tFreetypeOpr);
}
三、实现文字管理
我们可能要用到的字体有多种,那么怎么选择用哪个字符呢,所以我们要编写一个程序管理多种字符。
1.font_manager.c
#include <font_manager.h>
#include <string.h>
static PFontOpr g_ptFonts = NULL;
static PFontOpr g_ptDefaulFontOpr = NULL;
void RegisterFont(PFontOpr ptFontOpr)
{
ptFontOpr->ptNext = g_ptFonts;
g_ptFonts = ptFontOpr;
}
void FontSystemRegister(void)
{
extern void FreetypeRegister(void);
FreetypeRegister();
}
int SelectAndInitFont(char *aFontOprName, char *aFontFileName)
{
PFontOpr ptTmp = g_ptFonts;
while (ptTmp)
{
if (strcmp(ptTmp->name, aFontOprName) == 0)
break;
ptTmp = ptTmp->ptNext;
}
if (!ptTmp)
return -1;
g_ptDefaulFontOpr = ptTmp;
return ptTmp->FontInit(aFontFileName);
}
int SetFontSize(int iFontSize)
{
return g_ptDefaulFontOpr->SetFontSize(iFontSize);
}
int GetFontBitMap(unsigned int dwCode, PFontBitMap ptFontBitMap)
{
return g_ptDefaulFontOpr->GetFontBitMap(dwCode, ptFontBitMap);
}
四、单元测试
在之前写过的 disp_manager.c 文件代码添加一个绘制函数。
1.font_test.c
2.disp_manager.c
新添加void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor)函数。
void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor)
{
int i, j, p, q;
int x = ptFontBitMap->tRegion.iLeftUpX;
int y = ptFontBitMap->tRegion.iLeftUpY;
int x_max = x + ptFontBitMap->tRegion.iWidth;
int y_max = y + ptFontBitMap->tRegion.iHeigh;
int width = ptFontBitMap->tRegion.iWidth;
unsigned char *buffer = ptFontBitMap->pucBuffer;
//printf("x = %d, y = %d\n", x, y);
for ( j = y, q = 0; j < y_max; j++, q++ )
{
for ( i = x, p = 0; i < x_max; i++, p++ )
{
if ( i < 0 || j < 0 ||
i >= g_tDispBuff.iXres || j >= g_tDispBuff.iYres )
continue;
//image[j][i] |= bitmap->buffer[q * bitmap->width + p];
if (buffer[q * width + p])
PutPixel(i, j, dwColor);
}
}
}
3.disp_manager.h
新添加声明函数void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor);
新增头文件 #include <font_manager.h>
#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H
#include <common.h>
#include <font_manager.h>
typedef struct DispBuff {
int iXres;
int iYres;
int iBpp;
char *buff;
}DispBuff, *PDispBuff;
typedef struct DispOpr {
char *name;
int (*DeviceInit)(void);
int (*DeviceExit)(void);
int (*GetBuffer)(PDispBuff ptPDispBuff);
int (*FlushRegion)(PRegion ptRegion, PDispBuff ptPDispBuff);
struct DispOpr *ptNext;
}DispOpr, *PDispOpr;
int PutPixel(int x, int y, unsigned int dwColor);
void RegisterDisplay(PDispOpr ptPDispOpr);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
PDispBuff GetDisplayBuffer(void);
int FlushDisplayRegion(PRegion ptPRegion, PDispBuff ptPDispBuff);
void DisplaySystemRegister(void);
void DrawFontBitMap(PFontBitMap ptFontBitMap, unsigned int dwColor);
#endif
4.上机测试
上电开发板,挂载 Ubuntu 的 NFS 目录,编译测试: