前言:開發J2ME過程中,我們會發現平臺本身提供的字體太小,而且樣式有限,嚴重影響游戲性的提高。不廢話,進入正題。
????? 首先,我們了解到:一個GB2312漢字是由兩個字節編碼的,范圍為A1A1~FEFE。A1-A9為符號區,B0到F7為漢字區。每一個區有94個字符(注意:這只是編碼的許可范圍,不一定都有字型對應,比如符號區就有很多編碼空白區域)。下面以漢字“我”為例,介紹如何在HZK16文件中找到它對應的32個字節的字模數據。
????? 前面說到一個漢字占兩個字節,這兩個中前一個字節為該漢字的區號,后一個字節為該字的位號。其中,每個區記錄94個漢字,位號為該字在該區中的位置。所以要找到“我”在hzk16庫中的位置就必須得到它的區碼和位碼。(為了區別使用了區碼和區號,其實是一個東西,別被我誤導了)
????? 區碼:區號(漢字的第一個字節)-0xa0 (因為漢字編碼是從0xa0區開始的,所以文件最前面就是從0xa0區開始,要算出相對區碼)
????? 位碼:位號(漢字的第二個字節)-0xa0
????? 這樣我們就可以得到漢字在HZK16中的絕對偏移位置: offset=(94*(區碼-1)+(位碼-1))*32
????? 注解:?
????? 1、區碼減1是因為數組是以0為開始而區號位號是以1為開始的?
????? 2、(94*(區號-1)+位號-1)是一個漢字字模占用的字節數
????? 3、最后乘以32是因為漢字庫文應從該位置起的32字節信息記錄該字的字模信息(前面提到一個漢字要有32個字節顯示)
?????? 代碼如下:
- import ?java.io.InputStream; ??
- ??
- import ?javax.microedition.lcdui.Graphics; ??
- ??
- ??
- /** ?
- ?*?點陣字,可以實現9*9,10*10,11*11,12*12,13*13,14*14,15*15,16*16等點陣字的繪制 ?
- ?*?@author?夜夢星辰 ?
- ?*?@email?babala_234@163.com ?
- ?*? ?
- ?*/ ??
- public ? class ?RasterFont?{ ??
- ???? public ? final ? static ?String?ENCODE?=? "GB2312" ; ??
- ??
- ???? private ?String?fontFileName;???? //點陣字文件名 ??
- ???? private ? int ?diameter;??????????? //字大小,支持9-16 ??
- ??
- ???? /**?Creates?a?new?instance?of?CustomFont?*/ ??
- ???? public ?RasterFont(String?fontFileName, int ?diameter)?{ ??
- ???????? this .fontFileName?=?fontFileName; ??
- ???????? this .diameter=diameter; ??
- ????} ??
- ??
- ???? /** ?
- ?????*?繪制點陣中文漢字,gb2312 ?
- ?????*? ?
- ?????*?@param?g?????????畫筆 ?
- ?????*?@param?str???????需要繪制的文字 ?
- ?????*?@param?x?????????屏幕顯示位置x ?
- ?????*?@param?y?????????屏幕顯示位置y ?
- ?????*?@param?color?????文字顏色 ?
- ?????*? ?
- ?????*/ ??
- ???? protected ? void ?drawString(Graphics?g,?String?str,? int ?x,? int ?y,? int ?color)?{ ??
- ???????? byte []?data?=? null ; ??
- ???????? int []?code?=? null ; ??
- ???????? int ?interval;??? //字間間隔 ??
- ???????? int ?i16;???????? //兩字節一行,即16位 ??
- ????????g.setColor(color); ??
- ???????? for ?( int ?index?=? 0 ;?index?<?str.length();?index++)? ??
- ????????{ ??
- ????????????interval=index*diameter; ??
- ???????????? ??
- ???????????? if ?(str.charAt(index)?<? 0x80 )? //?非中文 ??
- ????????????{ ??
- ????????????????g.drawString(str.substring(index,?index?+? 1 ),?x+interval,?y,? 0 ); ??
- ????????????} ??
- ???????????? else ??
- ????????????{ ??
- ????????????????code?=?getByteCode(str.substring(index,?index?+? 1 )); ??
- ????????????????data?=?read(code[ 0 ],?code[ 1 ]); ??
- ???????????????? for ?( int ?line?=? 0 ;?line?<?diameter;?line++)? ??
- ????????????????{ ??
- ????????????????????i16=?data[line<< 1 ]& 0x000000ff ; ??
- ????????????????????i16?=?i16?<<? 8 ?|?(data[(line<< 1 )+ 1 ]& 0x000000ff );? //?16位整形值,注意先通過與運算轉為int ??
- ???????????????????? for ( int ?i= 0 ;i<diameter;i++) ??
- ????????????????????{ ??
- ???????????????????????? if ?((i16?&?( 0x8000 ?>>?i))?!=? 0 ){?????? //逐位測試:通過與1進行與運算 ??
- ????????????????????????????g.drawLine(x?+i+interval,?y?+?line,?x+i+interval,?y?+?line); ??
- ????????????????????????} ??
- ????????????????????} ??
- ????????????????} ??
- ????????????} ??
- ????????} ??
- ????} ??
- ??
- ???? /** ?
- ?????*?讀取文字信息 ?
- ?????*? ?
- ?????*?@param?areaCode??區碼 ?
- ?????*?@param?posCode???位碼 ?
- ?????*?@return??????文字數據 ?
- ?????*/ ??
- ???? protected ? byte []?read( int ?areaCode,? int ?posCode)?{ ??
- ???????? byte []?data?=? null ; ??
- ???????? try ?{ ??
- ???????????? int ?area?=?areaCode?-? 0xa0 ;? //?獲得真實區碼 ??
- ???????????? int ?pos?=?posCode?-? 0xa0 ;??? //?獲得真實位碼 ??
- ??
- ????????????InputStream?in?=?getClass().getResourceAsStream(fontFileName); ??
- ???????????? int ?bytePerLine=(diameter- 1 )?/ 8 + 1 ; ??
- ???????????? int ?bytePerFont=?bytePerLine*diameter; ??
- ???????????? long ?offset?=bytePerFont*((area?-? 1 )?*? 94 ?+?pos?-? 1 ); ??
- ????????????in.skip(offset); ??
- ????????????data?=? new ? byte [bytePerFont]; ??
- ????????????in.read(data,? 0 ,?bytePerFont); ??
- ????????????in.close(); ??
- ????????}? catch ?(Exception?ex)?{ ??
- ????????} ??
- ???????? return ?data; ??
- ????} ??
- ??
- ???? /** ?
- ?????*?獲得文字的區位碼 ?
- ?????*? ?
- ?????*?@param?str ?
- ?????*?@return?int[2] ?
- ?????*/ ??
- ???? protected ? int []?getByteCode(String?str)?{ ??
- ???????? int []?byteCode?=? new ? int [ 2 ]; ??
- ???????? try ?{ ??
- ???????????? byte []?data?=?str.getBytes(ENCODE); ??
- ????????????byteCode[ 0 ]?=?data[ 0 ]& 0x000000ff ; ??
- ????????????byteCode[ 1 ]?=?data[ 1 ]& 0x000000ff ; ??
- ????????}? catch ?(Exception?e)?{ ??
- ????????????e.printStackTrace(); ??
- ????????} ??
- ???????? return ?byteCode; ??
- ????} ??
- ??
- }??
import java.io.InputStream; import javax.microedition.lcdui.Graphics; /** * 點陣字,可以實現9*9,10*10,11*11,12*12,13*13,14*14,15*15,16*16等點陣字的繪制 * @author 夜夢星辰 * @email babala_234@163.com * */ public class RasterFont { public final static String ENCODE = "GB2312"; private String fontFileName; //點陣字文件名 private int diameter; //字大小,支持9-16 /** Creates a new instance of CustomFont */ public RasterFont(String fontFileName,int diameter) { this.fontFileName = fontFileName; this.diameter=diameter; } /** * 繪制點陣中文漢字,gb2312 * * @param g 畫筆 * @param str 需要繪制的文字 * @param x 屏幕顯示位置x * @param y 屏幕顯示位置y * @param color 文字顏色 * */ protected void drawString(Graphics g, String str, int x, int y, int color) { byte[] data = null; int[] code = null; int interval; //字間間隔 int i16; //兩字節一行,即16位 g.setColor(color); for (int index = 0; index < str.length(); index++) { interval=index*diameter; if (str.charAt(index) < 0x80) // 非中文 { g.drawString(str.substring(index, index + 1), x+interval, y, 0); } else { code = getByteCode(str.substring(index, index + 1)); data = read(code[0], code[1]); for (int line = 0; line < diameter; line++) { i16= data[line<<1]&0x000000ff; i16 = i16 << 8 | (data[(line<<1)+1]&0x000000ff); // 16位整形值,注意先通過與運算轉為int for(int i=0;i<diameter;i++) { if ((i16 & (0x8000 >> i)) != 0){ //逐位測試:通過與1進行與運算 g.drawLine(x +i+interval, y + line, x+i+interval, y + line); } } } } } } /** * 讀取文字信息 * * @param areaCode 區碼 * @param posCode 位碼 * @return 文字數據 */ protected byte[] read(int areaCode, int posCode) { byte[] data = null; try { int area = areaCode - 0xa0; // 獲得真實區碼 int pos = posCode - 0xa0; // 獲得真實位碼 InputStream in = getClass().getResourceAsStream(fontFileName); int bytePerLine=(diameter-1) /8+1; int bytePerFont= bytePerLine*diameter; long offset =bytePerFont*((area - 1) * 94 + pos - 1); in.skip(offset); data = new byte[bytePerFont]; in.read(data, 0, bytePerFont); in.close(); } catch (Exception ex) { } return data; } /** * 獲得文字的區位碼 * * @param str * @return int[2] */ protected int[] getByteCode(String str) { int[] byteCode = new int[2]; try { byte[] data = str.getBytes(ENCODE); byteCode[0] = data[0]&0x000000ff; byteCode[1] = data[1]&0x000000ff; } catch (Exception e) { e.printStackTrace(); } return byteCode; } }
???? 另外,經過測試,我發現如果采用稀疏矩陣來保存點陣圖可以節省不少內存,請大家看看以下是HZK16的統計數據:
統計結果:零位有:1538534,非零位有:602394,總位數為:2140928,非零位占百分比:0.28
?
分析:
1個字占的位數是2^8=256位
?如果轉為稀疏矩陣的話,則占的位數為2*0.28*2^8≈144位
?可以節省到56%(≈144/256)的內存
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
