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

news/2024/11/8 15:16:12/

注:本人已购买韦东山第三期项目视频,内容来源《数码相框项目视频》、数码相框-通过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 */

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


http://www.ppmy.cn/news/588354.html

相关文章

数码相框(三、LCD显示文字)

注&#xff1a;本人已购买韦东山第三期项目视频&#xff0c;内容来源《数码相框项目视频》&#xff0c;只用于学习记录&#xff0c;如有侵权&#xff0c;请联系删除。 文字在LCD上的显示其实就是LCD上的一些点的显示与不显示&#xff0c;这些显示的点就像我们的笔画一样&#x…

特权的DIY数码相框总结

本文是对DIY数码相框一章的总结&#xff0c;重在对整个数据通路的理解。 具体的需求参见该书的相关章节。整个数据流是&#xff1a; sd卡控制模块&#xff0c;通过spi接口读sd卡中的数据&#xff0c;给wrfifo进行缓存&#xff0c;满了256byte后wrfifo通知sdram读取fifo中的数…

11、数码相框编写程序之MainPage显存管理与页面规划

文章目录 1、显存的分配和获取1.1、构造显存链表的结构体1.2、显存分配函数1、将我们自己分配的显存加入显存链表2、 将LCD 实际设备FB 显存加入链表 1.3、显存获取函数 2、显示页面图标函数框架构思3、编写MainPage页面3.1、获得显存3.2、描画数据1、判断或得到的显存是否已经…

18.数码相框总结

框架 整体框架如上&#xff0c;我对他们的阅读顺序是按照博客发布的顺序来的&#xff0c;感觉还行&#xff0c;读起来不是特别困难 page文件夹下的代码太多&#xff0c;就不一个一个拿出来粘代码了&#xff0c;关于page文件夹的阅读顺序 **page_manager -> main_page ->…

数码相框笔记

1. 程序框架 1.1 触摸屏: 主按线程,通过socket发给显示进程 --------------------------- 封装事件&#xff1a;ts线程 按键线程 --------------------------- 操作系统 封装的数据有: 时间 类型(点击、上下左右移动) 位置 速度 幅度 1.2 显示…

数码相框项目学习笔记(一)

之前看了韦东山老师的数码相框项目&#xff0c;断断续续学完了&#xff0c;现在再整理回顾&#xff0c;做个笔记记录一下。 项目需求&#xff1a; 实现在开发板上显示、浏览图片文件&#xff0c;并能进行图片的放大、缩小、移动、连播等操作 项目的主体框架&#xff1a; 项目…

数码相框(一、系统框架)

注&#xff1a;本人已购买韦东山第三期项目视频&#xff0c;内容来源《数码相框项目视频》&#xff0c;只用于学习记录&#xff0c;如有侵权&#xff0c;请联系删除。 1.项目流程 ① 弄清需求 (弄清产品需要实现的功能)&#xff1b; ② 设计框架 (怎么实现需求)&#xff1b; ③…

vue3-element-admin 项目说明文档

vue3-element-admin官方文档 | 在线预览 项目介绍 vue3-element-admin 是基于 Vue3 Vite4 TypeScript5 Element-Plus Pinia 等最新主流技术栈构建的后台管理前端模板&#xff08;配套后端源码&#xff09;。 项目有以下特性&#xff1a; 基于 vue-element-admin 升级到…