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
![](http://blog.163.com/newpage/images/blogfileicons/rar35.png?1)
下载
像前面FreeType 字体库使用 -- 简易的字形装载中讲的那样,只是简单的显示一下没问题,但如果在实际应用中,那样使用,一直在不停的切换纹理是一些非常费的,一种极度不推荐的方法.要提高效率,可以从减少纹理的切换这一点不入手考虑.下面讲一下大致的思路吧.
1) 动态从FreeType库中加载所需字体.
对于汉字来说,一个字体库中包含几千个字,初始化时加载所有的文字是很纠结的,而且很多字体在整个程序运行过程中都用不到.所以,我们对于从FreeType字体库加载字体是用到时加载,不用不加载的原则.
2) 创建大纹理贴图.
我们可以在程序初始化的时候,建立几张大的空纹理,然后动态加载的字符数据填写到这些大纹理上,渲染时用UV纹理坐理来裁剪.创建的纹理过大,加载会过慢,太小纹理的切换次数也会过多.这个要根据具体的应用去创建.
像偶现在开发的游戏中,创建四张256*256的纹理,相对来说是比较适中的.游戏中使用12~24号字体,一张纹理上也能填充上200左右的字,游戏中用到的字也不算多.大多情况下,在一张纹理上就能满足游戏中所有的字了.如果是文字编辑等文字较多的程序来说,可以再把创建的纹理调大一点.
3) 创建字符渲染缓存.
没有必要在每次要渲染字符串的时候,都把数据送给设备去渲染.这样要渲染字符串调用的地方太多,切换纹理的频率也不会低.我们可以把一帧中所有要渲染的字符,按字符对应纹理按UV和渲染位置缓存在对应的BF列表中.然后在统一渲染.这样切换一次就把一张大纹理上所要渲染的所有的字符都渲染出来了.大大减少了纹理的切换次数.
大致的思路是这样的,附上简单的用应代码. VDISK网盘下载
原文链接:http://zengwu3915.blog.163.com/blog/static/278348972011108115939975/
![](http://blog.163.com/newpage/images/blogfileicons/rar35.png?1)
下载
FreeType 字体库使用 (简易的字形装载和实际应用)相关推荐
- CVE-2020-15999:Chrome FreeType 字体库堆溢出原理分析
聚焦源代码安全,网罗国内外最新资讯! 漏洞简介 Google发布公告,旧版本的 chrome 浏览器的 FreeType字体库中存在堆溢出,被利用可能导致 RCE(远程代码执行). 安全专家建议用户 ...
- 20.移植Freetype字体库
FreeType 支持 Gzip 压缩文件,会使用到 zlib 库.同时FreeType 可以加载 PNG 格式的彩色位 图字形,需要依赖于 libpng 库,因此在移植Freetype字体库前需要先 ...
- CVE-2020-15999:Chrome Freetype字体库堆溢出漏洞通告
360-CERT [三六零CERT](javascript:void(0)
- 基于Qt的FreeType字体轮廓解析
一.本文目的 以前的文档中.详细的介绍了FreeType开源字体引擎库的基础知识.基本用法.但并未详细的阐明在TurboCG中.是如何解析出一个文字的轮廓的,本文集中阐述.怎么样使用FreeType开 ...
- 用freetype开源字体库,实现在图片上字体大小
掌握truetype字体原理,利用freetype开源字体库,实现在图片上书写一行字体大小变化的诗句(比如首字体增大). 首先,在树莓派上安装freetype: 下载好: 传输文件,并且安装好: 解压 ...
- FreeType字体引擎介绍
在图像处理领域,有时候我们需要在图片上进行打印字体的任务.例如,打印一个logo到图片上.在这种情况下,我们需要调用字体库,并将其"雕刻"到图片上,而常用的TrueType,Ope ...
- Xft字体库:体系结构及用户指南(转)
Xft字体库:体系结构及用户指南(转) Xft字体库:体系结构及用户指南 Keith Packard XFree86 Core Team, SuSE Inc. keithp@keithp.com 本文 ...
- 在iOS应用中使用字体图标及制作字体库
做iOS开发的都知道,因为屏幕分辨率的问题,在iOS app 中都得放两套切图来支持retina屏和非retina屏幕,但是文字就不需要考虑分辨率的问题,所以可不可以将一些图片用文字来代替呢,省时省力 ...
- Android进阶之路 - 深入浅出字体、字体库
当时组内临时接到一个换字体库的需求,这个需求相对简单,因为手头有其他事情,同时之前也没换过字体库,就交给了同事去做了:现在有时间就好好充实下自己 ( 我写的也未必全对,如有不足可直接提出,相互探讨) ...
最新文章
- 2015年蓝桥杯省赛第5题--九数组分数
- 安卓application_阿里面试官刁钻连问:安卓 UID的分配、查看及相关知识
- android 并排按钮,简单布局:右边三个按钮并排靠右,左边一个输入框填满其他空间,多谢...
- MYSQL 与 Oracle 之间的数据类型转换
- bzoj 3224 Tyvj 1728 普通平衡树
- 34. 在排序数组中查找元素的第一个和最后一个位置012(二分查找+思路+详解+两种方法)Come Baby!!!!!!!! !
- Overload重載和Override重写的区别。Overloaded的方法是否可以改变返回值的类型?
- 第10章 bit_vector位向量容器
- 如何配置虚拟机的快照报警
- hibernate一对多映射实现
- NIPS 又!放!票!了!
- PHP获取每个订单下订单商品的数量
- OpenCV 二值化
- 一个双线性配对(双线性映射)的例子
- 九大ICT企业年中业绩大比拼
- Python3网络爬虫开发实战!付费讯代理、阿布云代理的使用!
- Windows下把文件夹压缩成.tar.gz格式
- 如何清除windowsoffice KMS激活
- QTableView中添加icon
- Elasticsearch:Runtime fields 及其应用(一)
热门文章
- 超级详细!!!Windows解决GitHub网页打开很慢的问题!!!!
- C#-WinForm设置托盘程序
- asp.net core 3.1和 .Net 5.0中使用AutoFac作为IoC容器组件
- 七周二次课(5月7日)
- 零基础小白如何学会Java?
- 【Power平台】Power Apps项目规划阶段(1),识别业务问题
- 【React工作记录九十一】Viewer.js实现图片预览效果
- 105 七夕祭(环形均分纸牌问题、绝对值不等式)
- oracle错误代码
- 开发,从需求出发 · 之一 所见即所得