最近在做要把文字(英文、汉字)显示到OLED显示屏上这方面内容,英文还好说,无非几十个字符,网上一搜也都有现成的方法。但汉字可就比较棘手了,首先要实现汉字的显示需要知道这个汉字的字模,这个我们可以很轻松地使用取字模软件获取(下边有下载地址),这样其实就可以了。棘手的是如果我要取得任意汉字的字模呢?不可能把所有字模的信息都生成吧!但是如果用到哪个生成哪个很明显扩展性不高也非常麻烦。这时我们就想到了使用字库,在字库中取出汉字的字模。于是问题来了,调取字库大多使用的是c语言,让我大Android(Java)情何以堪,不过字库毕竟是一个文件嘛,你在c语言能打开查找,我在java里自然也能打开查找喽。于是各种搜索资料,各种郁闷最终是成功了!中间遇到许多许多问题。趁现在思路比较清晰写下来,一是备忘,二也是说不定能帮到一样有这种问题困扰的各位。
首先OLED显示这块可以参考:
http://baike.baidu.com/link?url=suaEJ3tL3_kPWob7EfmrdMxelGUs0UouTOVZcnwIEuIk9MTRF0KXnasf5RU0CpxLW6mplLyYfdg0NLIOm6sLEa
或自行搜索。我们使用的是16x96 汉字为16x16的共阴极列行式逆向输出(输出方式很重要!)
HZK16(16x16汉字库)
(后边会附上字库下载地址,包含多种字体和大小的字库)
相关知识可参考下边连接或自行搜索
http://blog.twofei.com/505/
第一步就是通过字库(通过汉字的区码和位码得到偏移量)取出字模信息:
String s = "我的测试";
/*
* 循环取得每个汉字
* */
for (int i = 0; i < s.length(); i++) {
//获取汉字的信息
getHex(getByte(i, s));
}
public byte[] getByte(int i, String s) {
byte[] b_gbk = new byte[1];
String ss = s.substring(i, i + 1);
Log.i("hzkTest--->>>", ss);
try {
b_gbk = ss.getBytes("GBK");//必须转为GBK编码
Log.i("hzkTest--->>>", "Length=" + b_gbk.length);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return b_gbk;
}
其次,根据字节信息获取区位码和偏移量:
private void getHex(byte[] data) {
int size = 16;//字模的size
int sum = (size * size / 8);
byte iHigh, iLow;
iHigh = data[1];
iLow = data[0];
Log.i("hzkTest--->>>", "h=" + iHigh + ",l=" + iLow);
int IOffset;//偏移量
IOffset = (94 * (iLow + 256 - 161) + (iHigh + 256 - 161)) * sum;//+256防止byte值为负 汉字字模在字库中的偏移地址
Log.i("hzkTest--->>>", "IOffset=" + IOffset);
InputStream is = getResources().openRawResource(R.raw.hzk16);
try {
is.read(new byte[IOffset]);
byte iBuff[] = new byte[size * 2];//连续读入
is.read(iBuff);
getBinary(iBuff);
} catch (IOException e) {
e.printStackTrace();
}
}
其中raw为安卓res文件夹下的raw资源文件夹,把hzk16文件放到该文件夹下。
第三就是通过偏移量获取汉字的二进制数据:
/*
* 获取汉字的二进制数据
* */
private void getBinary(byte[] iBuff) {
StringBuffer stringBuffer=new StringBuffer();
int i, j, k;
for (i = 0; i < 16; i++) {
for (j = 0; j < 2; j++)
for (k = 0; k < 8; k++) {
if ((iBuff[i * 2 + j] & (0x80 >> k)) >= 1) {
stringBuffer.append("1");
} else {
stringBuffer.append("0");
}
}
}
Log.i("hzkTest--->>>", stringBuffer.toString());
//把 0 1 按照共阴极逆向式列行式取码方式输出
getRowLineReverseCode(stringBuffer);
}
关于取模方式可自己搜索,还有下边给出的取模软件有取模方式的演示,可以参考。不过个人认为他的那个演示逆向、顺向貌似反了!
/*
* 按照共阴极逆向式列行式取码方式(OLED显示方式)重新输出排列 0 1
* */
private void getRowLineReverseCode(StringBuffer sb) {
//得到前8行16列 128个
String pre128 = sb.substring(0, 128);
Log.i("hzkTest--->>>", "pre128--->>" + pre128);
//取出每16列的8个数据
for (int i = 0; i < 16; i++) {
StringBuffer sb1 = new StringBuffer();
for (int j = 112; j >=0; ) {
String s = pre128.substring(i + j, i + j + 1);
sb1.append(s);
j -= 16;
}
Log.i("hzkTest--->>>", "pre128--->>列行式2进制-->>" + sb1 + ",");
Log.i("hzkTest--->>>", "pre128--->>列行式10进制-->>" + Integer.parseInt(sb1.toString(),2) + ",");
Log.i("hzkTest--->>>", "pre128--->>列行式16进制-->>" + binaryString2hexString(sb1.toString()) + ",");
//直接使用十进制数据,不再转换16进制
buffer10.append(Integer.parseInt(sb1.toString(),2) + ",");
// hexBuffer.append(binaryString2hexString(sb1.toString())+",");
}
//得到后8行16列 128个
String las128 = sb.substring(128, 256);
Log.i("hzkTest--->>>", "las128--->>" + las128);
//取出每16列的8个数据
for (int i = 0; i < 16; i++) {
StringBuffer sb2 = new StringBuffer();
for (int j = 112; j >=0; ) {
String s = las128.substring(i + j, i + j + 1);
sb2.append(s);
j -= 16;
}
Log.i("hzkTest--->>>", "las128--->>列行式2进制-->>" + sb2 + ",");
Log.i("hzkTest--->>>", "las128--->>列行式16进制-->>" + binaryString2hexString(sb2.toString()) + ",");
//直接使用十进制数据,不再转换16进制
buffer10.append(Integer.parseInt(sb2.toString(),2) + ",");
// hexBuffer.append(binaryString2hexString(sb2.toString())+",");
}
// Log.i("hzkTest--->>>","HEX--->>>>"+hexBuffer);
Log.i("hzkTest--->>>","10---->>>>"+buffer10);
}
按照我们要求取出来的数据得到后就基本大功告成了。即文中的buffer10(意思是10进制的字符串),把这个字符串按”,“号截取再強转为int就是我们OLED显示屏需要的数据了。
这样我们就可以实现输入任意的汉字了!
用两张图简单说明:
这是从字库中取出的【我】的0 1 数据
感觉非常复杂自己也折腾了好久,但是感觉也没写出来什么东西!什么鬼!
如果有错误的地方,欢迎批评指正!谢谢!
附:
汉字取字模软件下载:
http://download.csdn.net/detail/breeze_wf/8905885
汉字字库下载地址:
http://download.csdn.net/detail/breeze_wf/8906059