JAVA 汉字字库及字模提取程序实现
研究使用 LED 显示屏显示汉字时,编写了这个使用 Java 语言从汉字字库里提取所需要
的字模数据。实现这个程序主要玩成以下的步骤就行:
在这里先说说这个程序的核心部分就是汉字字库。汉字字库文件有很多,如:HZK16S
为宋体,HZK16F 为仿宋,HZK16H 为黑体,HZK16K 为楷体,HZK16Y 为幼圆,HZK16L 为隶书
等,本文采取的字库文件是 HZK16。
HZK16 字库是符合 GB2312 标准的 16×16 点阵字库,GB2312-80 支持的汉字有 6763 个,
符号 682 个。其中一级汉字有 3755 个,按声序排列,二级汉字有 3008 个,按偏旁部首排
列。同时 HZK16 是一个二进制文件,一般程序是难以打开的,不过 Java 有可以打开二进制
文 件 的 方 法 , 那 就 是 “FileInputStream ”。 当 然 Java 里 除 了 “FileInputStream ” 外 还 有
“FileReader”,但两者是有区别的,“FileInputStream”是用于读取二进制数据(以字节流方
式),“FileReader”是用于读取文本数据(以字符流形式,即 Unicode 字符)。所以本文采用
FileInputStream。
FileInputStream fileIn = new FileInputStream(HZK16);//打开 HZK16
文件
到这里已经 HZK16 文件,但如果要显示文件内容,内容是一连串整型数据(十进制),
这是因为 Java 系统自动把一个字节的二进制数据转为十进制,如果想要得到十六进制数据
还需要一些操作。
首先要定义一个一维数组 ZiMo16:
byte[] ZiMo16 = new byte[(int)file.length()];
ZiMo16,file.length()是获取 HZK16 文件的长度(大小)
file = new File(HZK16);
fileIn.read(ZiMo16); //把读取出来的数据存进 ZiMo16 数组里
//新建文件,这句是要放在前面
// 创 建 临 时 数 组
此时 ZiMo16 数组里已经有 HZK16 所有数据,这样就可以对其进行数据的截取,例如根
据输入汉字的区位码进行截取 32 个数据。
说到要得到输入文本的内容,就需要新建一个“Scanner”流:
Scanner scan = new Scanner(System.in); //新建文本输入流
System.out.println("请输入:");
String str;
str = scan.nextLine();
然后就是获取汉字的区位码:
add = getAddress(strarray[i]);
因为这里我为了节省代码长度,已经把获取区位码和获取首地址写成一个函数。
//输入汉字字符
//逐个汉字调用地址偏移量函数
public static int getAddress(String str0) throws IOException{
获取地址(偏移量)函数
//
int quCode = 0;
int weiCode = 0;
int Address = 0;
String quweiCode = "";//定义字符型区位码
byte[] chineseByte = str0.getBytes("GBK");//将输入的中文字
//定义区码
//定义位码
//定义偏移量地址
符转为 GBK 码(byte 类型)
for(int i = 0;i < chineseByte.length;i++){
int a
=Integer.parseInt(bytes2HexString(chineseByte[i]),16);
//把获得的 GBK 码转十六进制再转为十进制(因为 GBK 码是带符号,
需要转为不带符号整型才可以进行十六进制运算)
quweiCode = (a - 0xA0)+"";
switch(i){
case 0: quCode = Integer.parseInt(quweiCode);//获得
case 1: weiCode = Integer.parseInt(quweiCode);//获
整型区码
得整型位码
}
}
System.out.print("区位码是:");
System.out.print(quCode+"\t");
System.out.println(weiCode);
Address = 32 * ((quCode - 1) * 94 + (weiCode - 1));
System.out.print("地址是:");
System.out.println(Address);
return Address;
}
有了首地址就可以在 HZK16 提取输入汉字字符相应的字模数据。
//逐个汉字调用地址偏移量函数
add = getAddress(str);
System.out.println(str); //显示输入汉字的首地址
for(int i = 0;i < 32;i++){
ZiMo[i] = ZiMo16[add+i];
ZiMoStr[i] = hexByte(ZiMo[i]);
十六进制
System.out.print(ZiMoStr[i]+" "); //输出
//按要求截取 ZiMo16 里 32 个数据
//将 byte 型十进制转为 String
if((j+1)%10==0) System.out.println();//每十个数据就换行
}
ZiMo[i]是前面定义的一个数组。
byte ZiMo[] = new byte[32];//定义汉字存储字模二维数组
到这里已经完成边这个程序目的。
完整的程序实例(只限提取单个字符):
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.File;
public class transform {
public static String bytes2HexString(byte abyte) {
//将 byte
类型数据转为字符串
return bytes2HexString(new byte[] {abyte});
}
public static String bytes2HexString(byte[] bytes) { //将整
型数据转为十六进制字符型数据,String 是字符串类
String ret = "";
for(int i = 0;i < bytes.length;i++) {
String hex = Integer.toHexString(bytes[i]&0XFF);//将输
进的十进制数据转为十六进制字符型数据
if(hex.length()==1){
hex = "0"+hex;
}
ret += hex.toUpperCase();
//System.out.println(hex);
}
return ret;
}
private static String hexByte(byte abyte) {
//byte 类型的十
进制转为 String 类型的十六进制
String hexstr0 = "0"+Integer.toHexString((int)abyte);
String hexstr = hexstr0.substring(hexstr0.length()-2);
return hexstr;
}
public static String[] stringToStringArray(String str2) {
//
把 String 转 String[]
String[] strArry = new String[str2.length()];
for(int i = 0;i < str2.length();i++) {
strArry[i] = str2.substring(i,i+1);
}
return strArry;
}
public static int getAddress(String str0) throws
IOException{
//获取地址(偏移量)函数
int quCode = 0;
int weiCode = 0;
int Address = 0;
String quweiCode = "";//定义字符型区位码
byte[] chineseByte = str0.getBytes("GBK");//将输入的中文字
//定义区码
//定义位码
//定义偏移量地址
符转为 GBK 码(byte 类型)
for(int i = 0;i < chineseByte.length;i++){
int a
=Integer.parseInt(bytes2HexString(chineseByte[i]),16);
//把获得的 GBK 码转十六进制再转为十进制(因为 GBK 码是带符号,
需要转为不带符号整型才可以进行十六进制运算)
quweiCode = (a - 0xA0)+"";
switch(i){
case 0: quCode = Integer.parseInt(quweiCode);//获得
case 1: weiCode = Integer.parseInt(quweiCode);//获
整型区码
得整型位码
}
}
System.out.print("区位码是:");
System.out.print(quCode+"\t");
System.out.println(weiCode);
Address = 32 * ((quCode - 1) * 94 + (weiCode - 1));
System.out.print("地址是:");
System.out.println(Address);
return Address;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String fileName = "HZK16X";
//String fileName = "word.txt";
Scanner scan = new Scanner(System.in); //新建文本输入流
System.out.println("请输入:");
String str = scan.nextLine();
//输入汉字字
符
String[] strarray = new String[str.length()];
int add;
//byte hanzinum = getHanZiNum(str);
//定义地址位移偏量
//获取汉字字符串
长度;
//定义文件长度
long fileLength;
byte ZiMo[] = new byte[32];//定义汉字存储字模数组
String[] ZiMoStr = new String[32];
boolean bool = false;
File file = null;
try {
file = new File(fileName);
FileInputStream fileIn = new
//新建文件
FileInputStream(fileName);//打开 HZK16C 文件
bool = file.exists();
//判断文件是否存
在
if(bool){
fileLength = file.length();
int len = new Long(fileLength).intValue(); //把 long
byte[] ZiMo16 = new byte[(int)file.length()]; //创
型的 fileLength 转为 int 型的 len
建临时数组 ZiMo16
fileIn.read(ZiMo16);
add = getAddress(str);
移量函数
for(int i = 0; i < 32 ;i++){
ZiMo[i] = ZiMo16[add+i];
取 ZiMo16 里 32 个数据
型十进制转为 String 十六进制
ZiMoStr[i] = hexByte(ZiMo[i]);
//调用地址偏
//按要求截
//将 byte
System.out.print(ZiMoStr[i]+" "); //输出
if((i+1)%10==0) System.out.println();//每十
个数据就换行
}
System.out.println();
System.out.println("file length:"+fileLength);
}
scan.close();//关闭 Scanner 流
fileIn.close();//关闭 FileInputStream 流
} catch (Exception e)
{
e.printStackTrace();
}
}
}
如果想实现多个汉字字模数据提取,只要把装载 32 个字模数据的 ZiMo 数组该
为二维数组,再对源程序稍作修改便可。