上一篇文章中我们介绍了在JavaME中实现Bitmap字体,但是要想通过Bitmap字体来显示中文几乎不太可能,除非你中文很少,也不介意这样做浪费时间,如果你想显示中文,又不想使用JavaME本身提供的字体,那么可以考虑使用点阵字,这就是本文将要给大家介绍的,如何在JavaME中使用点阵字库。
要在JavaME中使用点阵字,首先需要了解什么是点阵字,可以到各大百科互动网站找到相关介绍,这里就不耽误大家的时间了,点阵字实际上就是用画点的方式画出一个字。比如一个16*16的点阵字,它的每一个点占一位,一共是16*16,那么一个16的字所占大小是32byte。需要明白点阵字体优点是显示速度快,不像矢量字体需要计算;其最大的缺点是不能放大,一旦放大后就会发现文字边缘的锯齿,因此如果需要显示不同大小的点阵字,就需要准备不同大小的点阵字库。
点阵字库的制作方法也非常简单,网上有很多方法,本文我们选择使用HZK16字库来演示在JavaME如何使用点阵字库。
HZK16字库是符合GB2312标准的16× 16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。 我们知道一个GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。下面以汉字“我”为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到“我”在hzk16库中的位置就必须得到它的区码和位码。
区码:区号(汉字的第一个字节)-0xa0(因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)
位码:位号(汉字的第二个字节)-0xa0
这样我们就可以得到汉字在HZK16中的绝对偏移位置:
offset=(94*(区码-1)+(位码-1))*32
有了偏移地址就可以从HZK16中读取汉字编码了,下面我们就需要在JavaME中构建一个能够读取和显示点阵字库文字的类CustomFont,首先将我们准备的点阵字库HZK16放入工程的res文件夹中,并在CustomFont中标出该字库的路径和编码的等信息,如下代码所示。
public class CustomFont {
public final static int[] mask = { 128, 64, 32, 16, 8, 4, 2, 1 };
public final static String ZK_PATH = "/HZK16";
public final static String ENCODE = "GB2312";
//...
}
要读取一个汉字,我们首先要读取出汉字的区位码,通过如下代码可以读取出汉字的区位码:
/**
*获得文字的区位码
*/
protected int[] getByteCode(String str) {
int[] byteCode = new int[2];
try {
byte[] data = str.getBytes(ENCODE);
byteCode[0] = data[0] < 0 ? 256 + data[0] : data[0];
byteCode[1] = data[1] < 0 ? 256 + data[1] : data[1];
} catch (Exception ex) {
}
return byteCode;
}
然后通过区位码在字库中去查找文字信息,具体实现代码如下:
/**
*读取文字信息
*
* @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(ZK_PATH);
long offset = 32 * ((area - 1) * 94 + pos - 1);
in.skip(offset);
data = new byte[32];
in.read(data, 0, 32);
in.close();
} catch (Exception ex) {
}
return data;
}
能从字库中读取出点阵字的信息,下面就是将这些数据绘制出来即可,绘制函数如下所示。
/**
*绘制点阵中文汉字,gb2312,16字
*
* @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 byteCount;// 到点阵数据的第几个字节了
int lCount;// 控制列
g.setColor(color);
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) < 0x80) {// 非中文
g.drawString(str.substring(i, i + 1), x + (i << 4), y, 0);
continue;
}
code = getByteCode(str.substring(i, i + 1));
data = read(code[0], code[1]);
byteCount = 0;
for (int line = 0; line < 16; line++) {
lCount = 0;
for (int k = 0; k < 2; k++) {
for (int j = 0; j < 8; j++) {
if ((data[byteCount] & mask[j]) == mask[j]) {
g.drawLine(x + lCount + (i << 4), y + line, x
+ lCount + (i << 4), y + line);
}
lCount++;
}
byteCount++;
}
}
}
完成了点阵字的读取和绘制操作,下面我们通过:
mCustomFont.drawString(g, "测试点阵字库的显示!好看多了。", 0, 20, 0xff0000);
来测试该自定义点阵字库在JavaME中的使用 ,效果如下图所示。
显示肯定没有问题,但是我们开发出来的应用程序包也就随之增加了很大,主要包括HZK16字库文件,另外,在使用过程中所需要消耗的内存也增加,因为一个16*16的汉字就需要32个字节,因此,对于应用中汉字较少的,可以采用自己制作出一些特定的点阵字的数组,然后进行绘制,可以节省不少空间。
关于JavaME中字体的处理就介绍到这里,几乎介绍了JavaME中所有与字体相关的内容,足以解决JavaME中大部分文字显示的难题了。