项目代码链接:https://github.com/studyalldaya/100ask_project1
freetype库
freetype2库相关博客可以参考:
一般使用就是:
- 使用 FT_Init_FreeType() 函数初始化一个 FT_Library 句柄。
int ret;
FT_Library library;
/* 显示矢量字体 */
ret = FT_Init_FreeType(&library); /* initialize library */
if (ret) {
printf("FT_Init_FreeType err\n");
return -1;
}
- 通过字体文件名加载FT_Face
ret = FT_New_Face(library, file_path, 0, &face); /* create face object */
if (ret) {
printf("FT_New_Face err\n");
return -1;
}
- 此处设置字体编码方式为Unicode,如果不设置,FreeType默认为 utf-16编码类型
FT_Select_Charmap(face, FT_ENCODING_UNICODE);
- 设置字体大小
//设置成12*12像素, 0表示和另一个值相等!
FT_Set_Pixel_Sizes(face, defaultFontSize, 0);
- 设置旋转角度及原点位置,加载字形位图
直接使用 FT_Load_Char() 来代替 FT_Get_Char_Index()、FT_Get_Load_Glyph() 和 FT_Render_Glyph(),一步到位,例如:
FT_Set_Transform(face, 0, &pen);//0表示不旋转
/* 加载位图,默认RGB888 */
error = FT_Load_Char(face, code, FT_LOAD_RENDER);//加载face.glyph
if (error) {
printf("FT_Load_Char error\n");
return -1;
}
其中 FT_LOAD_RENDER 表示直接将图像转为位图,所以不需要使用 FT_Render_Glyph() 函数。
该函数默认生成的位图是 FT_RENDER_MODE_NORMAL 类型,即 RGB888。
使用这个库时要注意头文件的包含目录应该到${INC_DIR}/freetype2,
单位为1/64像素。
底层通过freetype获得bitmap
fbt->currOriginX和fbt->currOriginY有函数参数fbt提供,即要
static int freetype_get_bitmap(unsigned int code, Font_bitmap *fbt)
{
int error;
FT_Vector pen;
FT_Glyph glyph;
FT_GlyphSlot slot;
/*得到开始位置*/
pen.x = fbt->currOriginX * 64; /* 单位: 1/64像素 */
pen.y = fbt->currOriginY * 64; /* 单位: 1/64像素 */
/* 设置旋转以及位置 */
FT_Set_Transform(face, 0, &pen);//0表示不旋转
/* 加载位图,默认RGB888 */
error = FT_Load_Char(face, code, FT_LOAD_RENDER);//加载face.glyph
if (error) {
printf("FT_Load_Char error\n");
return -1;
}
slot = face->glyph;
fbt->buffer = slot->bitmap.buffer;
fbt->region.x = slot->bitmap_left;
fbt->region.y = fbt->currOriginY * 2 - slot->bitmap_top;
fbt->region.width = slot->bitmap.width;
fbt->region.height = slot->bitmap.rows;
fbt->nextOriginX = fbt->currOriginX + slot->advance.x / 64;
fbt->nextOriginY = fbt->currOriginY;
return 0;
}
同样提供注册函数给上层manager。
void freetype_font_register(void)
{
register_font_style(&freetype_style);
}
上层manager
用Font_bitmap 表示一个字符的相关信息,有它的region、freetype的origin原件,表示字符的位图的buffer。
用Font_style 表示字体显示的方式,可以是普通点阵也可以是用freetype的矢量字体,这里使用freetype。
typedef struct Font_bitmap {
Region region;
int currOriginX;//freetype 当前基点的x
int currOriginY;
int nextOriginX;
int nextOriginY;
unsigned char *buffer;
} Font_bitmap;
typedef struct Font_style {
char *name;//用普通点阵还是使用freetype
int (*font_init)(char *fname);
int (*font_set_size)(int size);
int (*font_get_bitmap)(unsigned int code, Font_bitmap *fbt);//code:编码值
int (*font_get_text_bbox)(char *str, Cartesian_region *textBBox);
struct Font_style *next;
} Font_style;
manager这层主要是对外提供一些api函数,首先和其它模块一样用链表把不同style链接起来,方便后续进行扩展。
extern void freetype_font_register(void);
void register_font_style(Font_style *fs)
{
fs->next = fontStyleHead;
fontStyleHead = fs;
}
void font_init(void)
{
freetype_font_register();
}
注册完底层的style之后,可以根据name来选择作为默认的style,就是遍历链表,找到对应的那个节点,并调用那个节点的init函数。
//传入style以及 ttc文件 or ttf文件 ttf为字形文件,ttc里面含有多个ttf也就是含有多个字形,通过不同编码找到对应字形
int select_and_init_font(char *style, char *file_path)
{
Font_style *ptTmp = fontStyleHead;
while (ptTmp) {
if (strcmp(ptTmp->name, style) == 0)
break;
ptTmp = ptTmp->next;
}
if (!ptTmp)
return -1;
defaultFontStyle = ptTmp;
return ptTmp->font_init(file_path);
}
api一般只是返回对应的默认设备的相应函数即可,把底层函数细节隐藏起来。
int font_get_bitmap(unsigned int code, Font_bitmap *fbm)
{
return defaultFontStyle->font_get_bitmap(code, fbm);
}