Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1676268
  • 博文数量: 311
  • 博客积分: 7778
  • 博客等级: 少将
  • 技术积分: 4186
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-09 19:59
个人简介

蓝点工坊(http://www.bluedrum.cn) 创始人,App和嵌入式产品开发。同时也做相应培训和外包工作。 详细介绍 http://pan.baidu.com/s/1y2g88

文章存档

2012年(3)

2011年(115)

2010年(170)

2009年(23)

分类:

2010-08-17 10:16:44

 Andrew Huang
 
 
一.ttf字体
-----------------------------------------------------------------
   SDL本身没有显示文字功能,它需要用扩展库SDL_ttf来显示文字。ttf是True Type Font的缩写,ttf是Windows下的缺省字体,它有美观,放大缩小不变形的优点,因此广泛应用很多场合。freeType是一个跨平台开源项目,它可以在利用ttf字体输出到屏幕上。一般的Linux发行版本都带了这个库(libfreetype.so),Windows下也有相应的移植版本。
    SDL_ttf封装freetype的库函数,提供一些简化的扩展接口提供SDL开发者使用。
   
    使用ttf库的第一件事要从Windows的字库下拷贝出一个字库出来,最好是中文字体,这样可以同时支持英文和中文显示。它一般在c:\windows\fonts 目录下面。比如simsun.ttf 就是仿宋体的字库,将这个文件拷贝到你的项目目录下。或者一个指定目录。
 
 
二.SDL_ttf 库的使用
-------------------------------------------------------------------------
 
 在进行开发前确认你的SDL库和SDL_ttf库是否已经编译成功,Windows版本可以直接从官方网上下载编译好的开发包(头文件,动态库和静态)
 
 Linux下,只需要简单用 ./configure ; make ; make install 即可编译好这个库,默认安装在/usr/local/lib 下面。
 
   嵌入式SDL库移植参见我的博文:
 
  在程序中使用SDL_ttf库,必须使用如下两个头文件,注意SDL是大写
    #include SDL.h>
    #include
 
   Linux应用程序链接时要也要链接两个库的 -lSDL_ttf -lSDL
 
完整的TTF库说明参见
 
 
可以查看一下SDL_ttf完整版本
 
 
三.SDL_ttf编程
--------------------------------------------------------------------
 
SDL_ttf的编程的核心数据结构是  TTF_Font
所有的文字输出都是围绕这个结构展开的。
 
显示一段文字的流程
  一.初始TTF库
 
  二.创建一个对应某个字体文件的TTF_Font.
 
  三.用TTF输出函数把一段文字输出成SDL_Surface.其中TTF_font是其中必须参数
 
  四,把这个SDL_Surface 输出到屏幕显示,如果不需它,必须释放它
 
  五.释放TTF_Font
 
  六.关闭TTF库
 
 
   其中在一个程序中,可以同时打开多个TTF_Font.可以可以用输出方法输出N个SDL_Surface.这个完全看你的设计要求。只要在退出时记得一一释放即可。
 
 
初始化TTF库
 

#include <SDL_ttf.h>
 
 
//Initialize SDL_ttf

if( TTF_Init() == -1 )
        return -1;

 
打开一个字体
 
使用 TTF_Font *TTF_OpenFont(const char *file, int ptsize);
  其中file是指字体文件的路径,可以为相对路径或绝对路径, ptsize是指字号,即字体大小。它是基于720DPI的,有一个简单办法来估算字体大小,在Word中选择相应的字号即可看出效果来。
 
  中文字体的(五号字,小五,四号,小四)与数字字号有一个对应关系。
 
  英文字体“磅”(Point)和中文字号的关系
美国人习惯于用“磅”作为文字的计量单位,而中国人却习惯于字号作为文字的计量单位。它们的对应关系是:
初号=42磅=14.82毫米
小初=36磅=12.70毫米
一号=26磅=9.17毫米
小一=24磅=8.47毫米
二号=22磅=7.76毫米
小二=18磅=6.35毫米
三号=16磅=5.64毫米
小三=15磅=5.29毫米
四号=14磅=4.94毫米
小四=12磅=4.23毫米
五号=10.5磅=3.70毫米
小五=9磅=3.18毫米
六号=7.5磅=2.56毫米
小六=6.5磅=2.29毫米
七号=5.5磅=1.94毫米
八号=5磅=1.76毫米
 
其中的磅值就是你要设置的ptsize大致的值。

 
以下是打开一个仿宋字体的代码,字号为三号字,字体文件跟可执行文件在同一个目录下。
 

TTF_Font *font;
     font=TTF_OpenFont("simsun.ttf", 16);
     if(!font)
 {
     printf("TTF_OpenFont: Open simsun.ttf %s\n", TTF_GetError());
     return -1;
 }

 
 
输出英文/数字到一个SDL_Surface
 
它使用 SDL_Surface *(TTF_Font *font, const char *text, SDL_Color fg);来输出一段英文
 
其中font是某个打开的字体,text是输出的文本,fg是文字的颜色采用类型SDL_Color.采用RGB三色定义
 
 

SDL_Color black = { 255, 255, 255 };   //黑色

SDL_Color red =    { 255, 0, 0 };              //红色

 

如果成功将文字输出一个SDL_Surface,如果失败将返回一个空值.

 

其中Solid是单色的意思,类似输出有,空心字体:

 

SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font, const char *text, SDL_Color fg, SDL_Color bg) ;

 

着色输出

SDL_Surface *TTF_RenderText_Blended(TTF_Font *font, const char *text, SDL_Color fg) ;

 

 

其中Solid输出,速度最快,但是字体不太美观。而Shaded 有点慢,但是字体美观,但是字体内部是空心的。

Blend输出是非常之慢的,但是字体最为美观

 

 

 

 

显示文字

  输出成SDL_Surface 意味着文字已经转换一个图像数据,把它象一个图象一样粘贴到屏幕SDL_Surface上后刷新即可显示。

 

用前面讲的apply_surface()把文字加入到屏幕Surface当中。

 

用SDL_Flip来刷新屏幕让文字显示

 

注意,用完Surface后一定要调用SDL_FreeSurface()来释放它。

 

 

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
    
//Temporary rectangle to hold the offsets

    SDL_Rect offset;
    
    
//Get the offsets

    offset.x = x;
    offset.y = y;
    
    
//Blit the surface

    SDL_BlitSurface( source, NULL, destination, &offset );
}


//字体颜色

SDL_Color textColor = { 255, 255, 255 };

SDL_Surface * message;

message = TTF_RenderText_Solid( font, "hello ,bluedrum ", textColor );
if(message)
 {
    apply_surface(0,0,message,screen);
//加入文本数据到屏幕

 }

 
//刷新屏幕,让刚才的修改生效

 if(SDL_Flip(screen) == -1_
   {
      return -2;
   }
   
  
  SDL_FreeSurface(message);
   

 

释放字体

 使用 void TTF_CloseFont(TTF_Font *font) ;

 

关闭TTF库

 

使用 void TTF_Quit() ;
 

//Close the font that was used

    TTF_CloseFont( font );
    
    
//Quit SDL_ttf

    TTF_Quit();

 
 
四.关于中文输出
------------------------------------------------------------------
 
  这个问题是一个比较复杂的问题,复杂的原因在于SDL是一个跨平台的库,而两大平台Linux和Windows对于中文的内部编码是不一致的。分别采用UTF-8和Unicode.
而SDL_ttf对于编码是非常敏感的,必须明确告诉它是哪一种编码,才能正确输出。否则将输出乱码。
  
  因此在使用SDL_ttf中文前,最好先读我关于文字编码的博文
 以及用iconv转换编码的博文
 
SDL两种编码都可以直接输出
 UNICODE输出:
   SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font, const Uint16 *text, SDL_Color fg) ;
  
UTF-8输出:
SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font, const char *text, SDL_Color fg) ;
 
简单言之,如果你的在LINUX下输入在代码中直接写成的中文,那它就是UTF-8的编码,如果在WINDOWS用文本编辑器输出中文,它就是Unicode的编码,这个你可以用二进制编辑工具查看。
 
  这样如果源码是在WINDOWS编辑后,拷贝到LINUX上编译,这个时候就会发生混乱了,用TTF_RenderUTF8_Solid输出必然是乱码.
 
  所以为了保险,可以在源代码用数组用固定的编码。这样无论在哪个平台都能正确输出。另外一种情况把文件写在带BOM头的文件里,这样可以知道文件内部编码,以便程序采用相应用输出。
 
  还一些特殊情况,比如网上所有LRC歌词文件,必须是GBK格式,实测所有音乐软件都只认这个编码。这样需要用iconv转换成Unicode或UTF-8格式.
 
显示中文代码
 

//汉字硬编码写法

    
//wchar_t msg[] =L"你好"; //如果源码在Windows下,是UNICODE,Linux下是UTF-8

    
// wchar_t msg[] = {L'你',L'b', 0x0}; //同上

    
    
//直接采用数字编码

    Uint16 msg[1024] = {0x4F60,0x597D,0};
//=Unicode 编码:你好


    message = TTF_RenderUNICODE_Solid( font, msg, textColor );

 
同样的 Unicode/UTF-8的输出还有其它两组
 
 
TTF_RenderUTF8_Shaded
TTF_RenderUNICODE_Shaded
TTF_RenderUTF8_Blended
TTF_RenderUNICODE_Blended
 
 
五.文字的高度和宽度
 
------------------------------------------------------------------------------
 
  在一个实用的程序中,可能需要更多方法来实现一些复杂功能,比如说一个电子书软件,想整屏显示一个文本,那么文字的高度和宽度就是一个重要选择了。
 
  SDL_ttf有好几个关于文字高度和宽度的方法
 
求一行文本高度和宽度
 
求英文/数字文本高度和宽度,返回值为0表示测试成功,高度和宽度分别由w和h返回。
  int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h) ;
 
求UTF-8文本高宽
int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h) ;
 
求Unicode文本高宽
int TTF_SizeUNICODE(TTF_Font *font, const Unit16 *text, int *w, int *h) ;

 

// get the width and height of a string as it would be rendered in a loaded font

//TTF_Font *font;

int w,h;
Uint16 text[]={'H','e','l','l','o',' ',
               'W','o','r','l','d','!'};
if(TTF_SizeUNICODE(font,text,&w,&h)) {
    // perhaps print the current TTF_GetError(), the string can't be rendered...

} else {
    printf("width=%d height=%d\n",w,h);
}


上述接口计算比较简单,但是对于象整屏输出文本内容,用上面测试并不太方便。SDL_ttf还有更精确的计算方法。

英文字母对于各部分高度有严格定义

 

参见上面图片,以baseline为基准,

  •   如果有向下伸展的字母 j,g等,额外向下伸出部分称为Descent.
  •  字母在基线上方的高度称Ascent.
  •  字母总高度称为 Height = Ascent + Descent
  • 每一行文字与下一方的行间距称为 Link Skip

这四个参数分别用如下方法测试

int TTF_FontLineSkip(const TTF_Font *font) ;

int TTF_FontAscent(const TTF_Font *font) ;

int TTF_FontDescent(const TTF_Font *font) ;

int TTF_FontHeight(const TTF_Font *font) ;

当然中文只需要TTF_FontHeight/TTF_FontLineSkip两个字符即可。

 

还有一种把文字当成图像,这个一直没找用如何使用,但是这个图算得很细,一并留在记在这里

 

 

它使用如下方法来测如下各个字.
int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch, int *minx, int *maxx, int *miny, int *maxy, int *advance) ;
 
 
 
 

 

// get the glyph metric for the letter 'g' in a loaded font

//TTF_Font *font;

int minx,maxx,miny,maxy,advance;
if(TTF_GlyphMetrics(font,'g',&minx,&maxx,&miny,&maxy,&advance)==-1)
    printf("%s\n",TTF_GetError());
else {
    printf("minx : %d\n",minx);
    printf("maxx : %d\n",maxx);
    printf("miny : %d\n",miny);
    printf("maxy : %d\n",maxy);
    printf("advance : %d\n",advance);
}


 

五.文字特效

------------------------------------------

TTF使用如下方法来显示特殊效果

void TTF_SetFontStyle(TTF_Font *font, int style)

style 参数可以设为如下几种效果
TTF_STYLE_BOLD                     #粗体
TTF_STYLE_ITALIC                   #斜体
TTF_STYLE_UNDERLINE                #下划线
TTF_STYLE_STRIKETHROUGH            #删除线(即中划线)
  
如果Style设为 TTF_STYLE_NORMAL, 效果将变成缺省效果

 

// set the loaded font's style to bold italics

//TTF_Font *font;

TTF_SetFontStyle(font, TTF_STYLE_BOLD|TTF_STYLE_ITALIC);

// render some text in bold italics...


// set the loaded font's style back to normal

TTF_SetFontStyle(font, TTF_STYLE_NORMAL);

六.测试代码

---------------------------------------------------------

 本测试代码在RHEL5下测试通过,这是测试结果,在运行前把从c:\windows\fonts拷贝simfang.ttf 到项目目录下。

 
 
文件: show_hz2.zip
大小: 21KB
下载: 下载
 
阅读(4874) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-08-19 11:38:00

老师好强啊 老师晓得有没有专门的SDL论坛?感觉搞SDL的太少啦