FreeType 字体库使用 (简易的字形装载和实际应用)

FreeType是一个用C语言实现的体光栅化引擎制作的一个函式库.它可以用来将字符栅格化并映射成位图以及提供其它字体相关业务的支持.FreeType也是一个跨平台的字体库,下面实例以 Windows环境加DX9.0实现.
       接下来讲一下简易的字形装载,包括以下内容
* 初始化库 
* 通过创建一个新的 face 对象来打开一个字体文件 
* 以点或者象素的形式选择一个字符大小 
* 装载一个字形(glyph)图像,并把它转换为位图 
* 渲染一个简单的字符串

1) 初始化库
       简单地创建一个FT_Library类型的变量,例如library,然后象下面那样调用函数FT_Init_FreeType: 
#include <ft2build.h> 
#include FT_FREETYPE_H 
FT_Library m_FT2Lib;

FT_Error error = FT_Init_FreeType( &m_FT2Lib);
 if (error)
 {
       // 当初始化库时发生了一个错误
 }
       这个函数,它创建一个FreeType 2库的新实例,并且设置句柄library为它.它装载库中FreeType所知道的每一个模块.
       返回值为0的错误代码始终意味着操作成功了,否则,返回值指示错误,library设为NULL。

2) 装载一个字体face
a.从一个字体文件装载
 
       应用程序通过调用FT_New_Face创建一个新的face对象.一个face对象描述了一个特定的字样和风格.例如,"黑体"(simhei.ttf文件). 
FT_Library m_FT2Lib; //库的句柄 
FT_Face    m_FT_Face; // face对象的句柄 
...
FT_Error error = FT_New_Face( m_FT2Lib, "/font/simhei.ttf",0,&m_FT_Face); 
if (error) 

... 装载出错 
}

FT_New_Face函数
FT_New_Face( FT_Library   library, // 一个FreeType库实例的句柄,face对象从中建立 
               const char*  filepathname, // 字体文件路径名(一个标准的C字符串),这个索引指示你想装载的face,Index 0总是正确的.
               FT_Long      face_index,   // 某些字体格式允许把几个字体face嵌入到同一个文件中
               FT_Face     *aface );Library // 一个指向新建的face对象的指针,当失败时其值被置为NULL
       要知道一个字体文件包含多少个face,只要简单地装载它的第一个face(把face_index设置为0),face->num_faces的值就指示出了有多少个face嵌入在该字体文件中.

b.从内存装载 
       如果你已经把字体文件装载到内存,你可以简单地使用FT_New_Memory_Face为它新建一个face对象,如下所示:
FT_Library m_FT2Lib; //库的句柄 
FT_Face    m_FT_Face; // face对象的句柄 
....
FT_Error error = FT_New_Memory_Face( library, // 一个FreeType库实例的句柄,face对象从中建立 
               buffer,  // 缓存的第一个字节
               size,     // 缓存的大小(以字节表示) 
               0,         // face索引
               &face ); 
if ( error ) { ...装载失败  } 
       FT_New_Memory_Face简单地用字体文件缓存的指针和它的大小(以字节计算)代替文件路径.除此之外,它与FT_New_Face的语义一致.

3) 设置像素大小
error = FT_Set_Pixel_Sizes( 
            face, //face对象句柄 
            0, // 象素宽度
            14 ); // 象素高度 
       这个例子把字符象素设置为14x14象素.尺寸中的任一个为0意味着"与另一个尺寸值相等"

4) 设置字符表
error = FT_Select_CharMap( 
          face,
// 目标face对象
          FT_ENCODING_UNICODE ); // 编码 
       这种方式只限于你所需的编码已经有对应的枚举定义在FT_FREETYPE_H中.至于没有的,我们可以遍历num_charmaps查找出face中所支持的字符表.这个不怎么常用,在这也不多扯了.

5) 装载一个字形图像
a) 装载一个字符的glyph
error = FT_Load_Char(
           m_FT_Face,
           ch, // 字符索引
           FT_LOAD_RENDER | FT_LOAD_TARGET_LIGHT ); // 装载标志
       load_flags的值是位标志集合,用位运算来表示,是用来指示某些特殊操作的.其默认值是FT_LOAD_DEFAULT即0
获取位图描述符
FT_GlyphSlot slot = m_FT_Face->glyph;
FT_Bitmap bitmap = slot->bitmap;

b) 把位图数据拷贝自己定义的数据区里
       因为FreeType中生成的每个字符位图的大小是不一样的,所以,我们还得记录一下,图的大小及一些偏移值等.这些值用来我们渲染字符串时对齐排版用.这些记录后,我们还需要将数据转成我们自己需要的数据格式.
       face中生成的图片有二种模式FT_RENDER_MODE_NORMAL一个高质量的抗锯齿(256级灰度)位图.还有一个是生成黑白位图FT_RENDER_MODE_MONO标志.下面以DX9.0来说.
       FT_RENDER_MODE_NORMAL这个模式下,我们将这个256级灰度转成纹理的alpha值,这样就可以行到一个纹理.
       FT_RENDER_MODE_MONO模式下,我们将0作为alpha的0,1作为alpha的255,这样也可以得到一个这样的纹理.
LPDIRECT3DTEXTURE9 d3d9_texture = NULL;
 if (m_pDevice->CreateTexture(width, height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &d3d9_texture, NULL) == D3D_OK)
 {
  D3DLOCKED_RECT locked_rect;
  d3d9_texture->LockRect(0, &locked_rect, NULL, 0);
  switch (m_FT_Face->glyph->bitmap.pixel_mode)
  {
  case FT_PIXEL_MODE_GRAY:
   {
    for (int y = 0; y < height; ++y)
    {
     for (int x = 0; x < width; ++x)
     {
      unsigned char _vl =  (x>=bitmap.width || y>=bitmap.rows) ? 0 : bitmap.buffer[x + bitmap.width*y];
      byte* destination_pixel = ((byte*) locked_rect.pBits) + locked_rect.Pitch * y + x * 4;

      destination_pixel[0] = 0xff; // b
      destination_pixel[1] = 0xff; // g
      destination_pixel[2] = 0xff; // r
      destination_pixel[3] = _vl; // a 
     }
    }
   }
   break;
  case FT_PIXEL_MODE_MONO:
   { 
    for (int y = 0; y < height; ++y)
    {
     for (int x = 0; x < width; ++x)
     {
      unsigned char _vl = 0;
      if(bitmap.buffer[y*bitmap.pitch + x/8] & (0x80 >> (x & 7)))
       _vl = 0xFF;
      else
       _vl = 0x00;

      byte* destination_pixel = ((byte*) locked_rect.pBits) + locked_rect.Pitch * y + x * 4;
      destination_pixel[0] = 0xFF;
      destination_pixel[1] = 0xFF;
      destination_pixel[2] = 0xFF;
      destination_pixel[3] = _vl;

     }
    }
   }
   break;
  }

  d3d9_texture->UnlockRect(0);
 }
       这样,一个字符的纹理图片就装载好了.只要渲染出来就可以了.

       装下来看完整的代码实例吧.
       以上程序代码实例下载: VDISK网盘下载
本文参考 <The FreeType 2 Tutorial> 和 Unigine引擎SDK中FreeType实现

原文链接:http://zengwu3915.blog.163.com/blog/static/278348972011911103541256?suggestedreading

FreeType_DX.rar(5.27M)   
下载




像前面FreeType 字体库使用 -- 简易的字形装载中讲的那样,只是简单的显示一下没问题,但如果在实际应用中,那样使用,一直在不停的切换纹理是一些非常费的,一种极度不推荐的方法.要提高效率,可以从减少纹理的切换这一点不入手考虑.下面讲一下大致的思路吧.

       1) 动态从FreeType库中加载所需字体.
       对于汉字来说,一个字体库中包含几千个字,初始化时加载所有的文字是很纠结的,而且很多字体在整个程序运行过程中都用不到.所以,我们对于从FreeType字体库加载字体是用到时加载,不用不加载的原则.

       2) 创建大纹理贴图.
       我们可以在程序初始化的时候,建立几张大的空纹理,然后动态加载的字符数据填写到这些大纹理上,渲染时用UV纹理坐理来裁剪.创建的纹理过大,加载会过慢,太小纹理的切换次数也会过多.这个要根据具体的应用去创建.
       像偶现在开发的游戏中,创建四张256*256的纹理,相对来说是比较适中的.游戏中使用12~24号字体,一张纹理上也能填充上200左右的字,游戏中用到的字也不算多.大多情况下,在一张纹理上就能满足游戏中所有的字了.如果是文字编辑等文字较多的程序来说,可以再把创建的纹理调大一点.

       3) 创建字符渲染缓存.
       
没有必要在每次要渲染字符串的时候,都把数据送给设备去渲染.这样要渲染字符串调用的地方太多,切换纹理的频率也不会低.我们可以把一帧中所有要渲染的字符,按字符对应纹理按UV和渲染位置缓存在对应的BF列表中.然后在统一渲染.这样切换一次就把一张大纹理上所要渲染的所有的字符都渲染出来了.大大减少了纹理的切换次数.

       大致的思路是这样的,附上简单的用应代码. VDISK网盘下载

原文链接:http://zengwu3915.blog.163.com/blog/static/278348972011108115939975/

FreeType_55.rar(5.16M)   
下载


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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。 希望这些信息对您有所帮助!如果您有任何进一步的问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值