数码相框_在PC机上测试freetype(4)

数码相框_在PC机上测试freetype(4)

如何来使用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_LIBRARY library;                         //库的句柄

FT_Face face;                        /* face对象的句柄 */


error = FT_Init_FreeType ( &library );   
if ( error )
{... ...}

... ...

error = FT_New_Face( library,
"/usr/share/fonts/truetype/arial.ttf",    //字形文件
0,
&face );

4)设置字体大小(参考freetype-2.4.10/docs/reference/ft2-base_interface.html):

方法1:

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表示与另一个尺寸值相等。 

得出:

字符物理大小为: 50*64* (1/64) * (1/72)英寸

字符的像素为: 50*64* (1/64) * (1/72)*100

方法2:

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;                                         
  pen.y = ( target_height - 200 ) * 64;        // target_height: LCD总高度


//设置 矩形参数
  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 );

6)加载字形图像

a.获取编码的索引

通过FT_Get_Char_Inde()函数将字符编码转换为一个字形(glyph)索引   (Freetype默认是utf-16编码类型)

例如:

glyph_index = FT_Get_Char_Index( face, charcode ); 

若glyph_index为NULL,表示没找到字形(glyph)索引

如果使用其它字符编码,则通过FT_Select_Charmap()来获取,例如获取big5编码:

error = FT_Select_Charmap(
face,                /* 目标face对象 */
FT_ENCODING_BIG5 ); /* big5编码 */

//FT_ENCODING_BIG5枚举定义在FT_FREETYPE_H中
//FT_ENCODING_GB2312 :GB2312编码
//该函数头文件位于:FT_FREETYPE_H (freetype/freetype.h).

b.通过索引,从face中加载字形

获得字形索引后,接下来便根据字形索引,来将字形图像存储到字形槽(glyph slot)中.

字形槽:每次只能存储一个字形图像,每个face对象都有一个字形槽,位于face->glyph

通过FT_Load_Glyph()来加载一个字形图像到字形槽:

error = FT_Load_Glyph(

face, /* face对象的句柄 */

glyph_index, /* 字形索引 */

load_flags ); /* 装载标志,一般填FT_LOAD_DEFAULT*/

并更新face->glyph下的其它成员,比如:

FT_Int            bitmap_left;            //该字形图像的最左边的X值
FT_Int            bitmap_top;            //该字形图像的最上边的Y值

c.转为位图

通过FT_Render_Glyph()函数,将字形槽的字形图像转为位图,并存到 face->glyph->bitmap->buffer[]里

error = FT_Render_Glyph( face->glyph, /* 字形槽 */

render_mode ); /* 渲染模式 */

render_mode标志可以设为以下几种:

FT_RENDER_MODE_NORMAL:表示生成位图每个像素是RGB888的

FT_RENDER_MODE_MONO :表示生成位图每个像素是1位的(黑白图)

并更新face->glyph->bitmap下的其它成员,比如:

int             rows;         //该位图总高度,有多少行
int             width;        //该位图总宽度,有多少列像素点
int             pitch:        //指一行的数据跨度(字节数),比如对于24位(3字节)的24*30汉字,则pitch=24*3

char            pixel_mode    //像素模式,1 指单色的,8 表示反走样灰度值

unsigned char*  buffer        //glyph 的点阵位图内存绶冲区

d.也可以直接使用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()函数 

该函数默认生成的位图是默认生成的FT_RENDER_MODE_NORMAL类型,RGB888的

若想生成FT_RENDER_MODE_MONO(黑白图)类型,操作如下:

error = FT_Load_Char( face, charcode, FT_LOAD_RENDER | FT_LOAD_MONOCHROME );

生成出来的位图像素,每8个像素点便表示 face->glyph->bitmap->buffer[]里的一个字节.

参考example1.c例程

example1.c位于freetype-doc-2.4.10.tar.bz2\freetype-2.4.10\docs\tutorial下

在PC虚拟机里编译例程:example1.c

安装freetype到/usr/local/里(拿给PC用)

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/里,所以需要加sudo

由于example1.c的打印范围是640*480,而我们secureCRT没有那么大,所以修改example1.c.

将:

#define WIDTH   640
#define HEIGHT  480

改为:

#define WIDTH   80
#define HEIGHT  80

然后将119行处的文字显示坐标:

  pen.x = 300 * 64;
  pen.y = ( target_height - 200 ) * 64;

改为:

  pen.x = 0 * 64;                                //在坐标(0,40)处显示
  pen.y = ( target_height - 40 ) * 64;

编译运行

gcc -o example1 example1.c

编译出错:

通过ls,发现又有这个文件:

所以通过-I,直接指定头文件目录:

gcc -o example1 example1.c  -I /usr/local/include/freetype2/

编译再次出错:

发现这些出错的都是函数,其中FT开头的是freetype库的函数,cos等都是数学库的函数,

freetype库的文件名是 libfreetype.so

数学库的文件名是libm.so

所以编译时,加上-l,指定库文件:

gcc -o example1 example1.c  -I /usr/local/include/freetype2/   -lfreetype  -lm

运行example1

将C:\Windows\Fonts下的simsun.ttc(宋体)字体文件拷到虚拟机里,输入./example1   simsun.ttc  agf,发现是斜的:

这是因为example1.c里通过FT_Set_Transform()设置了字体旋转

继续修改example1.c

关闭字体旋转,将

FT_Set_Transform( face, &matrix, &pen );

改为

FT_Set_Transform( face, 0, &pen );

修改字体大小,将

error = FT_Set_Char_Size( face, 50 * 64, 0, 100, 0 );

改为:

error = FT_Set_Pixel_Sizes( face, 24, 0 );             //24*24像素

编译运行:

显示汉字

如果用char存储汉字英文等,则还需要判断数据类型,而wchar_t刚好可以放一个unicode字符。

注意:wchar_t在windows占2byte,在linux4bytes.

宽字符:wchar_t

头文件: #include<wchar.h>

通过wcslen()判断wchar_t数组大小

修改example1.c

...
#include<wchar.h>    //添加此行

...
int main( int argc,char**  argv )
{
  ... ...
  wchar_t  *chinese_str=L"韦东山g";    //添加此行

  ... ...
for ( n = 0; n <wcslen(chinese_str); n++ )  //修改此行
{
FT_Set_Transform( face, 0, &pen );     //字体转换

 

    /* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );    //修改此行
... ...

} 
  return 0;
}

通过另存为文件,来看看文件本身是什么编码格式

如下图所示,看到是ANSI编码, 对于中文PC,ANSI编码对应的是GBK编码:

linux默认是utf-8编码,所以编译时,需要指定字符集:

gcc -o example1 example1.c  -I /usr/local/include/freetype2/   -lfreetype  -lm -finput-charset=GBK  -fexec-charset=utf-8
// -finput-charset:告诉编译器,文件里的字符是GBK格式
//-fexec-charset:告诉编译器,需要先将里面的内容转换为utf-8格式后,再来编译

运行代码:

添加坐标打印信息:

发现,我们打印坐标是在(40,0),为什么文字坐标还会超过原点?,参考以下图所示:

advance: 位于face->glyph-> advance,用来存放每个文字之间的间隔信息,每当加载一个新的图像时,系统便会更新该数据.

获取位图文字的信息

当我们每次将新的字形图像(face->glyph)转为位图后,而存放的前一个字形图像就会被删除.

当有时候,有可能需要提取字形图像的坐标,该怎么做?

1)首先添加头文件:

#include FT_GLYPH_H

2)通过FT_Get_Glyph()将一个字形图像(face->glyph)存到FT_Glyph类型的变量里,例如:

FT_Glyph  glyph;    /* a handle to the glyph image */
...

  error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NORMAL );
//通过字符编码,获取字形图像存到face->glyph里,并转为位图存到face->glyph->bitmap->buffer[]里

  if ( error ) { ... }

  error = FT_Get_Glyph( face->glyph, &glyph );         //将字形图像(face->glyph)存到glyph里
  if ( error ) { ... }

3) 通过FT_Glyph_Get_CBox()获取文字的xMin, xMax, yMin, yMax坐标信息

参考: /freetype-2.4.10/docs/reference/ft2-index.html

FT_Glyph_Get_CBox( FT_Glyph  glyph,                 //该值通过FT_Get_Glyph()来获取
                     FT_UInt   bbox_mode,        //模式,填入FT_GLYPH_BBOX_TRUNCATE即可
                     FT_BBox  *acbox );        //用来存放获取到的xMin, xMax, yMin, yMax信息

其中FT_GLYPH_BBOX_TRUNCATE表示:获取的坐标信息是像素坐标,而不是点坐标

修改example1.c,使它能打印每个汉字的坐标信息:

#include FT_GLYPH_H      //添加此行
... ...

int main( int     argc, char**  argv )
{
  FT_Glyph  glyph;
  FT_BBox   acbox;
... ...

for ( n = 0; n < wcslen(chinese_str); n++ )
{ 
 ... ...

error = FT_Load_Char( face,chinese_str[n], FT_LOAD_RENDER );
  if ( error )
      continue;                 /* ignore errors */

error = FT_Get_Glyph( face->glyph, &glyph );                   //添加此行
FT_Glyph_Get_CBox(  glyph,FT_GLYPH_BBOX_TRUNCATE,&acbox );     //添加此行
printf("0x%x:xMin=%ld,xMax=%ld,yMin=%ld,yMax=%ld\n",chinese_str[n],acbox.xMin,acbox.xMax,acbox.yMin,acbox.yMax);    //添加此行

... ...

编译运行:

表示韦字(97e6)的笛卡尔坐标 :  X坐标在0~23,y坐标在37~60,是个24*24字体.

由于笛卡尔坐标的原点坐标位于左下方.

所以对应韦字(97e6)的LCD坐标: X坐标在0~23 ,y坐标为20~43

猜你喜欢

转载自blog.csdn.net/xiaodingqq/article/details/84930589