=========================================
基础篇
=========================================
font family, 一类字体的总称,包括 look, style, serif 等等
font face, font family 中的某一中特定 style,比如:
Fixed # font family
Fixed:style=Bold # font face
Fixed:style=Regular # font face
对于同样的 font family,可以有不同的 font file format (文件格式),比如:OpenType、TrueType。以 TrueType 为例,不同的 font face 保存在不同的文件中,如:arial.ttf(Arial Regular)、ariali.ttf(Arial Italic)。
=====
glyph, character image, 其实就是一个 bitmap, 对应着某个字(字符)。
=====
dpi (dots per inch) 其实就是 pixel per inch,300x600 dpi 意味着每 inch 宽300pixel, 高600pixel。再如,同样 640x480 的分辨率,在15''和17''的显示器上,per pixel 的大小是不一样的。
point, pt, 几号字体,一个绝对大小。1 point = 1/72 inch
pixel size,像素尺寸,特定 dpi 下,同样字号的字体,使用固定大小的像素尺寸。
pixel_size = point_size * resolution / 72
我们常说的 12pt 就是12号字,但要注意,windows上我们说的12pt字,都是 96dpi 条件下的。如:pixel_size = 12 * 96 / 72 = 16,即普通情况下,显示器通过 16x16 pixels 来显示一个字符(汉字)。这里的 16x16 也就是一个 glyph 的 width x height 了。
=====
矢量化字体 (vectorial representation)
字体的每个 glyph 有一个原始的初始大小,叫做 EM size。不同 point 大小的字体,是通过对原始大小的缩放来进行的。
这一节没太懂。- -# TODO
=====
因为要缩放, 所以缩放后, 可能字体变形严重,就不好看了。所以字体中还包括了一些 grid-fitting (hinting) 信息,比如字母 I, T 的'|'竖线应该在正中间等信息。保证缩放后效果不至于失真太严重。
=====
kerning (字距调整), 比如 A 和 V 之间,应该稍微挨近些 AV,才显得好看。
不过方块汉子似乎没有 kerning 的必要了。
=========================================
应用篇
=========================================
言归正传,理论基础补完了,来看看如何用 FreeType2 绘制文字。FreeType2 做了什么事情,其实支持读取不同的 font file format,然后生成 glyph(bitmap) 让你可以绘制出字体。
---------------------------------------
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_ULong text[] = { 0x4e2d, 0x6587, 'a', 'b' }; // 中国ab
int base_x = 0, base_y = 0;
// 初始化一个 lib,多线程的话,每个线程应拥有自己的一个 lib
FT_Init_FreeType( &library );
// 打开 wqy-zenhei.ttf 文件
FT_New_Face( library, "wqy-zenhei.ttf", 0, &face );
// 参数:face, char_width, char_height, horz_resolution, vert_resolution
//
// 设置字号,这里 char_height, vert_resolution 设置 0,表示
// 沿用 char_width, horz_resolution 的值。这里设置 12pt 字号,96dpi
// 注意 12 * 64,因为 FreeType2 中所有 float 都是通过变换成整数来做的,这
// 里是 26.6 float format,所以 (12 << 6) == 12.0
FT_Set_Char_Size(face, 12*64, 0, 96, 0);
// 加载一个具体的字符的 glyph,注意第三个参数,不同的参数可以得到不同的效果
// 加载之后,face->glyph 就是加载好的字体的信息了(包括bitmap)
FT_Load_Char(face, text[0], FT_LOAD_RENDER);
slot = face->glyph;
// 绘制 slot->bitmap;
for ( y = base_y, q = 0; y < bitmap->rows+base_y; y++, q++ )
{
for ( x = base_x, p = 0; x < bitmap->width+base_x; x++, p++ )
{
if ( bitmap->pixel_format == FT_PIXEL_MODE_GRAY )
{
// bitmap->buffer 是 256-gray map, one byte / pixel
offset = y*screen_pitch + x;
index = q*bitmap->pitch + p;
screen_buffer[offset] = bitmap->buffer[index];
}
else
{
// bitmap->buffer 是 2-gray map, one bit / pixel
offset = y*screen_pitch + x;
index = q*bitmap->pitch + p;
flag = bitmap->buffer[index] & (1<<(7-(p%8)));
screen_buffer[offset] = flag ? BLACK : BGCOLOR;
}
}
}
// 绘制这个字符后,应该向右走几个像素
base_x += (slot->advance.x / 64);
---------------------------------------
注意上面 bitmap->pixel_format,其告知了 bitmap->buffer 中信息的格式。对于普通的 TrueType,都是通过样板缩放得到特定大小的 glyph 的。但为了让较小的字符看起来也非常清晰,字体中的某些字号可能会是特殊制作的点阵字符(fixed size),比如 windows 的宋体(simsun.ttf/ttc)中的 9pt~12pt、文泉驿(wenq.org)正黑的 9pt~12pt。对于点阵字,就是上面 _MONO 那种类型的 pixel format。
=====
FT_Load_Char 的几个常用参数:
FT_LOAD_RENDER | FT_LOAD_NO_BITMAP | FT_LOAD_FORCE_AUTOHINT
上面说到矢量字体在缩放时会比较难看,可以通过 AUTOHINT 来提高些质量,同时 FT_LOAD_NO_BITMAP 强制不使用点阵字符。
用 wqy-正黑 12pt,效果还行。
FT_LOAD_RENDER | FT_LOAD_MONOCHROME
MONO 是强制输出点阵格式的 bitmap,无论是否此字号有真实对应的点阵字符。没有的话,FreeType2 先通过缩放,然后默认帮你转。
再说下 FT_LOAD_RENDER,指在默认加载 glyph 之后,立即输出 slot->bitmap 的内容,不用之,你不能在 FT_Load_Char 之后,立即使用 slot->bitmap。
=====
下面是 12pt 字绘制效果展示:
宋体(sumsun) fixed size
正黑(wqy-zenhei) fixed size
宋体(sumsun) no fixed size(矢量图缩放)
正黑(wyq-zenhei) no fixed size(矢量图缩放)
上面的字体都向上对齐了,严重不满足我们的显示要求嘛 ... Em~ 请听下回分解。:-)
ps. iconv 可以用来转换各种编码。