SDL顯示文字及中文


 

一.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庫移植參見我的博文:
http://blog.chinaunix.net/u3/105675/showart_2149945.html

在程序中使用SDL_ttf庫,必須使用如下兩個頭文件,注意SDL是大寫
#include SDL.h>
#include

Linux應用程序鏈接時要也要鏈接兩個庫的 -lSDL_ttf -lSDL

完整的TTF庫說明參見
http://jcatki.no-ip.org/SDL_ttf/SDL_ttf_59.html#SEC59

可以查看一下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>

//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_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對於編碼是非常敏感的,必須明確告訴它是哪一種編碼,才能正確輸出。否則將輸出亂碼。

因此在使用SDL_ttf中文前,最好先讀我關於文字編碼的博文
http://blog.chinaunix.net/u3/105675/showart_2121442.html
以及用iconv轉換編碼的博文
http://blog.chinaunix.net/u3/105675/showart_2096177.html

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 到項目目錄下。


免責聲明!

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



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