写点什么

SDL 文字显示

作者:柒号华仔
  • 2022 年 7 月 19 日
  • 本文字数:4097 字

    阅读完需:约 13 分钟

 一.ttf 字体

    SDL 本身没有显示文字功能,它需要用扩展库 SDL_ttf 来显示文字。ttf 是 TrueTypeFont 的缩写,ttf 是 Windows 下的缺省字体,它有美观,放大缩小不变形的优点,因此广泛应用很多场合。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/SDL.h>

   #include<SDL/SDL_ttf.h>

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

  可以查看一下 SDL_ttf 完整版本

    http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf.html

三.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>    if( TTF_Init() == -1 )    return -1;

打开一个字体

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

    其中 file 是指字体文件的路径,可以为相对路径或绝对路径,ptsize 是指字号,即字体大小。

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

    TTF_Font*font;


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

    if(!font)

    {           printf("TTF_OpenFont: Opensimsun.ttf %s\n", TTF_GetError());

           return -1;    }

输出英文/数字到一个 SDL_Surface


   它使用 SDL_Surface*TTF_RenderText_Solid(TTF_Font *font, const char *text, SDL_Colorfg);来输出一段英文


其中 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_Colorfg, SDL_Color bg) ;


着色输出


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


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


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


显示文字


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


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


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

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

voidapply_surface( int x, int y, SDL_Surface* source, SDL_Surface*destination ){     //Temporaryrectangle to hold the offsets    SDL_Rectoffset;    //Get the offsets     offset.x= x;     offset.y = y;     //Blitthe 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);

释放字体

    使用 voidTTF_CloseFont(TTF_Font *font);

关闭 TTF 库

    使用 voidTTF_Quit();

    //Closethe font that was used    TTF_CloseFont( font );    //QuitSDL_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_Colorfg);

    UTF-8 输出:

   SDL_Surface*TTF_RenderUTF8_Solid(TTF_Font *font,const char *text,SDL_Colorfg);

    简单言之,如果你的在 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 返回。

   intTTF_SizeText(TTF_Font *font,const char *text,int *w,int *h);

   求 UTF-8 文本高宽

   intTTF_SizeUTF8(TTF_Font *font,const char *text,int *w,int *h);

   求 Unicode 文本高宽

   intTTF_SizeUNICODE(TTF_Font *font,const Unit16 *text,int *w,int *h);


    int w,h;

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

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

   }

六.文字特效

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

    voidTTF_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 bolditalics...   // set the loaded font's style back tonormal   TTF_SetFontStyle(font, TTF_STYLE_NORMAL);


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


#include

SDL_Surface*screen;

staticvoid quit(int rc)

{

      SDL_Quit();

      exit(rc);

}

voidapply_surface(int x,int y,SDL_Surface *source)

{

      SDL_Rect offset;

      offset.x = x;

      offset.y = y;

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

}

intmain(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'tinitialize SDL:%s\n",SDL_GetError());

            return (1);

      }

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

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

quit(1);

}


SDL_WM_SetCaption("SDLjice","jicetest");

if(TTF_Init() == -1)

return -1;


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

if(!font)

{

printf("TTF_OpenFont:Opensimsun.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;

}


发布于: 刚刚阅读数: 3
用户头像

柒号华仔

关注

星光不问赶路人,时光不负有心人。 2022.07.01 加入

CSDN 5G领域新星创作者,阿里云星级博主,专注于5G领域,兼顾网络,编解码协议,linux,C/C++等方向,欢迎关注我。

评论

发布
暂无评论
SDL文字显示_7月月更_柒号华仔_InfoQ写作社区