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