Chinaunix首页 | 论坛 | 博客

分类: C/C++

2011-01-27 09:20:27

一.ttf字体

    SDL本身没有显示文字功能,它需要用扩展库SDL_ttf来显示文字。ttfTrue Type Font的缩写,ttfWindows下的缺省字体,它有美观,放大缩小不变形的优点,因此广泛应用很多场合。freeType是一个跨平台开源项目, 它可以在利用ttf字体输出到屏幕上。一般的linux发行版本都带了这个库(libfreetype.so),Windows下也有相应的移植版本。

    SDL_ttf封装freetype的库函数,提供一些简化的扩展接口提供SDL开发者使用。

    使用ttf库的第一件事要从Windows的字库下拷贝出一个字库出来,最好是中文字体,这样可以同时支持英文和中文显示。它一般在c:\windows \fonts 目录下面。比如simsun.ttf 就是仿宋体的字库,将这个文件拷贝到你的项目目录下。或者一个指定目录。

二.SDL_ttf 库的使用

    在进行开发前确认你的SDL库和SDL_ttf库是否已经编译成功,Linux下,只需要简单用 ./configure ; make ; make install 即可编译好这个库,默认安装在/usr/local/lib 下面。

    在程序中使用SDL_ttf库,必须使用如下两个头文件,注意SDL是大写

    #include SDL.h>

    #include

    Linux应用程序链接时要也要链接两个库的 -lSDL_ttf -lSDL.

   可以查看一下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
    if( TTF_Init() == -1 )
    return -1;

打开一个字体

    使用 TTF_Font *TTF_OpenFont(const char *file, int ptsize);

    其中file是指字体文件的路径,可以为相对路径或绝对路径, 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_RenderText_Solid(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对于编码是非常敏感的,必须明确告诉它是哪一种编码,才能正确输出。否则将输出乱码。可以用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格式.

    同样的 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) ;


    int w,h;

    if(TTF_SizeUTF8(font,"测试",&w,&h) == 0) {

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

    }

六.文字特效

    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);



例程如下(注意编译链接-lSDL_ttf -lSDL)

#include

SDL_Surface *screen;

static void quit(int rc)

{

       SDL_Quit();

       exit(rc);

}

void apply_surface(int x,int y,SDL_Surface *source)

{

       SDL_Rect offset;

       offset.x = x;

       offset.y = y;

       SDL_BlitSurface(source,NULL,screen,&offset);

}

int main(int argc,char *argv[])

{

       char *file;

       int w,h;

       Uint8 bpp;

       Uint32 flags;

       TTF_Font *font;

       SDL_Color red = {255,0,0};

       SDL_Surface *message1,*message2;

       w = 320;

       h = 240;

       bpp = 0;

       flags = SDL_SWSURFACE;

       if(SDL_Init(SDL_INIT_VIDEO) < 0){

             fprintf(stderr,"Couldn't initialize SDL:%s\n",SDL_GetError());

             return (1);

       }

if((screen=SDL_SetVideoMode(w,h,bpp,flags)) == NULL){

fprintf(stderr,"Couldn't set %dx%dx%d video mode: %s\n",w,h,bpp,SDL_GetError());

quit(1);

}


SDL_WM_SetCaption("SDL jice","jicetest");

if(TTF_Init() == -1)

return -1;


font = TTF_OpenFont("simkai.ttf",16);

if(!font)

{

printf("TTF_OpenFont:Open simsun.ttf %s\n",TTF_GetError());

return -1;

}

message1 = TTF_RenderText_Solid(font, "ttf test", red);

message2 = TTF_RenderUTF8_Solid(font, "字体显示", red);


if(message1||message2)

{

apply_surface(100,20,message1);

apply_surface(100,50,message2);

}

if(SDL_Flip(screen) == -1)

{

return -1;

}

SDL_FreeSurface(message1);

SDL_FreeSurface(message2);

TTF_CloseFont(font);

SDL_Delay(1000);

SDL_Quit();

return 0;

}



                 本文主要来源:bluedrum.cublog.cn                 作者:Andrew Huang

                 collator:jice    Email:chenhua2820@163.com          time:2011-01-27


阅读(2337) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~