03.freetype显示英文

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值