使用HZK16字库文件提取文字并显示到OLED显示屏上(Java Android实现)

最近在做要把文字(英文、汉字)显示到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;
    }

需要注意的是需要转为GBK编码,否则默认的unicode编码一个汉字所占的字节为3,会造成后边计算区码位码偏移量错误!


其次,根据字节信息获取区位码和偏移量:

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 数据,比如我们的就是共阴极列行式逆向输出。

关于取模方式可自己搜索,还有下边给出的取模软件有取模方式的演示,可以参考。不过个人认为他的那个演示逆向、顺向貌似反了!

   /*
    * 按照共阴极逆向式列行式取码方式(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);
    }

之前有先转为16进制,不过后来发现直接使用10进制就行。所以没必要转来转去了。

按照我们要求取出来的数据得到后就基本大功告成了。即文中的buffer10(意思是10进制的字符串),把这个字符串按”,“号截取再強转为int就是我们OLED显示屏需要的数据了。

这样我们就可以实现输入任意的汉字了!


用两张图简单说明:

这是从字库中取出的【我】的0 1 数据


使用HZK16字库文件提取文字并显示到OLED显示屏上(Java Android实现)_第1张图片


使用HZK16字库文件提取文字并显示到OLED显示屏上(Java Android实现)_第2张图片


感觉非常复杂自己也折腾了好久,但是感觉也没写出来什么东西!什么鬼!

如果有错误的地方,欢迎批评指正!谢谢!


附:

汉字取字模软件下载:

http://download.csdn.net/detail/breeze_wf/8905885

汉字字库下载地址:

http://download.csdn.net/detail/breeze_wf/8906059



你可能感兴趣的:(移动开发,Android)