在嵌入式Linux及QT/Embedded-2.3.7下製作QPF字型檔

admin @ 2014-03-25 , reply:0

    QT是目前在Linux操作系統平台下應用最多的圖形用戶界面的底層庫,由其派生出的QT/Embedded大量用於嵌入式系統開發和研製中。實際上,QT/Embedded提供給用戶的非ASCII碼的字型檔一般比較少,在我們開發過程中用的嵌入式Linux系統中中文和日文的字型檔都只有一個(不算不同的旋轉角),其中還存在字體大小不一樣的問題,因此在實際開發過程中我們在處理中文字體顯示時,最終使用這些工具開發出來的軟體的用戶就經常抱怨字體很難看,字體大小有時都不一致,因此定製自己的字型檔,以便使得最終用戶能夠看到漂亮的中文顯示,這是使用QT/Embedded開發各種程序急需解決的一個問題。

1 如何定製字型檔
    定製自己的字型檔需要修改兩個文件,一個是FONTDIR,它是應用程序尋找當前系統中最適合自己需要的字型檔的索引;另一個就是字型檔文件了,可以有一個或者多個字型檔文件,字型檔文件是最終顯示的字的點陣圖或者矢量。它們都必須放在目錄/usr/qt/lib/fonts下(基於我們的平台QT/Embedded,其它平台可能有區別,下同)。

1.1 FONTDIR的簡介
     一個典型的FONTDIR文件的內容如下所示:
fixed fixed_120_50.qpf QPF n 50 120
helvetica helvetica_80_50.qpf QPF n 50 80
helvetica helvetica_120_50.qpf QPF n 50 120 u
helvetica helvetica_120_75.qpf QPF n 75 120 u
helvetica helvetica_140_75.qpf QPF n 75 140
helvetica helvetica_180_75.qpf QPF n 75 180
    文件中每行都標識一個特定的字型檔,每個段的含義是:第一列為name,第二列為file,第三列為renderer,相當於字型格式,所以有BDF,TTT,QPF等選擇。第四列n表示iitalic,表示是否為斜體字。第五列表示weight,其中50表示Normal,75表示Bold。第六列表示size,例如:120表示12pt。第七列為flags,有下面三個選擇:s=smooth(anti-aliased)u =unicode range when saving (default is Latin 1 a = ASCII range when saving(default is Latin 1))
                                                         —— 摘自參考文獻[1]
    其中屬性file,renderer(BDF,TTF,QPF)和size特別要設置對,其它屬性問題不大。還要注意如果在該目錄下有QPF的文件,系統只會使用QPF格式的文件,而不會讀取其它格式的文件,不管FONTDIR裡面的內容是什麼。如果有多個QPF文件,應用程序按照大小,家族,黑體和斜體的順序查找,即首先查找大小和自己一樣的字型檔,大小無法區分唯一的字型檔的再看對應的家族,還是無法區分的再看是否黑體,是否斜體。可以參考PC上的字型檔索引文件FONTDIR:
例如:
-cclib -song -medium -r -normal -jiantizi -16 -160 -75 -75 -c -160 -gb2312 1980 -0
其中,每個段的含義如下:
cclib:製造商
song:字體族,此處表示“宋體”字
medium:字權重(中等),還有bold(粗體)選項
r:傾斜,R(Roman),I(Italic),O(Oblique)
normal:字符集寬度,此外還有condensed,narrow,double
jiantizi:附加說明(此處意義為“簡體字”)
16:用像素衡量的寬度。
160:點數 10
75(1):水平解析度(dpi)
75(2):垂直解析度(dpi)
c:間距。c:square,m:fixed width,p:variable width
160:平均寬度(10*pixels)
gb2312.1980:註冊字符集,標準名
0:第0套,基本集
                                                      —— 摘自參考文獻[2]

1.2 幾種格式字型檔的簡介
    QT支持四種格式的字型檔(TTF,BDF,PFA/PFB,QPF)(見參考文獻[3]),但在產品中,如果直接使用,TTF或PFA/PFB。即讓應用程序在顯示的時候再計算點陣,最終的效果並不理想,會發現有些字大,有些字小,而且需要佔用非常多的FLASH和內存,速度也有點慢,所以我在此不想過多的介紹PFA/PFB。如果直接使用BDF,速度非常慢,而且需要佔用比較多的FLASH和內存;使用QPF,速度和佔用其它資源是最小的,因此我們最終的產品中採用QPF格式。下面我簡單介紹,TTF,BDF和QPF字體的結構,這樣就比較容易理解後面的轉換過程。

1.2.1  TTF字體
   TTF(TrueType Font)是Apple公司和Microsoft公司共同推出的字體文件格式,隨著Windows的流行,已經變成最常用的一種字體文件表示方式。TTF字體已經成功用在Windows中文版生成漢字字型檔,此字體採用二次B樣條曲線來描述字元輪廓,對字元輪廓的上的點,按順時針方向從小到大編號,填充部分在其右邊。TTF文件結構分成三個部分:文件名(12Bytes),描述表目錄(每個16Bytes),描述表數據。
    對於每一個字,都有一個假想的矩形框,正常情況字是不會超出這個矩形框的,中文屬於象形字,不象英文,大小不一致,比如:英文中的f就可能會超出矩形框。微軟把矩形的高度稱為EM,實際字元的高度稱為BODY.矩形框最原始的坐標系是矩形的中心為原點,但為了實際字體在列印和顯示的使用過程中的方便,通常將坐標原點放在左下角,或中下。
    通常,在實際列印過程中,TTF字體是用像素來度量的,如何將矩形框中的字體轉成像素呢?有一個計算公式,實例如下:如果18個點的72點每英寸屏下有一個550的長度,矩形框內有2048個單位。那其像素為550*18*72/72/2048=4.83像素。顯然,每英寸里的點取的越多,字就越逼真,同時這樣的存儲空間和計算的時間也就越多。在嵌入程序開發過程中,這往往是不可以接受的,因為嵌入式系統的硬體資源本來就很有限,如果真的這樣的話,在顯示過程會很慢。並且如果為了提高速度而減少每英寸中的點數,則字體失真的情況很嚴重。更加具體的關於,TTF字體的內容可見參考資料[3]。
    另外,在Windows下編程,Microsoft實現了讓用戶對字體操作處理具有透明性,有關字體結構定義見參考文獻[4]。

1.2.2 BDF字體
    BDF(Bitmap Distribution Format)是在X窗口系統中的一種表示點陣圖字體的文件格式。是X協會定義的一種標準,是ASCII文件 它由兩部分組成,一是表示字體整體屬性的文件頭信息;二是每一個字元獨有的屬性和點陣圖數據。我以16*16的點陣圖字體為例描述BDF字體文件格式。
STARTFONT2.1 /*後面跟一個版本號,指出該字體文件版本*/
COMMENT /*表示註釋*/
FONT -adobe -courier -bold -r -normal -16 -160 -75 -75 -m -160 -gb2312.1980 -0
/*表示字體名*/
SIZE 16 75 75 /*字元大小與在X,Y方向上的解析度*/
FONTBOUNDINGBOX 16 16 0 0 /*X方向上寬度與Y方向高度及x和Y方向上的偏移*/
STARTPROPERTIES 16 /*設置字體的屬性項目數*/
FOUNDRY "Adobe" /*字體的製造廠家*/
FAMILY_NAME "Courier" /*字體的變種字型*/
WEIGHT_NAME "Bold" /*字體的印刷權*/
SLANT "R" /*字體字型的設計情況*/
SEWINDTH_NAME "Normal" /*字體的縮放因素*/
ADD_STYLE_NAME "" /*唯一的標識該字體,一般為空*/
PIXEL_SIZE 16 /*依賴於設備的字體尺寸*/
POINT_SIZE 160 /*設計字體的實際尺寸*/
RESOLUTION_X 75 /*設計字體的水平解析度*/
RESOLUTION_Y 75 /*設計字體的垂直解析度*/
SPACING "m" /*指出字元寬度是定長還是可變*/
AVERAGE_WIDTH 160 /*字體中所有字元的平均寬度*/
CHARSET_REGISTRY "gb2312.1980" /*字符集名*/
CHARSET_ENCODING "0" /*字符集編號*/
FONT_DESCENT 0 /*基線下的高度*/
FONT_ASCENT 16 /*基線上的高度*/
ENDPROPERTIES /*屬性項設置結束*/
CHAR 6775 /*字體文件中的字元數*/
STARTCHAR 啊 /*字元起始標誌及名稱*/
ENCODE 3021 /*X伺服器在存取該字元時使用的編碼。如漢字國標碼*/
SWIDTH 1000 0 /*X和Y方向上的邏輯寬度和高度*/
DWIDTH 16 0 /*字元在x和Y方向上的設備單位寬度*/
BBX 16 16 0 0 /*字元邊界框的寬度,高度以及偏移*/
BITMAP /*字元的點陣圖的信息起始標誌*/
0000 /*字元點陣圖*/
04a0
……
0590
ENDCHAR /*字元結束標誌*/
STARTCHAR 阿 /*第二個字元開始*/
……
ENDFONT /*BDF字體文件結束標誌*/

1.2.3 QPF字體簡介
    QPF格式的字型檔是僅用於QT/Embedded的不可縮放的字體,在程序運行過程中,對TTF格式的字體,在第一次裝入使用時,都要以給定的字體大小進行處理;而對於BDF字體,當其使用時,所有字體都必須被處理;而對於QPF字體,均以相同格式的存儲。所以在字體顯示時,Qt只要讀取字體,做相應分析,然後顯示就完成了,這樣進一步減少了對RAM資源的浪費。QPF字體是基於UNICODE編碼的,這為QT/Embedded良好的可移植性奠定了基礎。有關QPF更詳細的資料可以查閱參考文獻[5]。

2 如何從TTF字體文件轉成QPF字體文件
2.1 把TTF轉換成BDF
    儘管不推薦使用TTF格式的字型檔,但由於TTF格式的字型檔可以轉換成任意大小的BDF字型檔,而可以找到的BDF字型檔都是固定大小的,因此在實際製作QPF字體文件時,還是需要TTF格式的字型檔。把TTF轉換成BDF的方法如下:
./ttf2bdf source.ttf -p yourSize -o destination.bdf
    即利用軟體ttf2bdf可以把源文件source.ttf轉換成大小為yourSize的BDF格式的文件destination.bdf。那在程序內部是如何實現將TTF轉成BDF的呢?由2.2.1和2.2.2的介紹,並且查閱參考文獻[3],可以知道TTF的內部存儲結構。其中最核心的部分是TTF文件格式中的12個位元組的文件表:表目錄按tag以升序排列。

Type Name Description
ULONG  tag 4位元組的標識
ULONG checkSum 表中的CheckSum
ULONG offset TrueType font文件的起始偏移量Offset
ULONG length 表長


    還有一個有關Offset表的信息,包括版本號,表的數量,查找範圍。入口選擇,轉換範圍。
    通過操作文件表,將描述表中的數據取出來,按照BDF字體所定義的格式寫入,就可以生成對應的字體。比如,可以給出一小段c語言程序,此程序用於計算當前CheckSum的位置。
ULONG
CalcTableChecksum(ULONG *Table,ULONG Length)
{
ULONG Sum = 0L;
ULONG *Endptr=Table+((Length+3)& ~3)/sizeof(ULONG);
while(Table<EndPtr)
Sum += *Table++;
return Sum;
}
    利用此程序可以將每個字體的信息分開,並將每個字體信息從文件中取出來,對每個字體進行操作。在從TTF轉到BDF過程中,僅通過使用WINDOW的函數是很不方便的,最方便的辦法是使用c語言對字體進行操作。我在此列出轉換過程中最重要的幾個值:PIXEL_SIZE,POINT_SIZE,RESOLUTION_X,RESOLUTION_Y,FONT_DESCENT,FONT_ASCENT,SWIDTH,DWIDTH,BBX。這些值決定著最後生成的BDF字體與TTF字體的失真度,因為TTF是可縮放的,而BDF是固定大小的,所以在轉換過程中一定會出現失真的情況。

2.2 對得到的BDF文件進行調整
    由於從軟體xmbdfed里得到的三個字型檔不符合系統的要求,因此需要手動對其進行一些調整,其它方法得到的BDF文件不需要進行調整。
直接從xmbdfed里得到的字型檔是按照GB2312-80.0進行編碼的,因此首先要將其轉換成符合UNICODE編碼,這需要用到我手動寫的一個程序gb2unieode,把源文件拷貝到gb2unicode程序的目錄下,將其名字改為hanzist24a.txt(程序的要求,也可以不改名字而修改程序里源文件的名字再重新編譯),然後運行./change之後,就完成了,因為QT中因現成的轉換函數可以調用,在此我不想多說關於用程序轉換的代碼。因為有一種更簡單的方法,即在Word中打開GB字型檔。然後另存為UNICODE字型檔文件就行了。
    等待該命令執行完后(注意需要的時間比較長),對所生成的文件dest.txt進行排序,方法如下:把dest.txt的名字改為dest.bdf(只要後綴名為bdf就行);然後運行軟體xmbdfed,用其打開該文件(xmbdfed只能直接打開後綴明為bdf的文件),另存為yourname.bdf即可。排完序后需要手
動修改處理yourname.bdf。
    由上面介紹的BDF字體格式,現在對轉換得到的BDF字體文件進行如下手工處理:先刪除行說明屬性默認的字元的行DEFAULT_CHAR 8481,因為從GB2312轉換成UNICODE后,編碼為8481的字元已經不存在了,如果不刪除該行,運行時會出現段錯誤。然後刪除那些存在於兩個16號字型檔但在標準GB2312中沒有的一些字模。標準GB2312中有7445個字模,而兩個16字型檔有7612個字模,多出來的那部分在用gb2unicode轉換的時候因為找不到相應的GB2312碼而沒有寫進dest.txt的字模開始行"STARTCHAR ****"。可以用xmbdfed打開,如果出錯則說明還有一些不完整的字模,還需要手動刪除這些不完整的字模,如果可以正確打開則說明目標文件已經是正確的。(24號字型檔不存在這個問題,因此不需要進行本項操作。)最後從其它大小相同的.bdf文件中拷貝編碼為20-7F(ASCII碼)和編碼為FE54(分號;)的字模到目標文件。

2.3 把TTF.BDF轉換成QPF
    從參考文獻[5]中可以知道QT提供的把TTF,BDF轉換成QPF的方法有兩種,一種是工具makeqpf,這個命令無論是在Pc機上還是在開發板上都沒有效果(但是QT的官方網站卻說是可以的,不知道為什麼,並且,也不是每個版本的QT都有makeqpf這個工具,還要說明的是,文獻[6]中說這個工具是可以的,不過我沒有試驗成功)。
    另一種是運行應用程序時加上選項-savefonts,如在開發板上運行應用程序的命令:./sulfur -qws -savefonts
    如果此時系統中/usr/qt/lib/fonts目錄下沒有QPF格式的字型檔而只有TTF或BDF格式的字型檔,對應的文件fontdir中只保留要轉換的文件的行,QT就會在運行時首先生成QPF格式的字型檔。儘管通過TTF字體也可以得到QPF字體,不過最好不要這樣做,因為失真太大。

3 總結
    經過本人對字型檔進行上述處理后,就可以在嵌入式開發板上顯示各種字體,只要找到給定TTF或BDF的字型檔,如果找不到BDF字型檔,可以找到字型檔,然後通過TTF2BDF這個程序來得到BDF字型檔。這樣在開發板上可以顯示行書,楷書等字體,並且字體顯示也很正常,不會出現大小不一致的問題。但是,本人認為,由於這是嵌入式開發,存儲資源非常有限,如果能進一步將字型檔縮小,只留下程序中所要用的漢字組成的字型檔就好了,這是需要下一步研究的方向。

參考文獻:
[1] http://jserv.Sayya.org/qtopia/doe/qte.txt
[2] http://www.Linuxfans.org/nuke/modules.php?name=Forums&file= viewtopic&t=82950&highlight=fonts.dir
[3] Microsoft Corporation. TTF Technical Specification Revision 1.66 November 1995.
[4] Windows 2000編程核心技術精解[M].中國水利水電出版社,2001.
[5] http://doc.Trolltech.com/3.0/emb-fonts.html
[6] 黃敬群.Qt/Embedded中文處理實戰[M]




[admin via 研發互助社區 ] 在嵌入式Linux及QT/Embedded-2.3.7下製作QPF字型檔已經有2274次圍觀

http://cocdig.com/docs/show-post-42299.html