SDL顯示文字


  前面教程里,我們只顯示圖片,沒提到如何顯示文字, SDL本身沒有顯示文字功能,它需要用擴展庫SDL_ttf來顯示文字。ttf是True Type Font的縮寫,ttf是Windows下的缺省字體,它有美觀,放大縮小不變形的優點,因此廣泛應用很多場合。

  使用ttf庫的第一件事要從Windows的字庫下拷貝出一個字庫出來,最好是中文字體,這樣可以同時支持英文和中文顯示。它一般在c:\windows\fonts 目錄下面。比如simhei.ttf 就是仿黑體的字庫,將這個文件拷貝到你的源文件目錄下。

  要使用SDL_ttf庫首先要下載該擴展庫:http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf.html

  下載完成后按以前方式安裝(SDL安裝教程里有講),然后在你的源文件里加載頭文件"SDL_ttf.h”。要顯示文字需要按以下步驟進行:

  一.初始TTF庫

  初始化TTF庫要調用TTF_Init(),成功返回-1,不成功返回0。

  二.打開一個TTF_Font字體.

    使用 TTF_Font *TTF_OpenFont(const char *file, int ptsize);函數打開字體
    其中file是指字體文件的路徑,可以為相對路徑或絕對路徑, ptsize是指字號,即字體大小。它是基於720DPI的,有一個簡單辦法來估算字體大小,在Word中    選擇相應的字號即可看出效果來,不成功返回NULL。以下是打開一個黑體代碼,字號20,字體文件跟原文件在同一個目錄下。  

    //打開simfang.ttf 字庫,設字體為20號
    font  = TTF_OpenFont("simhei.ttf",20);
    if(font == NULL)
    {
       fprintf(stderr,"font open failure %s\n",SDL_GetError());
       exit(-1);
    }  

   三.將文字轉換成表面

  要想顯示文字,首先要將文字渲染成一副圖像,將文字渲染成一個圖像表面,有三種渲染方式:

  Solid  渲染的最快,但效果最差,文字不平滑,是單色文字,不帶邊框。

  Shaded 比Solid渲染的慢,但顯示效果好於Solid,帶陰影。

  Blend 渲染最慢,但顯示效果最好。

  四.把文字SDL_Surface 輸出到屏幕顯示,如果不需它,必須釋放它

   文字表面和其他表面一樣,可以傳輸到顯示表面顯示。
    五.關閉TTF_Font字體

  使用 void TTF_CloseFont(TTF_Font *font) ;關閉字體
    六.釋放TTF庫

  如果不需要再顯示文字,可以釋放TTF庫,使用 void TTF_Quit() ;
   下面以一個例子展示一下如何顯示文字,程序運行效果:  

  在這個例子里我們要掌握如何顯示西文、中文,以及如何給程序設置標題、圖標。程序主要代碼如下:  

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include "font.h"
 5 
 6 int main(int argc,char * argv[])
 7 {
 8     char a[] = "Hello World!";
 9     int quit = 0;
10     wchar_t * p ;
11     char tmp[]="世界,你好!";
12     wchar_t msg[] =L"聖    旨";  
13 
14    if(!init("文字","icon.bmp"))
15    {       
16        exit(0);
17    }
18 
19    //打開simfang.ttf 字庫,設字體為20號
20     font  = TTF_OpenFont("simhei.ttf",20);
21     if(font == NULL)
22     {
23        fprintf(stderr,"font open failure %s\n",SDL_GetError());
24        exit(-1);
25     }  
26 
27     gpBackground =  loadImage("background.jpg");  
28     applySurface(0,0,gpBackground,gpScreen);
29 
30     //TTF_SetFontStyle(font,TTF_STYLE_BOLD |  TTF_STYLE_ITALIC);
31 
32     //顯示西文
33     gpMessage[0] = TTF_RenderText_Solid(font,a,RGB_Black);
34     gpMessage[1] = TTF_RenderText_Shaded(font,a,RGB_Black,RGB_White);
35     gpMessage[2] = TTF_RenderText_Blended(font,a,RGB_Black);
36     applySurface(80,120,gpMessage[0],gpScreen);
37     applySurface(80,150,gpMessage[1],gpScreen);
38     applySurface(80,180,gpMessage[2],gpScreen);
39     SDL_Flip(gpScreen);
40 
41 
42     //顯示中文
43     p = cstringToUnicode(tmp); 
44     gpChinese = TTF_RenderUNICODE_Solid( font, p, RGB_Black);
45     applySurface(340,120,gpChinese,gpScreen);
46     SDL_FreeSurface(gpChinese);
47     gpChinese = TTF_RenderUNICODE_Shaded( font, p, RGB_Black,RGB_White);
48     applySurface(340,150,gpChinese,gpScreen);
49     SDL_FreeSurface(gpChinese);
50     gpChinese = TTF_RenderUNICODE_Blended( font, p, RGB_Black);
51     applySurface(340,180,gpChinese,gpScreen);
52     SDL_FreeSurface(gpChinese);
53     SDL_Flip(gpScreen);
54     free(p);
55     p = NULL;
56 
57     TTF_CloseFont(font);
58 
59     //重新打開simfang.ttf 字庫,設字體為40
60     font  = TTF_OpenFont("simhei.ttf",40);
61     if(font == NULL)
62     {
63         fprintf(stderr,"font open failure %s\n",SDL_GetError());
64         exit(-1);
65     }  
66     gpChinese = TTF_RenderUNICODE_Solid( font, msg, RGB_Yellow);
67     applySurface(260,50,gpChinese,gpScreen);
68     SDL_Flip(gpScreen);
69     SDL_FreeSurface(gpChinese);
70     
71     gpChinese = TTF_RenderUNICODE_Solid( font, L"C語言始終被模仿,從未被超越!", RGB_Red);
72     applySurface(100,240,gpChinese,gpScreen);
73     SDL_FreeSurface(gpChinese);
74 
75     gpChinese = TTF_RenderUNICODE_Solid( font, L"不懂C語言不要說自己是程序員!", RGB_Red);
76     applySurface(100,300,gpChinese,gpScreen);
77     SDL_FreeSurface(gpChinese);
78     SDL_Flip(gpScreen);
79 
80    // 事件處理
81    while(!quit)
82    {
83        if (SDL_PollEvent(&myEvent))
84        {
85            if (myEvent.type==SDL_QUIT)
86            {
87                quit = 1;
88            }
89        }       
90     }   
91     return 0;
92 }

  其中font.h是自己定義的頭文件,聲明了常用的變量、常量、函數,其代碼如下:  

#ifndef FONT_H_2012_05_31
#define FONT_H_2012_05_31
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include <Windows.h>

//定義布爾類型
typedef  int BOOL;
#define TRUE  1
#define FALSE 0

//屏幕分辯率
#define  SCREEN_WIDTH  718
#define  SCREEN_HEIGHT  419
#define  SCREEN_BPP  32

//表面聲明
extern SDL_Surface *gpBackground; //背景表面
extern SDL_Surface *gpScreen; //顯示表面
extern SDL_Surface *gpMessage[3]; //西文文字表面
extern SDL_Surface *gpChinese;//中文文字表面

//事件聲明
extern SDL_Event myEvent;

// 字體聲明
extern TTF_Font *font;

/*****************************聲明常見顏色*****************************************/
extern const SDL_Color RGB_Black;
extern const SDL_Color RGB_Red;
extern const SDL_Color RGB_Green;
extern const SDL_Color RGB_Blue;
extern const SDL_Color RGB_Cyan;
extern const SDL_Color RGB_Magenta;
extern const SDL_Color RGB_Yellow;
extern const SDL_Color RGB_White;
extern const SDL_Color RGB_Gray;
extern const SDL_Color RGB_Grey;
extern const SDL_Color RGB_Maroon ;
extern const SDL_Color RGB_Darkgreen;
extern const SDL_Color RGB_Navy;
extern const SDL_Color RGB_Teal;
extern const SDL_Color RGB_Purple;
extern const SDL_Color RGB_Olive;
extern const SDL_Color RGB_Noname;

/*****************************函數聲明*****************************************/
BOOL init(char* aCaption,char * aIcon);
SDL_Surface *loadImage( char * filename );
void applySurface( int x, int y, SDL_Surface* source, SDL_Surface* destination );
void cleanup();
char *localeToUTF8(char *src);
wchar_t* cstringToUnicode(char * aSrc);

#endif

  其中引用了windows.h,因為要做C語言字符串和寬字節字符的轉換要用到其中函數。C語言本身沒有BOOl類型,所以用typedef定義了自己的布爾類型,並且聲明了布爾常量TRUE和FALSE。

  下面我們從主函數說起,在第10行和12行我們看到了一種新的數據類型wcha_t,其實這是C99新加的一種寬字符類型,C語言char類型用一個字節表示一個ANSI字符,但漢字、日文等文字無法表示,所以引入了wchar_t,wchar_t用兩個字節表示一個字符,所以它可以表示絕大多數字符,無論是那種語言,unicode字符是wchar_t一種實現,在C語言中,unicode字符串一般來說都是wchar_t類型。TTF庫中提供了unicode字符串顯示和UTF8字符串顯示,要顯示中文必須是這兩種串才能顯示。

  第14行init函數完成系統初始化,包括初始化SDL、建立主窗口、初始化TTF庫,設置程序標題、圖標。其代碼如下:

/*
 函數名:init
 函數功能:完成系統初始化工作
 函數參數:aCaption程序標題欄顯示名稱,c語言字符串
           aIcon 程序圖標,必須為32*32bmp圖片
 函數返回值:無
*/
BOOL init(char* aCaption,char * aIcon)
{    
    //初始化 SDL
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
    {
        return FALSE;
    }

    //載入程序圖標
    SDL_WM_SetIcon(SDL_LoadBMP(aIcon), NULL);

    //初始化窗口
    gpScreen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE||SDL_HWSURFACE );
    if( gpScreen == NULL )//檢測是否初始化成功
    {
        return FALSE;
    }
    atexit(cleanup);

    //初始化字體庫
    if( TTF_Init() == -1 )
        return FALSE;

    //設置窗口名字和圖標
    SDL_WM_SetCaption(localeToUTF8(aCaption), NULL );
    return TRUE;
}

  注意要設置程序圖標,必須在建立主窗口前調用SDL_WM_SetIcon(SDL_LoadBMP(aIcon), NULL);來設置圖標,圖標必須是32*32的bmp圖片,因為TTF庫不是SDL自己的,所以必須調用TTF_Init()單獨初始化;最后設置程序標題,注意標題如果設英文可以直接顯示,但如果像我們這個程序這樣顯示中文,則必須將字符串轉換成UTF8的才能顯示,所以我們調用了自定義的函數localeToUTF8(aCaption)完成將c語言的字符串轉換成UTF8格式的字符串,這個函數定義如下:

/*--------------------------------------------------------------------
    函數名:    localeToUTF8
    參  數:    char *src  C語言字符串
    返回值: char * UTF8字符串
    功  能:    將C語言字符串轉換成UTF8字符串
    備  注:
----------------------------------------------------------------------*/
char *localeToUTF8(char *src)
{
    static char *buf = NULL;
    wchar_t *unicode_buf;
    int nRetLen;

    if(buf){
        free(buf);
        buf = NULL;
    }
    nRetLen = MultiByteToWideChar(CP_ACP,0,src,-1,NULL,0);
    unicode_buf = (wchar_t*)malloc((nRetLen+1)*sizeof(wchar_t));
    MultiByteToWideChar(CP_ACP,0,src,-1,unicode_buf,nRetLen);
    nRetLen = WideCharToMultiByte(CP_UTF8,0,unicode_buf,-1,NULL,0,NULL,NULL);
    buf = (char*)malloc(nRetLen+1);
    WideCharToMultiByte(CP_UTF8,0,unicode_buf,-1,buf,nRetLen,NULL,NULL);
    free(unicode_buf);
    return buf;
}

  這個函數完成將C語言字符串轉換成UTF8格式的字符串。 這樣我們就可以設置中文程序標題了。

  在主函數的第20行我們打開了一個字體庫,並設置字號為20,關於字號的大小你可以打開word看一下字號的大小。接下來,在33行我們調用TTF_RenderText_Solid將文字渲染成一幅圖片,返回圖片表面的指針,這個函數只能顯示西文,不能顯示中文。其原型:

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

  參數:font,打開的字體;text要顯示的字符串,C語言格式的字符串(以\0做結束符);fg是文字的顏色,前面我們介紹過SDL_Color結構,這里不再多說。

  除了這種渲染,還有:

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

  其中font、text和fg與TTF_RenderText_Solid中的一樣,bg是文字背景色。

  SDL_Surface *TTF_RenderText_Blended(TTF_Font *font, const char *text, SDL_Color fg)和TTF_RenderText_Solid參數一樣,關於這三種渲染的差別前面已經提過,運行結果頁顯示了blend效果最好,solid最差,shade可以設置文字背景。

  然后我們把這些表面和顯示圖片一樣顯示就可以了,36至40我們調用了自定義函數顯示文字:

  void applySurface( int x, int y, SDL_Surface* source, SDL_Surface* destination );

  x、y是文字顯示到屏幕上的位置,source是文字表面,destination是目標表面,一般是顯示表面。

  顯示西文比較簡單。顯示中文稍微麻煩點,如果你把char tmp[]="世界,你好!";顯示到屏幕,調用TTF_RenderText_Solid只會顯示一堆亂碼,因為這個函數只能顯示西文,如果要顯示中文要調用:  

顯示UTF8字符串 SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font, const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font, const char *text, SDL_Color fg, SDL_Color bg);
SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font, const char *text, SDL_Color fg);
顯示unicode字符串 SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font, const Uint16 *text, SDL_Color fg) ;
SDL_Surface *TTF_RenderUNICODE_Shaded(TTF_Font *font, const Uint16 *text, SDL_Color fg, SDL_Color bg) ;
SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font, const Uint16 *text, SDL_Color fg) ;

 

 

 

 

 

 

 

   UTF8編碼請查:http://baike.baidu.com/view/25412.htm;UNICODE編碼請查:http://baike.baidu.com/view/40801.htm

  這些函數的參數和前面差不多,唯一不同是要求text必須是UTF8或unicode格式的。那么如何將C語言字符串轉換成UTF8字符串或unicode字符串呢,前面我們使用自定義的函數char *localeToUTF8(char *src)將c字符串轉換為UTF8字符串返回,將c字符串轉換成unicode字符串,我們自定義了函數:

/*--------------------------------------------------------------------
    函數名:    cstringToUnicode
    參  數:    char *src  C語言字符串
    返回值: wchar_t * Unicode字符串
    功  能:    將c語言字符串轉換成unicode字符串
    備  注:
----------------------------------------------------------------------*/
wchar_t* cstringToUnicode(char * aSrc)
{
    int size;
    wchar_t *unicodestr = NULL;
    if(!aSrc)
    {
        return NULL;
    }
    size=MultiByteToWideChar(CP_ACP,0,aSrc,-1,NULL,0);
    unicodestr= malloc((size+1)*sizeof(wchar_t));
    MultiByteToWideChar(CP_ACP,0,aSrc,-1,unicodestr,size);
    return unicodestr;
}

  這個函數完成將c語言字符串轉換成unicode字符串返回,使用這兩個函數要注意,在函數中我們動態分配了內存來保存UTF8或unicode字符串,然后將其返回,所以我們在調用函數中顯示完后必須釋放這些字符串所占空間。主函數第43行我們將tmp串轉換成unicode串返回給p,然后顯示,在54行釋放了p。

  在第57行我們關閉了前面打開的字體,因為下面我們將用大一點字體顯示,如果要顯示中文,其實最簡單的辦法是在程序里直接定義wchar_t類型數組保存unicode字符串,然后可以直接顯示這個字符串,在第12行我們定義了wchar_t msg[] =L"聖    旨";unicode的字符串,注意unicode字符串必須以L開頭,否則就是C語言的字符串了。在第66-69行我們直接將其顯示到屏幕了。你也可以顯示unicode常量串,第71-78行我們分別顯示了兩個unicode常量串。

  在這里我們只討論了windows平台下中文顯示問題,如果在linux下會有所不同,具體的你可以查詢linux平台相關資料。如果你想要例子的源代碼,請點擊這兒。代碼中的字體文件太大,刪除了,你可以從windows下的fonts目錄下copy一個中文ttf文件到源文件目錄就可以了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM