数码相框(四、使用freetype库实现矢量字体显示)

注:本人已购买韦东山第三期项目视频,内容来源《数码相框项目视频》、数码相框-通过freetype库实现矢量显示,只用于学习记录,如有侵权,请联系删除。

    在数码相框(三、LCD显示文字)中使用字体的点阵数据显示文字,这种LCD显示文字的方法比较简单,但它有一个缺点,一旦选定了字库,字体的大小就确定了,无法更改。矢量字体可以弥补点阵字体无法更改字体大小的缺点,而且矢量字体无论放大、缩小,都可以清晰显示。

1. 矢量字体原理

    在矢量字体文件中存储的是字符若干闭合曲线的关键点,把这些关键点使用数学曲线(贝塞尔曲线)连接在一起,并填充闭合曲线的闭合空间,就形成了一个矢量字符。例如,字母“B”,如下图所示。红色点为字体的关键点,使用数学曲线把关键点连接在一起,形成闭合的曲线(即字体的轮廓线),然后填充闭合空间(即灰色的填充区域)。
在这里插入图片描述
由于每个字符的笔划不一样,从而每个字符数据长度也不同,所以只能采用索引的方法。因而每种矢量字库都是由两部分组成,一部分是汉字的索引信息,一部分是汉字的字形(glyph)数据(即字符的关键点)

2. Freetype库

FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,用于处理矢量字体文件的。
freetype-2.4.10库下载:https://sourceforge.net/projects/freetype/files/freetype2/2.4.10/
freetype-2.4.10英文参考文档下载:https://sourceforge.net/projects/freetype/files/freetype-docs/2.4.10/
FreeType 中文使用参考:
https://wenku.baidu.com/view/2d24be10cc7931b765ce155b.html
https://wenku.baidu.com/view/e7149f6748d7c1c708a14574.html

2.1 freetype-2.4.10的使用

(1) 想象一个文字的显示过程:
① 给定一个文字,例如,‘A’, 0x41, “中”, GBK、UNICODE,可以确定它的编码值;
② 根据上面的编码值,从字体库中找到“glyph”,glyph 中含有那些关键点;
③ 设置字体大小;
④ 用某些函数把glyph里的点缩放成第③步中指定的字体大小
⑤ 把 glyph 转换为位图点阵
⑥ 把字体的位图点阵在LCD显示出来。

(2) 代码的过程:
① 包含头文件:

#include <ft2build.h>
#include FT_FREETYPE_H

② 初始化库:(使用FT_Init_FreeType()函数初始化一个FT_Library类型的变量)

FT_LIBRARY library;                         /*库的句柄*/

error = FT_Init_FreeType( &library );   
if ( error )
{
//初始化失败
}
... ...

③ 装载一个字体 face:(应用程序通过FT_NEW_Face()函数打开一个字体文件,然后提取该文件的一个FT_Face类型的face变量(一个 face 对象描述了一个特定的字样和风格,例如,’ Times New Roman Regular’和’ Times New Roman Italic’对应两个不同的 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 );

④ 设置字体大小: 设置字体大小有两种方法:
方法一:

FT_Set_Char_Size( FT_Face     face,
                  FT_F26Dot6  char_width,  /*字符宽度,单位为1/64点, 字符宽度为0意味着与字符高度相同*/
                  FT_F26Dot6  char_height, /*字符高度,单位为1/64点,字符高度为0意味着与字符宽度相同*/
                  FT_UInt     horz_resolution,   /*水平分辨率,为0意味着与垂直分辨率相同*/
                  FT_UInt     vert_resolution ); /*垂直分辨率,为0意味着与水平分辨率相同*/

注:
a. 字符宽度和高度以 1/64 点为单位表示;
b. 点是物理上的距离,一个点代表1/72英寸(1英寸 = 2.54cm);
c. 设备的水平和垂直分辨率以每英寸点数(dpi)为单位表示,表示一个英寸有多少个像素;

例如:

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。

方法二:

FT_Set_Pixel_Sizes(FT_Face  face,
                   FT_UInt  pixel_width,     //像素宽度
                   FT_UInt  pixel_height );  //像素高低

例如:

error = FT_Set_Pixel_Sizes( face, 24, 0);      //把字符像素设置为24*24像素, 0表示与另一个尺寸值相等。

⑤ 字体的变换: 使用FT_Set_Transform()设置字体的位置、移动、旋转的角度等

error = FT_Set_Transform(face,     /*目标face对象 */
                         &matrix,  /*指向2x2矩阵的指针,写0表示不旋转,使用正矩形*/
                         &delta ); /*字体坐标位置(用的笛卡尔坐标),以1/64像素为单位表示,写0表示原点是(0,0)*/

如下图所示,在LCD的坐标系中,原点在屏幕的左上角。对于笛卡尔坐标系,原点在左下角。freetype使用笛卡尔坐标系,在显示时需要转换为LCD坐标系。从下图可知,X方向坐标值是一样的。在Y方向坐标值需要换算,假设LCD的高度是V。在LCD坐标系中坐标是(x, y),那么它在笛卡尔坐标系中的坐标值为(x, V-y)。反过来也是一样的,在笛卡尔坐标系中坐标是(x, y),那么它在LCD坐标系中坐标值为(x, V-y)。
在这里插入图片描述
例如:设置字体旋转25度,并在(300, 200)显示,在example1.c有如下代码:

FT_Vector     pen;                    /*   */
FT_Matrix     matrix;                 /* transformation matrix */
double        angle;

angle         = ( 25.0 / 360 ) * 3.14159 * 2;      /* use 25 degrees     */

/* set up matrix */
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 );

/* the pen position in 26.6 cartesian space coordinates; */
/* start at (300,200) relative to the upper left corner  */
pen.x = 300 * 64;
pen.y = ( target_height - 200 ) * 64; /*其中target_height为LCD的总高度*/

FT_Set_Transform( face, &matrix, &pen );

⑥ 根据字符的编码值,加载 glyph:
a. 根据编码值,找到字体文件的索引:

glyph_index = FT_Get_Char_Index( face, charcode );

b. 通过索引,把字形图像存 face->glyph成员中:(通过调用 FT_Load_Glyph()函数来装载一个字形图像到字形槽(glyph slot)中,如下:)

error = FT_Load_Glyph(face, /* face 对象的句柄 */
                      glyph_index, /* 字形索引 */
                      load_flags ); /* 装载标志,用来指示某些特殊操作的。其默认值是 FT_LOAD_DEFAULT 即 0。*/

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

c. 转换为位图:得到字形槽后,可以通过 FT_Render_Glyph()函数把它直接转换为一个位图,并存到 face->glyph->bitmap->buffer[] 里:

error = FT_Render_Glyph(face->glyph,  /* 字形槽 */
                        render_mode); /* 渲染模式,render_mode 参数是一个位标志集合,用来指示如何渲染字形图像。*/

render_mode有两种渲染模式:
FT_RENDER_MODE_NORMAL: 渲染出一个高质量的抗锯齿(256 级灰度)位图;
FT_RENDER_MODE_MONO: 表示生成位图每个像素是1位的(黑白图)。

以上a、b、c三步等价于函数:

FT_Load_Char(face,charcode,FT_LOAD_REND); /*FT_LOAD_RENDER表示直接将图像转为位图, 并保存到face->glyph->bitmap->buffer[]*/
2.2 在PC上测试Freetype

(1) 解压、配置、编译、安装 freetype:

tar -xjf freetype-2.4.10.tar.bz2    /*解压*/
cd freetype-2.4.10/  
./configure                         /*配置*/
make                                /*编译*/
sudo make install                   /*接将库安装到根目录/usr/local/ */

(2) 编译example1.c:(example1.c在freetype-doc-2.4.10/freetype-2.4.10/docs/tutorial目录下)

 gcc -o example1 example1.c 

编译出现如下错误:
在这里插入图片描述
上面的错误提示说不存在freetype/config/ftheader.h这个文件,但在/usr/local/include/freetype2/freetype/config/是存在ftheader.h这个文件的,如下图所示:
在这里插入图片描述
所以需要通过 -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

(3) 运行example1.c:
C:\Windows\Fonts下的simsun.ttc(宋体)字体文件拷问到虚拟机example1所在的目录下,运行:

./example1 simsun.ttc abc

运行的结果如下:
在这里插入图片描述
example1.c的打印范围是640*480,从上图打印的结果可知,这个打印范围显然过大,只能看到打印字体的一部分,所以我们需要把example1.c的打印范围调小,调为80*80。因此需要把example1.c中的如下代码:

#define WIDTH   640
#define HEIGHT  480

改为:

#define WIDTH   80
#define HEIGHT  80

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

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

改为:

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

修改后,重新编译,运行的结果如下图所示:
在这里插入图片描述
从打印的结果可知,打印的字符abc是斜体。通过检查example1.c代码发现,通过FT_Set_Transform()函数设置了字体旋转,并在95行设置了旋转的角度为25度,因此需要把旋转角度设置代码:

angle = ( 25.0 / 360 ) * 3.14159 * 2;      /* use 25 degrees     */

修改为0度:

angle = ( 0 / 360 ) * 3.14159 * 2;      /* use 0 degrees     */

修改后,重新编译,运行的结果如下图所示:
在这里插入图片描述
从上图我们发现,显示不全,下面我们把字体大小改小一点,把example1.c的105行设置字体大小的代码:

  /* use 50pt at 100dpi */
  error = FT_Set_Char_Size( face, 50 * 64, 0,
                            100, 0 );                /* set character size */

改为 24*24的字体大小:

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

修改后,重新编译,运行:

./example1 simsun.ttc abc

打印结果如下图所示:最终显示正常。
在这里插入图片描述
(4) 修改example1.c代码显示汉字:
① 包含宽字符头文件:#include <wchar.h>
② 通过wcslen()函数判断wchar_t数组大小;
注:wchar_twindows2byte,在linux4bytes

为了显示汉字,对example1.c做了如下修改:

...
#include <wchar.h>    /*1.添加宽字符头文件*/
...

/*main函数修改为如下*/
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;
  double        angle;
  int           target_height;
  int           n;

  wchar_t  *chinese_str = L"韦gif";


  filename      = argv[1];                           /* first argument     */
  angle         = ( 0 / 360 ) * 3.14159 * 2;      /* use 25 degrees     */
  target_height = HEIGHT;

  error = FT_Init_FreeType( &library );              /* initialize library */
  /* error handling omitted */

  error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */

  /*设置字体大小*/
  error = FT_Set_Pixel_Sizes( face, 24, 0 );             /* 24*24像素 */
  /* error handling omitted */

  slot = face->glyph;

  /* set up matrix */
  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 );

  /* the pen position in 26.6 cartesian space coordinates; */
  /* start at (300,200) relative to the upper left corner  */
  pen.x = 0 * 64;
  pen.y = ( target_height - 40 ) * 64;

  for ( n = 0; n < wcslen(chinese_str); n++ )
  {
    /* set transformation */
    FT_Set_Transform( face, &matrix, &pen );

    /* load glyph image into the slot (erase previous one) */
    error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );
    if ( error )
      continue;                 /* ignore errors */

    /* now, draw to our target surface (convert position) */
    draw_bitmap( &slot->bitmap,
                 slot->bitmap_left,
                 target_height - slot->bitmap_top );

    /* 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;
}

在Ubuntu虚拟机使用vim编辑器修改example1.c(vim 编辑器默认为UTF-8编码格式),编译程序:

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

若example1.c文件格式为ANSI编码(ANSI编码),因为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格式后,再来编译

运行:

./example1 simsun.ttc

运行打印结果如下:
在这里插入图片描述
在example1.c中的 show image() 函数添加打印坐标信息,如下图红色框所示:
在这里插入图片描述
重新编译,运行打印结果如下图所示:
在这里插入图片描述
从上图可知,文字的显示超出了原点坐标(40,0),这是为什么呢?如下图所示:
在这里插入图片描述
在显示一行文字时,这些文字会基于同一个基线来绘制位图:baseline。在baseline上,每一个字符都有它的原点(origin)例如上图中baseline左边的黑色圆点就是字母“g”的原点。当前origin加上advance就可以得到下一个字符的origin,比如上图中baseline右边的黑色圆点在显示一行中多个文件字时,后一个文字的原点依赖于前一个文字的原点及advance

字符的位图是有可能越过baseline的,比如上图中字母“g”在baseline下方还有图像。上图中红色方框内就是字母“g”所点据的位图,它的四个角落不一定与原点重合。 我们通过FT_Glyph_Get_CBox()函数可以获取上图中字体的xMin、xMax、yMin、yMax参数,这些参数会保存在一个FT_BBox结构体中,该结构体的代码如下图所示:
在这里插入图片描述
(5) 获取位图文字的信息:
① 首先添加头文件:

#include FT_GLYPH_H

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

FT_Glyph  glyph;    /* a handle to the glyph image */
...
/*通过字符编码,获取字形图像存到face->glyph里,并转为位图存到face->glyph->bitmap->buffer[]里*/
error = FT_Load_Char(face,charcode,FT_LOAD_REND);
if ( error ) { ... }

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

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

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;   /*添加*/
  ...
  error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );
  if ( error )
    continue;                 /* ignore errors */
  error = FT_Get_Glyph(face->glyph, &glyph);      /*添加*/    //将字形图像(face->glyph)存到glyph里
  if(error )  /*添加*/
    continue;  /*添加*/
  FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &acbox);    /*添加*/
  printf("0x%04x:xMin=%ld,xMax=%ld,yMin=%ld,yMax=%ld\n",chinese_str[n],acbox.xMin,acbox.xMax,acbox.yMin,acbox.yMax);  /*添加*/
  ...
 }

重新编译,运行打印的结果如下:
在这里插入图片描述
例如:第一行表示“韦”字的笛卡尔坐标: X坐标在0~23,y坐标在37~60,是个24*24字体。前面讲过,笛卡尔坐标原点位于左下方,LCD坐标原点位于左上方,所以,“韦”字的LCD坐标为: X坐标在0~23,y坐标在20~43(LCD的大小为:80*80)。

3. 在JZ2440开发板LCD显示矢量字体

3.1构建交叉编译环境(arm-linux-gcc 4.4.3)

(1) 交叉编译 freetype:

tar xjf freetype-2.4.10.tar.bz2
mkdir tmp
cd freetype-2.4.10/  
./configure --host=arm-linux 或 ./configure --host=arm-none-linux-gnueabi (有时候--host=arm-linux时,编译出来的libfreetype.so是x86-64格式的(file libfreetype.so 可知它是个符号连接指向libfreetype.so.6.9.0,执行file libfreetype.so.6.9.0可知格式为x86-64),这可能是为系统的问题,建议配置时用第二个。)
make
make DESTDIR=$PWD/../tmp install   /*安装到tmp目录*/

(2) 编译出来的头文放入:/work/tools/arm-linux-gcc-4.4.3/lib/gcc/arm-none-linux-gnueabi/4.4.3/include目录

cp tmp/usr/local/include/* /work/tools/arm-linux-gcc-4.4.3/lib/gcc/arm-none-linux-gnueabi/4.4.3/include -rf 
cd /work/tools/arm-linux-gcc-4.4.3/lib/gcc/arm-none-linux-gnueabi/4.4.3/include
mv freetype2/freetype .  /*代码中用的是 freetype,不是 freetype2*/

(3) 编译出来的库文件放入:/work/tools/arm-linux-gcc-4.4.3/arm-none-linux-gnueabi/lib目录

cp tmp/usr/local/lib/* /work/tools/arm-linux-gcc-4.4.3/arm-none-linux-gnueabi/lib -d -rf

(4) 把tmp/usr/local/lib/目录下所以的so文件,复制到开发根文件系统的lib目录下,如下图所示:
在这里插入图片描述

3.2 在LCD上显示矢量字体

(1) 交叉编译example1.c

arm-linux-gcc -o example1 example1.c -lfreetype  -lm

若example1.c文件格式为ANSI编码(ANSI编码),因为linux默认是UTF-8编码,所以编译时,需要指定字符集:

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

把交叉编译出的可知文件拿到开发板运行,发现运行的结果是在终端显示,并非在开发板的LCD显示。

(2) 修改example1.c代码,在开发板LCD显示矢量字体: 修改后的代码如下:

/* example1.c                                                      */
/*                                                                 */
/* This small program shows how to print a rotated string with the */
/* FreeType 2 library.                                             */

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>
#include <linux/fb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

#define WIDTH   80
#define HEIGHT  80

/* origin is the upper left corner */
//unsigned char image[HEIGHT][WIDTH];

int fd_fb;
struct fb_var_screeninfo var;	/* Current var */
struct fb_fix_screeninfo fix;	/* Current fix */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;

/*
 * @brief         在LCD指定位置显示指定的颜色
 *
 * @param[in]     x   预显示位置的横坐标
 *
 * @param[in]     y   预显示位置的纵坐标
 *
 * @param[in]     color 预显示的颜色
 *
 * @return        无
 *
 * @note          颜色color 的格式是 0x00RRGGBB
 */
void lcd_put_pixel(int x,int y,unsigned int color)
{
    unsigned char  *pen_8 = fbmem + y * line_width + x * pixel_width;
    unsigned short *pen_16;
    unsigned int   *pen_32;

    unsigned int red, green, blue;

    pen_16 = (unsigned short *)pen_8;
    pen_32 = (unsigned int *)pen_8;

    switch(var.bits_per_pixel)
    {
        case 8:  *pen_8 = color;break; /*对于8BPP:color 为调色板的索引值,其颜色取决于调色板的数值*/
        case 16:
        {
            red   = (color >> 16) & 0xff;
            green = (color >> 8)  & 0xff;
            blue  = (color >> 0)  & 0xff;

            color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); /*格式:RGB565*/

            *pen_16 = color;

            break;
        }
        case 32: *pen_32 = color;break;
        default: printf("can't surport %dbpp",var.bits_per_pixel);break;
    }
}

/* Replace this function with something useful. */
void
draw_bitmap( FT_Bitmap*  bitmap,
             FT_Int      x,
             FT_Int      y)
{
  FT_Int  i, j, p, q;
  FT_Int  x_max = x + bitmap->width;
  FT_Int  y_max = y + bitmap->rows;


  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       ||
           i >= var.xres || j >= var.yres )
        continue;

     // image[j][i] |= bitmap->buffer[q * bitmap->width + p];
	  lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);	
    }
  }
}

int main( int argc, char** argv )
{
  FT_Library    library;
  FT_Face       face;
  FT_Glyph      glyph;
  FT_BBox       acbox;

  FT_GlyphSlot  slot;
  FT_Matrix     matrix;                 /* transformation matrix */
  FT_Vector     pen;                    /* untransformed origin  */
  FT_Error      error;

  char*         filename;
  double        angle;
  int           target_height;
  int           n;

  wchar_t  *chinese_str = L"韦gif";

  if( argc != 2)
  {
	 printf ("usage: %s  font_file \n", argv[0] );
	 return -1; 
  }

  fd_fb = open("/dev/fb0", O_RDWR);

  if(fd_fb < 0)
  {
	  printf("can't open /dev/fb0\n");
	  return -1;
  }

  if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
  {
	  printf("can't get var\n");
	  return -1;
  }

  if(ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))
  {
	  printf("can't get fix\n");
	  return -1;
  }

  line_width  = var.xres * var.bits_per_pixel / 8;
  pixel_width = var.bits_per_pixel / 8;
  screen_size = var.xres * var.yres * var.bits_per_pixel / 8;

  fbmem = (unsigned char *)mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
  if(fbmem == (unsigned char*)-1)
  {
	  printf("can't mmap\n");
	  return -1;
  }
  
  /*清屏*/
  memset(fbmem, 0, screen_size);

  filename      = argv[1];                           /* first argument     */
  angle         = ( 0 / 360 ) * 3.14159 * 2;      /* use 25 degrees     */
  target_height = HEIGHT;

  error = FT_Init_FreeType( &library );              /* initialize library */
  /* error handling omitted */

  error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */

  /*设置字体大小*/
  error = FT_Set_Pixel_Sizes( face, 24, 0 );             /* 24*24像素 */

  /* error handling omitted */

  slot = face->glyph;

  /* set up matrix */
  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 );

  /* the pen position in 26.6 cartesian space coordinates; */
  /* start at (300,200) relative to the upper left corner  */
  pen.x = 0 * 64;
  pen.y = ( target_height - 40 ) * 64;

  for ( n = 0; n < wcslen(chinese_str); n++ )
  {
    /* set transformation */
    FT_Set_Transform( face, &matrix, &pen );

    /* load glyph image into the slot (erase previous one) */
    error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );
    if ( error )
      continue;                 /* ignore errors */

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

    FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &acbox);
    printf("0x%04x:xMin=%ld,xMax=%ld,yMin=%ld,yMax=%ld\n",chinese_str[n],acbox.xMin,acbox.xMax,acbox.yMin,acbox.yMax);
    /* now, draw to our target surface (convert position) */
    draw_bitmap( &slot->bitmap,
                 slot->bitmap_left,
                 target_height - slot->bitmap_top );

    /* increment pen position */
    pen.x += slot->advance.x;
    pen.y += slot->advance.y;
  }

  FT_Done_Face    ( face );
  FT_Done_FreeType( library );

  return 0;
}
/* EOF */

重新编译,运行的结果如下图所示:
在这里插入图片描述

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
FreeType是一个开源的字体渲染,它提供了一套功能强大的API,用于加载、解析和渲染字体文件。使用FreeType,您可以在应用程序中实现高质量的字体渲染。 以下是使用FreeType加载和渲染字体的基本步骤: 1. 下载和安装FreeType:您可以从FreeType官方网站(https://www.freetype.org)下载文件,并按照文档进行安装。 2. 引入头文件和链接:在您的项目中引入FreeType的头文件和链接。具体的引入方式会根据您使用的编程语言和开发环境而有所不同。 3. 初始化FreeType:在使用FreeType之前,需要调用FT_Init_FreeType函数来初始化FreeType。 4. 加载字体文件:使用FT_New_Face函数加载字体文件。您需要提供字体文件的路径,并指定要加载的字体索引(如果字体文件包含多个字体)。 5. 设置字体大小:使用FT_Set_Pixel_Sizes函数或FT_Set_Char_Size函数设置字体的大小。 6. 渲染字符:使用FT_Load_Char函数加载要渲染的字符,并使用FT_Render_Glyph函数将字符渲染为位图。 7. 获取位图数据:通过FT_GlyphSlot结构体中的bitmap成员获取位图数据。 8. 绘制位图:将位图数据绘制到屏幕或纹理上,以实现字体渲染效果。 9. 释放资源:在使用FreeType后,需要调用相应的清理函数来释放资源,例如FT_Done_Face和FT_Done_FreeType。 请注意,以上仅为使用FreeType的基本步骤,具体的实现方式会根据您的需求和编程语言而有所不同。您可以参考FreeType的文档和示例代码,以及相关编程语言的FreeType绑定或封装使用指南,来更详细地了解和应用FreeType。 希望这些信息对您有所帮助!如果您有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Louis@L.M.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值