LED点阵显示,有关特殊国别(阿拉伯,希伯来,泰文)字符排版和乱码问题解决

:最近公司的需求:做一个模拟LED屏的显示控件

中间各种曲折!此文做个记录,本来早就改写完的!各种原因前后隔了两个多月!

文章写的比较详细,熟悉的大佬可以跳过直接看代码!

PS:后面有完整的代码

正文:具体的读字库和点阵显示就不详细写了,可以参考  简书ForeverCy 大神的文章

传送门  https://www.jianshu.com/p/82301771b4eb

废话不多说,先看下直接读出来的数据显示,效果如下:






问题一:字符间隔太大!

分析原因:图中选择的是12字体大小!读取的12*12点阵字库数据,一个字符占12*2=24个字节,每个字符横向占2个字节也就是16位(绘制出来就是16个点),而英文字母实际上所占用的位置只有5-7位,所以字符间会有点大!当然不只是英文字符,其他字符也有一样的问题

解决思路:我们读取出来的字库字模数据最后是转换成二维布尔数组给显示控件绘制的,能动的就是这个数组了,所以将二维数组竖排取出判断,如果全是flase那就是没有数据的空格了!再做删除处理,然为了保证程序的适应性,防止存在占满16位的字符(显示出来的效果就是两个字符连在一起)!在删除间隔之前,需在字符之间再添加一位空格!

代码实现

step1:在字符间插入一位空格

   /**
     * 在字符间插入一位空格
     * */
    private void inserAemptyData(){
        Log.e("matrix",matrix[0].length+"");
        //初始化空值数组
        empty_data = new boolean[dots];
        for (int i=0;i<dots;i++) {
            empty_data[i] = false;
        }
        ArrayList<boolean[]> tem = new ArrayList<>();
        int position = -1;//更改后的数组当前下标
        int matrix_index=-1;//更改前的数组当前下标
        spaceIndexs = new ArrayList<>();
        ArabicIndexs = new ArrayList<>();
        for (int i=0;i<str.length();i++){
            String indexstr = str.substring(i, i + 1);
            String followstr = "";
            if (i<str.length()-1){
                followstr = str.substring(i+1,i+2);
            }
            boolean isSpace = indexstr.equals(" ");
            boolean isArabic = (!followstr.equals(""))&&ArabicUtils.isArbic(followstr)&&ArabicUtils.isArbic(indexstr);
            Log.e("indexstr>>>>",indexstr+"");
            for (int j=0;j<16;j++){//无论是12还是16字体 横排都是两个字节 16位
                position=position+1;
                matrix_index+=1;
                boolean[] indx = getstrbycolumn(matrix,matrix_index);//取一竖排
                if (isArabic){
                    ArabicIndexs.add(position);
                }
                if (isSpace){
                    spaceIndexs.add(position);
                }
                tem.add(position,indx);
                indx =null;
            }

//            连续的两个阿拉伯字符之间不需要插入空格
            if ((!followstr.equals(""))&&ArabicUtils.isArbic(followstr)&&ArabicUtils.isArbic(indexstr)){

            }else{
                Log.e("insert","1");
                tem.add(position,empty_data);
                position+=1;
            }
        }
PS:此函数中还考虑了空格(16位空格)和阿拉伯文(字符是连在一起的不需要间隔)

step2:取数组竖排判断并删除多余位空格(只留一个位)

    /*
    * 2017.12.25 添加
    * 消除多余空格
    * */
    private void fillMatrixEmpty(){
        //原则:判断boolean二维数组竖排是否出现连续为Flase的情况 如果是 便舍弃一个  否则添加到新的数组中
        //
        ArrayList<boolean[]> tem = new ArrayList<>();
        int space_number=0;
        for (int i = 0;i<matrix[0].length-1;i++){
            boolean[] indx = getstrbycolumn(matrix,i);//取一竖排
            boolean[] indy = getstrbycolumn(matrix,i+1);
            if (i==matrix[0].length-1&&!Arrays.equals(empty_data,indy)){//最后一排加进去
//                Log.e(i+">>>>","last_data");
                tem.add(indy);
            } else if (isSpaceVaules(i)&&isSpaceVaules(i+1)){//如果是空格的位置
                space_number+=1;

//                Log.e(i+">>>>","空格");
                if (space_number<5){//空格位置过长  只取4个点作为空格
                    tem.add(indx);
                }
                if (space_number==16){
                    space_number=0;
                }
            }
            else if (!isSpaceVaules(i)&&Arrays.equals(empty_data,indx)&&Arrays.equals(empty_data,indy)){//如果相邻两列都为空 不保存
//                Log.e(i+">>>>","empty_data");
            }
            else if (isArabicVaules(i)&&!isSpaceVaules(i)&&Arrays.equals(empty_data,indx)){//阿拉伯文 清除所有空格

            }
            else{
                //否则保存
//                Log.e(i+">>>>","data");
                tem.add(indx);
            }
            indx = null;
            indy = null;

        }
        boolean[][] temps1 = new boolean[matrix.length][tem.size()];//12*n
        for (int i = 0;i<tem.size();i++){
            boolean[] pos = tem.get(i);
            for (int j=0;j<matrix.length;j++){
                temps1[j][i] = pos[j];
            }
        }
        spaceIndexs=null;
        ArabicIndexs =null;
        matrix = temps1;
//        Log.e("matrix>>>>",matrix[0].length+"");
//        Log.e("tem>>>>",tem.size()+"");
//        Log.e("temps1>>>>",temps1[0].length+"");

    }

/**
     * 取某一竖排值
     * */
    public boolean[] getstrbycolumn(boolean[][] strarray, int column){
        int columnlength = strarray.length;
        boolean[] result = new boolean[strarray.length];
        for(int i=0;i<columnlength;i++) {
            result[i] = strarray[i][column];
        }
        return result;
    }
此时再看下效果,如下:







很明显间隔ok了,当然既然我们的主题是解决特殊国别的问题,先看下现在的效果如何

               

从左至右依次是:泰文,希伯来文,阿拉伯文

首先来看下泰文的问题:

问题二:字符上下标(估浅先这么叫)无法正常显示

原因分析:带上下标的文字根本不只是一个字符,但我们读取字模数据的时候是按照字符读取的,所以上下标字符肯定不会出现在对应字符的上标或者下标位置

解决思路:这里先看下 建国雄心 大佬新浪微博上的文章 泰文排版规则 可以先了解下泰文的基本字符知识,文章最后给出的那个解决方案,在下才疏学浅没有用得上!浪费了大佬的苦心,抱歉!那就另辟蹊径吧!


仔细看图中泰文的上标字符,其中区域1(暂时叫实部)是有用的,区域2(暂时叫虚部)是不需要的!再用字库软件打开字库文件看下:


所有的上下标的字符的虚部所占的位置都是一样的!既然这样,那在读取字库数据的时候就可以去掉虚部的部分,留下来的 实部再叠加到对应的字符上就行了,至于有哪些字符存在这种情况就需要一个个找了!我这里给我三种国别文字上下标字符的Unicode码,供参考:

//阿拉伯文上下标字符 unicode
    static final int[] ArabicSup_Subs = {0x64b,0x64c,0x64d,0x64e,0x64f,0x650,0x651,0x652,0x653,0x654,0x655,0x656,0x657,0x658,0x659,0x65a,0x65b,0x65c,0x65d,0x65e,
                                    0x6d6,0x6d7,0x6d8,0x6d9,0x6da,0x6db,0x6dc,
                                    0x6df,0x6e0,0x6e1,0x6e2,0x6e3,0x6e4,
                                    0x6e7,0x6e8,0x6ea,0x6eb,0x6ec
    };
//希伯来文上下标字符 unicode
    static final int[] HebrewSup_Subs = {0x591,0x592,0x593,0x594,0x595,0x596,0x597,0x598,0x599,0x59a,0x59b,0x59c,0x59d,0x59e,0x59f,0x5a0,
            0x5a1,0x5a2,0x5a3,0x5a4,0x5a5,0x5a6,0x5a7,0x5a8,0x5a9,0x5aa,0x5ab,0x5ac,0x5ad,0x5ae,0x5af,0x5b0,0x5b1,0x5b2,
            0x5b3,0x5b4,0x5b5,0x5b6,0x5b7,0x5b8,
            0x5bb,0x5bd,0x5bf,0x5c1,0x5c2,0x5c4,0x5c5,0x5c7
    };
    //泰文 上下标字符 unicode
    static final int[] ThaiSup_Subs = {0x0e31,0x0e34,0x0e35,0x0e36,0x0e37,0x0e38,0x0e39,0x0e3a,
                                        0x0e47,0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e
    };

PS:实际上阿拉伯文和希伯来文都存在这种上下标的现象,在这里就一并处理了!后面就不再累述了!

实现代码

step1:在读取字符字模数据时,去掉虚部并叠加到相应字符

//泰文上下标处理
                            if (ArabicUtils.isThai(subjectStr)&ArabicUtils.isThai(followStr)){//都为泰文字符
                                String follow2str = "";
                                if(index<str.length()-2){
                                    follow2str = str.substring(index+2,index+3);//泰文存在上下标同时存在的情况
                                }
                                if (!follow2str.equals("")&&ArabicUtils.isSup_SubThai(follow2str)&&ArabicUtils.isSup_SubThai(followStr)){
                                    byte[] data_follow2 = readAllZiMo(follow2str);
                                    if(data_follow2!=null){//后续字符数据不为空
                                        data = ArabicUtils.adminSup_SubThai(data_follow,data,dots);//将后面字符数据叠加到当前字符数据中
                                        data = ArabicUtils.adminSup_SubThai(data_follow2,data,dots);//将后面字符数据叠加到当前字符数据中
                                        index+=2;
                                        System.arraycopy(data, 0, dataResult, hasDealByte, data.length);
                                        hasDealByte = hasDealByte + data.length;
                                        System.arraycopy(replacedata, 0, dataResult, hasDealByte, replacedata.length);
                                        hasDealByte = hasDealByte + replacedata.length;
                                        System.arraycopy(replacedata, 0, dataResult, hasDealByte, replacedata.length);
                                        hasDealByte = hasDealByte + replacedata.length;
                                    }
                                }else if (ArabicUtils.isSup_SubThai(followStr)){//后面字符是否为上下标特殊字符
                                    if(data_follow!=null){//后续字符数据不为空
                                        data = ArabicUtils.adminSup_SubThai(data_follow,data,dots);//将后面字符数据叠加到当前字符数据中
                                        index+=1;
                                        System.arraycopy(data, 0, dataResult, hasDealByte, data.length);
                                        hasDealByte = hasDealByte + data.length;
                                        System.arraycopy(replacedata, 0, dataResult, hasDealByte, replacedata.length);
                                        hasDealByte = hasDealByte + replacedata.length;
                                    }
                                }else {
                                    System.arraycopy(data, 0, dataResult, hasDealByte, data.length);
                                    hasDealByte = hasDealByte + data.length;
                                }
                            }else {
                                System.arraycopy(data, 0, dataResult, hasDealByte, data.length);
                                hasDealByte = hasDealByte + data.length;
                            }
上面的代码中还处理了上下标同时存在的情况,处理前后对比图如下(12*12的点阵太小,16*16才能看除效果):

        

很明显 效果好很多了,上面只给出了泰文的处理方式,其他两种语言也都一样,这里我就不再贴了!如果需要完整代码,后面我会给出链接!

接下来,看阿拉伯文!


问题三:读取的字符混乱,而且反向相反

这里再次感谢 建国雄心的微博阿拉伯文排版规则   的解惑,

原因分析:引用文章中的一句话:“阿拉伯文的字母没有大写和小写的区分,但有印刷体和书写体的区别,而且除去دذ ر زو五个字母以外,其他23个字母都可以和后面的字母连写,而且因其在词头,词中和词尾的位置不同,字形也有所变化。阿拉伯文字的书写方向和中文不同,它是自右向左横着写”,也就是说,我们看到的是书写体,而字库文件是以印刷体保存的!也因为阿拉伯文是连字体的,所以直接读取出来的数据是不对的,需要重新变形成新的字符串再读取byte数据

解决思路:大神的微博中给出的重排规则,至于方向,如果是纯阿拉伯文字,直接反向就行了!但对于阿拉伯文和中文或者英文混输就需要另外判断了,

实现代码:

/**
    * 阿拉伯文排版
    * **/
    @NonNull
    public  static  String getArbicResult(String str){
        StringBuffer stringBuffer = new StringBuffer();
        for (int i=0;i<str.length();i++){
            //取连续的三个字符判断
            String substr = str.substring(i,i+1);
            String pre_sub ;
            String for_sub ;
            if (i==0){
                pre_sub = "";
            }else {
                pre_sub = str.substring(i-1,i);
            }

            if (i==str.length()-1){
                for_sub = "";
            }else {
                for_sub = str.substring(i+1,i+2);
            }
            if (isArbic(substr)){ //如果当前字符是阿拉伯文
                boolean ispreconnect = false ;
                boolean isforconnect  = false;
                //排版规则1:
                // 1.判断是否前连
                if (isArbic(pre_sub)&&!pre_sub.equals("")){//如果前一个字符是阿拉伯文,判断是否前连
                    ispreconnect = getIsPreConnect(pre_sub);

                }else{//不需要判断是否前连
                }
                //2.判断是否后连
                if (isArbic(for_sub)&&!for_sub.equals("")){//如果前一个字符是阿拉伯文,判断是否后连
                    isforconnect =  getIsForConnect(for_sub);
                }else{//不需要判断是否后连
                }
                //排版规则2:
                //以0x644开头,后面跟的是0x622,0x623,0x625,0x627
                if (Integer.parseInt(gbEncoding(substr),16)==0x0644&&!for_sub.equals("")) {//是0x0644
                    int fors = Integer.parseInt(gbEncoding(for_sub),16);
                    if (fors==0x0622||fors==0x0623||fors==0x0625||fors==0x0627){//后面接0x622,0x623,0x625,0x627
                        //这种情况处理后 两个字符合并成一个字符
                        //判断0x0644前一个字符是否前连
                        int temp = 0;
                        if (ispreconnect){//是前连 取arabic_specs数组 1
                            temp = 1;
                        }else{//不是 取arabic_specs数组 0
                            temp = 0;
                        }
                        switch (fors){
                            case 0x0622:
                                substr = arabic_specs[0][temp]+"";
                                break;
                            case 0x0623:
                                substr = arabic_specs[1][temp]+"";
                                break;
                            case 0x0625:
                                substr = arabic_specs[2][temp]+"";
                                break;
                            case 0x0627:
                                substr = arabic_specs[3][temp]+"";
                                break;
                        }
                        substr = getStrFromUniCode(substr);
                        i+=1;
                    }
                }else if (isNeedChange(substr)){//不是0x0644,并且在需要变形的数组中
                    int index = 0;
                    if(!isforconnect&&ispreconnect){//前连
                        index = 1;
                    }
                    if (isforconnect&&!ispreconnect){//后连
                        index = 2;
                    }

                    if (isforconnect&&ispreconnect){//中间
                        index = 3;
                    }
                    if (!isforconnect&&!ispreconnect){//独立
                        index = 4;
                    }
                        substr = getChangeReturn(substr,index);
                    substr = getStrFromUniCode(substr);

                }
            }else{//不是阿拉伯文

            }
            stringBuffer.append(substr);
        }
        return stringBuffer.toString();
    }
    /**
     *返回重排后的字符
     * */
    private static String getChangeReturn(String substr,int index) {
        int subunicode = Integer.parseInt(gbEncoding(substr),16);
        for (int i=0;i<Arbic_Position.length;i++){
            if (Arbic_Position[i][0]==subunicode){
                substr = "\\u"+Integer.toHexString(Arbic_Position[i][index]);
            }
    }
        return substr;
    }
    //阿拉伯文 当前字符是否需要重排
    private static boolean isNeedChange(String substr) {
        int subunicode = Integer.parseInt(gbEncoding(substr),16);
        for (int i=0;i<Arbic_Position.length;i++){
           if (Arbic_Position[i][0]==subunicode){
               return true;
           }
        }
        return false;
    }
    //后连
    private static boolean getIsForConnect(String for_sub) {
        int subunicode = Integer.parseInt(gbEncoding(for_sub),16);
        for (int i=0;i<theSet2.length;i++){
            if (theSet2[i]==subunicode){
                return true;
            }
        }
        return false;
    }
    //前连
    private static boolean getIsPreConnect(String pre_sub) {
        int subunicode = Integer.parseInt(gbEncoding(pre_sub),16);
        for (int i=0;i<theSet1.length;i++){
            if (theSet1[i]==subunicode){
                return true;
            }
        }
        return false;
    }

下面是需要的Unicode数组:

 //阿拉伯文中需要变形字符的unicode码 0x621-0x64a 集合中对应不同位置变形后的unicode码
    static final int[][] Arbic_Position = //former first, last, middle, alone
            {

                    {0x621, 0xfe80, 0xfe80, 0xfe80, 0xfe80},    // 0x621

                    {0x622, 0xfe82, 0xfe81, 0xfe82, 0xfe81},

                    { 0x623,0xfe84, 0xfe83, 0xfe84, 0xfe83},

                    { 0x624,0xfe86, 0xfe85, 0xfe86, 0xfe85},

                    {0x625, 0xfe88, 0xfe87, 0xfe88, 0xfe87},

                    { 0x626,0xfe8a, 0xfe8b, 0xfe8c, 0xfe89},

                    {0x627, 0xfe8e, 0xfe8d, 0xfe8e, 0xfe8d},

                    {0x628, 0xfe90, 0xfe91, 0xfe92, 0xfe8f},   // 0x628

                    { 0x629,0xfe94, 0xfe93, 0xfe94, 0xfe93},

                    {0x62a, 0xfe96, 0xfe97, 0xfe98, 0xfe95},   // 0x62A

                    {0x62b, 0xfe9a, 0xfe9b, 0xfe9c, 0xfe99},

                    {0x62c, 0xfe9e, 0xfe9f, 0xfea0, 0xfe9d},

                    {0x62d, 0xfea2, 0xfea3, 0xfea4, 0xfea1},

                    { 0x62e,0xfea6, 0xfea7, 0xfea8, 0xfea5},

                    {0x62f, 0xfeaa, 0xfea9, 0xfeaa, 0xfea9},

                    {0x630, 0xfeac, 0xfeab, 0xfeac, 0xfeab},   // 0x630

                    {0x631, 0xfeae, 0xfead, 0xfeae, 0xfead},

                    { 0x632,0xfeb0, 0xfeaf, 0xfeb0, 0xfeaf},

                    {0x633, 0xfeb2, 0xfeb3, 0xfeb4, 0xfeb1},

                    {0x634, 0xfeb6, 0xfeb7, 0xfeb8, 0xfeb5},

                    { 0x635,0xfeba, 0xfebb, 0xfebc, 0xfeb9},

                    {0x636, 0xfebe, 0xfebf, 0xfec0, 0xfebd},

                    {0x637, 0xfec2, 0xfec3, 0xfec4, 0xfec1},

                    {0x638, 0xfec6, 0xfec7, 0xfec8, 0xfec5},  // 0x638

                    {0x639, 0xfeca, 0xfecb, 0xfecc, 0xfec9},

                    { 0x63a,0xfece, 0xfecf, 0xfed0, 0xfecd},  //0x63A

                    {0x63b, 0x63b, 0x63b, 0x63b, 0x63b},

                    {0x63c, 0x63c, 0x63c, 0x63c, 0x63c},

                    {0x63d, 0x63d, 0x63d, 0x63d, 0x63d},

                    {0x63e, 0x63e, 0x63e, 0x6
  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
v1.11 (08/14/2012) 1. 增加注册年限选择。 v1.10 (06/26/2012) 1. 精简字库检索表。 2. 增加 GBK 字库输出。 3. 增加一种点阵数据存储格式(只存有效像素数据--not fixed, 不支持MBCS编码格式的中日韩), 对泰文,缅甸文等特殊语种显示非常便捷。 v1.09 (06/15/2012) 1. 增加输出 C 语言(数组) 字体格式。 V1.08 (05/17/2012) 1. 增加了两个版本(免费和试用版) 免费版 只对 16点阵有效。 试用版 对所有点阵有效,但是会缺部分字符。 2. 增加热键功能。 3. 修改了多国语言生成.h文件时,start 与 end 不匹配的bug。 4. 完善文档《GuiTool 使用说明》, 增加更多图解说明。 文档下载地址: http://ishare.iask.sina.com.cn/f/24472766.html v1.07 (05/02/2012) 1. 修改注册方式(改为文件)。 2. 增加bdf格式编码过滤功能,主要是为了支持 MTK 手机点阵字库。 3. 增加xp控件属性。 4. 增加扫描模式图解。 5. 修改了 bdf 2 bin 的一个bug。(选择输出位图时,会输出n个位图文件) 6. 修改了 BDF 文件中当字符显示宽度为0,存位图(所有字符存一张图片)失败的错误。 v1.06 (04/10/2012) 1. 增加系统字体支持,操作更简便,快捷。 枚举所有已安装系统字体,直接选择即可。 v1.05 (03/24/2012) Fontmaker(点阵字库) 1. 修正了字符对齐问题。 2. 增加了单个字符或多个字符输出成位图文件设定。 3. 完善了阿拉伯文字库(unicode 字库有效)。 4. 增加自定义字符功能(unicode 字库有效)。 Multi-language(多国语言) 1. 增加输出编码格式 (mbcs, utf16-lb, utf8)设置 2. 增加数组格式输出。 Image Manager(图像管理) 1. 该页为新增功能,支持图片图像的数据转换。主要应用在做产品logo图片方面。 V1.04 (07/16/2011) 1. 增加了一个字符串mbcs2unicode(内码转统一码)的功能。 (支持转:U16-LE, U16-BE, UTF8) V1.03 (07/05/2011) 1. 修改了 Example 中点阵字库解析源码,更加便于移植。(基本做到只需修改font_file.c 即可) 2. 修改了内码(MBCS)字库点阵信息读取的一个错误。 3. 增加了多语言支持(简中,英文),还有待完善。。。 V1.02 (07/01/2011) 1. FontMaker V2.03 a. 增加字符宽高比调节(HorR & VerR) b. 增加对*.ttc 字库的支持。 c. 增加bdf(*.bdf)文件格式转Simple Unicode编码格式的bin文件。 V1.01 (06/29/2011) 1. FontMaker V2.02 a. 增加了 Simple Unicode功能。(适合小字库) b. 增加了 “扫描方向及反显”设置。 2. Multi-Language V1.01 a. 修改了除 office 2000 外,其它不能支持的问题。 V1.00: (2007-2011) 1. 继承 FontMaker V2.01 的所有功能。 2. 增加了一个 Multi-Languge V1.00 的打包转换功能。 FontMaker 基本功能: 1.支持所有 windows 字符集:CP932(日文Shift-JIS)CP936(简体中文GBK)CP949(韩文)CP950(繁体中文 Big5),CP874(泰文),CP1250(中欧)CP1251(西里尔文),CP1252(西欧--"拉丁文I"),CP1253(希腊文), CP1254(土耳其文),CP1255(希伯来文),CP1256(阿拉伯文),CP1257(波罗的海文),CP1258(越南) 2.支持非等宽字库。 3.支持BIN,TXT,BMP,BDF 文件输出。 4.支持unicode字库输出,即可以做到在一个窗口中同时显示多国语言(文字) 5.支持单个字符编辑,预览(所见即所得)。 6.支持字库文件和输出路径记忆功能. 7. 支持从bdf格式转换自定义字库(bin文件)格式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值