1.点阵字库的缺点
点阵字库确定好了像素,如8x8,8x16等,字体定死,不能缩放
2.矢量字体原理
矢量字体由 若干条曲线的关键点 和 数学曲线(贝塞尔曲线)连接 组成。
将汉字的笔划边缘用直线段描述成封闭的曲线,并将线段各端点的坐标经压缩存储,如下图所示:
由于每个汉字的笔划不一样,从而每个汉字数据长度也不同,所以只能采用索引的方法。因而每种矢量字库都是由两部分组成,一部分是汉字的索引信息,一部分是汉字的字形(glyph)数据.
当显示文字时,便提取出各端点,并通过贝塞尔曲线来连接各个坐标,最后填充封闭空间.
3.freetype
freetype库是一个开源的字体引擎,支持多种字符集编码(utf-8等).
freetype库下载: https://sourceforge.net/projects/freetype/files/freetype2/2.4.10/
freetyoe英文参考文档下载:https://sourceforge.net/projects/freetype/files/freetype-docs/2.4.10/
FreeType 字体引擎分析与指南
http://wenku.baidu.com/view/2d24be10cc7931b765ce155b.html
https://wenku.baidu.com/view/e7149f6748d7c1c708a14574.html
1、美工描字
2、程序员提取关键点和其相对位置,制作成字库文件(simsun.ttc–字库文件)
3、其中每一个字/字符都有一个glygh(n.字形,字的轮廓)
4、字体文件中有charmaps,在字体文件的头,记录可以支持哪几种编码方式(GBK/UNICODE/BIG5),这个字体文件可能不支持GBK,BIG5,但一定会支持UNICODE码。
4.显示一个文字的过程
1.给定一个文字’A’ (0x41),“中”(GBK、unicode、BIG5),可以确定它的编码值
2.根据"编码值"从字体文件中找到“glyph”,这里面有关键点和它的相对位置
3.设置字体大小
4.用某些函数把glyph中的点缩放为设置的大小(第三步的)
5.转换为位图(点阵图像) 并 在LCD上显示
如何使用freetype
1)包含头文件:
#include <ft2build.h>
#include FT_FREETYPE_H
2)初始化库:
使用FT_Init_FreeType()函数初始化一个FT_Library类型的变量,例如:
FT_LIBRARY library; //库的句柄
error = FT_Init_FreeType( &library );
if ( error )
{
//初始化失败
}
... ...
3)加载face对象:
通过FT_NEW_Face()打开一个字体文件,然后提取该文件的一个FT_Face类型的face变量,
FT_Face face; /* face对象的句柄 */
error = FT_New_Face( library,
"/usr/share/fonts/truetype/arial.ttf", //字形文件
0,
&face );
4)设置字体大小:
法一:
FT_Set_Char_Size( FT_Face face,
FT_F26Dot6 char_width, //字符宽度,单位为1/64点
FT_F26Dot6 char_height, //字符高度,单位为1/64点
FT_UInt horz_resolution, //水平分辨率
FT_UInt vert_resolution ); //垂直分辨率
字符宽度和高度以1/64点为单位表示。点是物理上的距离,一个点代表1/72英寸(2.54cm)
分辨率以dpi(dots per inch)为单位表示,表示一个英寸有多少个像素
error = FT_Set_Char_Size( face, 50 * 64, 0,100, 0 ); //0表示与另一个尺寸值相等。
得出:
字符水平方向物理大小为: 50x64* (1/64) * (1/72)英寸
字符水平方向的像素个数为: 50x64* (1/64) * (1/72)*100
这个方法太麻烦,对于LCD来说,只考虑字符的像素点,所以用法二。
法二: 更改字体大小推荐用这个
FT_Set_Pixel_Sizes( FT_Face face,
FT_UInt pixel_width, //像素宽度
FT_UInt pixel_height ); //像素高低
error = FT_Set_Pixel_Sizes( face, 0,16); //把字符像素设置为16*16像素, 0表示与另一个尺寸值相等。
5)设置字体显示位置,以及旋转度数(不设置的话表示原点位于0,0):
error = FT_Set_Transform(face, /* 目标face对象 */
&matrix, /* 指向2x2矩阵的指针,写0表示不旋转,使用正矩形 */
&delta ); /*字体坐标位置(用的笛卡尔坐标),以1/64像素为单位表示,写0表示原点是(0,0) */
由于我们LCD的坐标原点是位于左上方
笛卡尔坐标:表示坐标原点位于左下方(与LCD的y轴相反)
所以转换之前填写坐标时,需要转换一下y轴值(总高度 - y)
转换成功后还需要转换回来( 总高度 - y)
比如,旋转25,并在(300,200)处显示:
FT_Vector pen; /* */
FT_Matrix matrix; /* transformation matrix */
angle = ( 25.0 / 360 ) * 3.14159 * 2; /* use 25 degrees */
//这个是设置显示的位置,即在屏幕什么地方显示
pen.x = 300 * 64; //这里乘64是因为上面,单位是1/64
pen.y = ( target_height - 200 ) * 64; // target_height: LCD总高度
//设置 矩形参数 如果需要旋转的话,就需要这4行
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
FT_Set_Transform( face, &matrix, &pen ); //这个是设置的函数
//如果想字体不旋转,第二项matrix设置成0就行
6)加载字形图像
直接使用FT_Load_Char()来代替FT_Get_Char_Index()、FT_Get_Load_Glyph()和FT_Render_Glyph().
error = FT_Load_Char( face, charcode, FT_LOAD_RENDER );
其中FT_LOAD_RENDER:表示直接将图像转为位图,所以不需要使用FT_Render_Glyph()函数
该函数默认生成的位图是默认生成的
到此,已经生成了位图(点阵文件),可以拿去显示了
!!!!!!分析一下example1.c文件,代码在附录
在PC上跑example1.c
1.安装freetype 到 /usr/local 里
tar -xjf freetype-2.4.10.tar.bz2
mv freetype-2.4.10 freetype-2.4.10_pc
cd freetype-2.4.10_pc/
./configure //配置
make //编译
sudo make install //执行这个就会把库安装到根目录/usr/local/下
2.修改example
由于example1.c的打印范围是640*480,而我们终端没有那么大,所以修改example1.c.
将:
#define WIDTH 640
#define HEIGHT 480
改为:
#define WIDTH 80
#define HEIGHT 80
再将显示的坐标:
pen.x = 300 * 64;
pen.y = ( target_height - 200 ) * 64;
改为
pen.x = 0 * 64; //在坐标(0,40)处显示
pen.y = ( target_height - 40 ) * 64;
3.编译
gcc -o example1 example1.c
编译出错:
提示库中没有这个文件
而在目录下发现有这个文件
所以在编译的时候指定文件目录,用 -I
gcc -o example1 example1.c -I /usr/local/include/freetype2/
编译再次出错:
很多函数未定义
需要加上我们刚刚编译好的库文件
freetype库的文件名是 libfreetype. so
数学库的文件名是libm. so
gcc -o example1 example1.c -I /usr/local/include/freetype2/ -lfreetype -lm
4.运行
屏幕分辨率设置成了 80 * 80
字符分辨率设置成了 24 * 24
显示的位置在(0,40)处 (此处不为笛卡尔坐标)
./example1 simsun.ttc agf
附录:example1.c
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
//这里类似于设置lcd的分辨率
#define WIDTH 80
#define HEIGHT 80
//这个就相当于lcd的framebuffer
unsigned char image[HEIGHT][WIDTH];
void draw_bitmap( FT_Bitmap* bitmap,FT_Int x,FT_Int y)
{
FT_Int i, j, p, q; //i j表示的是物理坐标
FT_Int x_max = x + bitmap->width;//bitmap->width表示的是这个字的宽度
FT_Int y_max = y + bitmap->rows; //同理bitmap->row 这个字的高度
for ( i = x, p = 0; i < x_max; i++, p++ )
{
for ( j = y, q = 0; j < y_max; j++, q++ )
{
if ( i < 0 || j < 0 || //如果目前超出了整个屏的物理地址(这里物理地址就设置成前面的两个define),那么就跳过
i >= WIDTH || j >= HEIGHT )
continue;
image[j][i] |= bitmap->buffer[q * bitmap->width + p];//这个就是这一点的数据 bitmap->buffer[q * bitmap->width + p]
} //放到显存对应的位置上
}
}
void show_image( void )
{
int i, j;
for ( i = 0; i < HEIGHT; i++ )
{
for ( j = 0; j < WIDTH; j++ )
putchar( image[i][j] == 0 ? ' '
: image[i][j] < 128 ? '+'
: '*' );
putchar( '\n' );
}
}
int main( int argc,char** argv )
{
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_Matrix matrix; /* transformation matrix */
FT_Vector pen; /* untransformed origin */
FT_Error error;
char* filename;
char* text;
double angle;
int target_height;
int n, num_chars;
if ( argc != 3 )
{
fprintf ( stderr, "usage: %s font sample-text\n", argv[0] );
exit( 1 );
}
filename = argv[1];
text = argv[2];
num_chars = strlen( text ); //看需要显示几个符号
angle = ( 0 / 360 ) * 3.14159 * 2; //这里不设置字体旋转
target_height = HEIGHT;
/***************第一步,初始化库,得到句柄*********************/
error = FT_Init_FreeType( &library );
/***************第二步,加载face对象,也就是打开字库文件*********************/
error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
/***************第三步,设置字体的大小*********************/
// error = FT_Set_Char_Size( face, 50 * 64, 0,100, 0 ); //前面两个是一个字符的物理大小,后面两个是一个单位物理大小内有几个像素,这样就可以算出一个符号的实际物理像素
//只考虑字符像素,不用考虑别的
FT_Set_Pixel_Sizes(face,24,24);
slot = face->glyph; //glyph存着那些符号的位置什么的
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L ); //若设置了字体旋转,就需要这几行,固定的,只用把前面的angle按照那样算一下就行
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
/*在坐标什么地方处显示*/
pen.x = 0 * 64;
pen.y = ( target_height - 40 ) * 64;
for ( n = 0; n < num_chars; n++ ) //一个符号循环一次
{
//设置字用不用旋转和开始显示的位置
FT_Set_Transform( face, &matrix, &pen );
//转换为点阵
error = FT_Load_Char( face, text[n], FT_LOAD_RENDER );
if ( error )
continue;
/* now, draw to our target surface (convert position) */
draw_bitmap( &slot->bitmap, //位图存在的地方 &slot->bitmap = &face->glyph->bitmap->buffer
slot->bitmap_left, //x坐标
target_height - slot->bitmap_top ); //y坐标
/* increment pen position */
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
show_image();
FT_Done_Face ( face );
FT_Done_FreeType( library );
return 0;
}
/* EOF */