方式二、使用字体引擎(Font Engine)
AGG的字体引擎利用WinAPI:GetGlyphOutline或FreeType库得到字体数据(字模),它可以处于 “Scanline Rasterizer”层或“顶点源”层。要使用字体引擎,要把相应的字体引擎源码(agg_font_win32_tt.cpp或 agg_font_freetype.cpp)加入项目一起编译。
头文件
- #include <agg_font_win32_tt.h>
- #include <agg_font_freetype.h>
注意,它们都有自己的文件夹,不是在agg的include文件夹里。
类型
agg::font_engine_win32_tt_int16 agg::font_engine_win32_tt_int32 agg::font_engine_freetype_int16 agg::font_engine_freetype_int32
显然,前两个利用WinAPI实现,后两个利用FreeType库实现。类型后面的_int16或_int32后缀用于指定坐标单位, 一般int16已经可以满足要求。
成员类型定义:
typedef path_adaptor_type | 把字体数据包装成顶点源的类 |
typedef gray8_adaptor_type | 把字体数据包装成Scanline Rasterizer的类 |
typedef mono_adaptor_type | 把字体数据包装成Scanline Rasterizer的类,但无AA效果 |
成员属性:
double: height | 字体高度,单位为Point(和Word里的单位一样) |
double: width | 字体宽度,单位为Point*2.4。0表示规则大小(height/2.4) |
bool: italic | 斜体 |
bool: flip_y | 上下翻转 |
bool: hinting | 字体修正 |
unsigned: resolution | 字体解析度,单位为dpi |
成员方法:
void transform(const trans_affine& affine); | 按矩阵变换 |
bool create_font(const char* typeface_, glyph_rendering ren_type); | font_engine_win32_tt_*专有方法 建立字体,typeface_为字体名,ren_type稍后再说 |
bool load_font(const char* font_name, unsigned face_index, glyph_rendering ren_type, const char* font_mem = 0, const long font_mem_size = 0); | font_engine_freetype_*专有方法 建立字体,font_name是字体文件名或字体名 |
bool prepare_glyph(unsigned glyph_code) unsigned data_size() const void write_glyph_to(int8u* data) const | 得到字体数据(字模)所需方法 |
字体引擎的create_font()方法和load_font()方法需要一个glyph_rendering类型的ren_type参数,它决定了字 体数据的形式。三个成员类型定义:path_adaptor_type、gray8_adaptor_type和mono_adaptor_type所包 装的字体数据是 不一样的,只有与ren_type参数对应才能生成正确的AGG显示节点。
glyph_rendering是一个枚举类型,定义是:
- enum agg::glyph_rendering{
- glyph_ren_native_mono, //对应mono_adaptor_type
- glyph_ren_native_gray8, //对应gray8_adaptor_type
- glyph_ren_outline, //对应path_adaptor_type
- glyph_ren_agg_mono, //对应mono_adaptor_type
- glyph_ren_agg_gray8 //对应gray8_adaptor_type
- };
示例代码1 - 从顶点源层输出文字
- typedef agg::font_engine_win32_tt_int16 fe_type;
typedef fe_type::path_adaptor_type vs_type;
// 字体引擎
fe_type fe( ::GetDC(::GetActiveWindow()) ); //注意,实际应用时要释放HDC
fe.height(36.0);
fe.flip_y(true);
fe.hinting(true);
// 注意后面的glyph_rendering ren_type参数
fe.create_font("黑体",agg::glyph_ren_outline);
// 字体串
wchar_t *s = L"C++编程";
// 存放字体数据
std::vector<agg::int8u> data;
// 顶点源
vs_type vs;
// 注意这里,使用conv_curve转换
agg::conv_curve<vs_type> ccvs(vs);
// 字符输出的位置
int x=20,y=100;
for(;*s;s++)
{
// 让字体引擎准备好字体数据
if(!fe.prepare_glyph(*s)) continue;
// 把字体数据放到容器里
data.resize( fe.data_size() );
fe.write_glyph_to( &data[0] );
// 从字体数据中得到顶点源
vs.init(&data[0], data.size(), x, y);
// 移动输出位置
x += fe.advance_x();
y += fe.advance_y();
// 输出
ras.add_path(ccvs);
agg::render_scanlines_aa_solid(ras,sl,renb,agg::rgba(0,0,1));
}
由于字体顶点源可能会包含带Curve命令的顶点,所以要用conv_curve来 转换。你可以试试去掉这层转换,字符'C' 就不会那么平滑了。
示例代码2 - 从Scanline Rasterizer层输出文字
- // 字体引擎类型定义
typedef agg::font_engine_win32_tt_int16 fe_type;
typedef fe_type::gray8_adaptor_type ras_type;
typedef ras_type::embedded_scanline sl_type;
// 字体引擎
fe_type fe( ::GetDC(::GetActiveWindow()) ); //注意,实际应用时要释放HDC
fe.height(36.0);
fe.flip_y(true);
fe.hinting(true);
// 注意后面的glyph_rendering ren_type参数
fe.create_font("黑体",agg::glyph_ren_agg_gray8);
// 字体串
wchar_t *s = L"C++编程";
// 存放字体数据
std::vector<agg::int8u> data;
// Rasterizer和Scanline
ras_type ras_font;
sl_type sl_font;
// 字符输出的位置
int x=20,y=100;
for(;*s;s++)
{
// 让字体引擎准备好字体数据
if(!fe.prepare_glyph(*s)) continue;
// 把字体数据放到容器里
data.resize( fe.data_size() );
fe.write_glyph_to( &data[0] );
// 从字体数据中得到Rasterizer
ras_font.init(&data[0], data.size(), x, y);
// 移动输出位置
x += fe.advance_x();
y += fe.advance_y();
// 输出
agg::render_scanlines_aa_solid(ras_font,sl_font,renb,agg::rgba(0,0,1));
}
显示效果