[Feature phone 系列]字符信息的显示和绘制原理

这里的内容,不属于完全原创,引用了比部分内容,由于之前整理的时间过早,所以没有记录出处,如有雷同请包涵.
1>首先必须有字库,这里只涉及点阵字库[不同国家,不同大小]
    因为点阵字库在嵌入式设备上使用最广。
    有点:方便开发,执行效率高;
    缺点:通用性差[不能对字体进行缩放等操作].
2>如何添加字库?
首先澄清一些概念:
字符:是各种文字和符号的总称,包括各个国家的文字,标点符号,图形符号,数字等.
字符集:是多个字符的集合,如:ASCII字符集,ISO8859字符集,GB2312-80字符集,BIG5字符集,GB18030字符
           集,Unicode字符集等.<字符的集合>
字符编码:规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”.
              当各个国家和地区在制订编码标准的时候,"字符的集合"和"编码"一般都是同时定制的.因此我们平常所说的"字  
              符集",比如:GB2312等,除了有"字符的集合"这层含义外,同时也包含了"编码"的含义.
内码:维基百科上解释,内码指的是"将资讯编码后,透过某种方式存储在特定的记忆装置时,装置内部的编码形式"。在不
        同的系统中,会有不同的内码。比如:GB2312字符集内定义的编码的含义[双字节,四字节],ASCII字符集单字节    
        编码.
Windows 操作系统上,记事本保存TXT格式的三个选项:
ANSI American National Standards Institute( ANSI ——美国国家标准学会),ASCII字符集[英文系统]/GB2312字符集[简体中文系统]
Unicode,
Unicode big endian,
UTF-8
    首先我们需要根据自己的平台[硬件平台无关,软件平台],当前支持哪种字符编码规范[或者说当前使用的是哪种]
    当前可供使用的字符集编码规范:
    1> ASCII用来表示英文字符的一种编码规范,每个字符占用一个byte宽度,因此它能表示的最大英文字符数是256.
        英文字符并没有这么多因此, 一般只用前128个(最高位为0),其中包括了控制字符、数字、大小写字母和其他一些符号.
           而最高位为1的另128个字符被成为“扩展ASCII”,一般用来存放英文的制表符、部分音标字符等等的一些其他符号,这种字符编
          码规范显然用来处理英文没有什么问题。(实际上也可以用来处理法文、德文等一些其他的西欧字符,但是不能和英文通用),但
          是面对中文、阿拉伯文之类复杂的文字,255个字符显然不够用.
     2>GB2312-80
           GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,
          
        ......
        

         占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE.
         由于上面的原因, 中文的文字编码规范叫做“GB2312-80”,它是和ASCII兼容的一种编码规范,其实就是利用扩展ASCII没有真正标准
          化这一点,把一个中文字符用两个扩展ASCII字符来表示.
          问题
           中文文字没有真正属于自己的编码,因为扩展ASCII码虽然没有真正的标准化,但是PC里的ASCII码还是有一个事实标准的
         (存放着英文制表符),所以很多软件利用这些符号来画表格。这样的软件用到中文系统中,这些表格符就会被误认作中文字,
         破坏版面。而且,统计中英文混合字符串中的字数,也是比较复杂的,我们必须判断一个ASCII码是否扩展,以及它的下一个
         ASCII是否扩展,然后才“猜”那可能是一个中文字。
          扩展问题
           GB2312是内地国家标准;Big5是台湾标准,而且同时和GB2312存在一些相同的编码.
           所以手机、MP3一般只支持GB2312.
---------------------------------------------------------------------
      当中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存,于是想到把那些ASCII码中127号之后的奇异符号们直接取消掉, 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。这种汉字方案叫做 "GB2312"。GB2312 是对 ASCII 的中文扩展。兼容ASCII。
       对于人名、古汉语等方面出现的罕用字,GB 2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现.
分区表示
GB 2312中对所收汉字进行了“分区”处理,每区含有94个汉字/符号。这种表示方式也称为区位码。
01-09区为特殊符号。
16-55区为一级汉字,按拼音排序。
56-87区为二级汉字,按部首/笔画排序。
10-15区及88-94区则未有编码。
举例来说,“啊”字是GB2312之中的第一个汉字,它的区位码就是1601。
字节结构
在使用GB2312的程序通常采用EUC[Extend Unix Code]储存方法,以便兼容于ASCII。浏览器编码表上的“GB2312”,通常都是指“EUC-CN”表示法。
每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”。
“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。
例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节)0xA1(第二个字节)储存。(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。

       3>Big5 
           同样由于第一个原因,TW自己也弄了一个标准:Big5其中和GB3212里面存在一些相同的编码.
       4>Unicode
            Unicode的学名"Universal   Multiple-Octet Coded Character Set",
            前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1
           兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。
           简称为UCS。UCS可以看作是"Unicode Character Set"的缩写.
           很过国家的语言都面临上面的问题,因此要解决这个问题,Unicode编码就诞生了。Unicode有两个标准:
            < UCS-2(Unicode-16),用2个字节为字符编码 Unicode Character Set
             以目前常用的UCS-2为例,它可以表示的字符数为2^16=65535,基本上可以容纳所有的欧美字符和绝大部分的亚洲字符。
             在Unicode里,所有的字符被一视同仁。汉字不再使用“两个扩展ASCII”,而是使用“1个Unicode”,注意,现在的汉字是
            “一个字符”了,于是,拆字、统计字数这些问题也就自然而然的解决了。
            问题:
            A.兼容ASCII编码
            由于Unicode诞生的时候不是所有的 系统都使用Unicode来处理字符,因此必须考虑这个严峻的问题: 和ASCII字符集之间的不兼容问题。
            ---- ASCII字符是单个字节的,比如“A”的ASCII是65。而Unicode是双字节的,比如“A”的Unicode是0065,这就造成了一个
                 非常大的问题:以前处理ASCII的那套机制不能被用来处理Unicode了
            B. C语言使用'\0'作为字符串结尾,而Unicode里恰恰有很多字符都有一个字节为0,这样一来,C语言的字符串函数将无法正常处
               理Unicode,除非把世界上所有用C写的程序以及他们所用的函数库全部换掉.
            < UCS-4(Unicode-32), 用4个字节为字符编码 >
              UCS-2、UCS-4、BMP[ Basic Multilingual Plane ]
              UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,
             最高位必须为0)编码。下面让我们做一些简单的数学游戏:
              UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位
              UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个
             字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同.
              group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。
             将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。
             而目前的UCS-4规范中还没有任何字符被分配在BMP之外.
      5> UTF= UCS Transformation Format
            要解决上面的问题,UTF诞生了, UCS转换格式,它是将Unicode编码规则和计算机的实际编码对应起来的一个规则。
            现在流行的UTF有2种:UTF-8和UTF-16.
            A.UTF-16:
                其中UTF-16和上面提到的Unicode本身的编码规范是一致的,因此不用再叙述.
            B.UTF-8:
                它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容.
                UTF-8有点类似于Haffman编码,它将Unicode编码为00000000-0000007F的字符,用单个字节来表示:
                00000080-000007FF的字符用两个字节表示
                00000800-0000FFFF的字符用3字节表示
                因为目前为止Unicode-16规范没有指定FFFF以上的字符,所以UTF-8最多是使用3个字节来表示一个字符。但理论上来说,
               UTF-8最多需要用6字节表示一个字符.
                在UTF-8里,英文字符仍然跟ASCII编码一样,因此原先的函数库可以继续使用。而中文的编码范围是在0080-07FF之间,
              因此是2个字节表示(但这两个字节和GB编码的两个字节是不同的),用专门的Unicode处理类可以对UTF编码进行处理.
            PS:
            在Unicode出来之前总共有三套中文编码标准:
             GB2312-80,是中国大陆使用的国家标准,其中一共编码了6763个常用简体汉字。Big5,是台湾使用的编码标准,编码了台湾使用
            的繁体汉字,大概有8千多个。HKSCS,是中国香港使用的编码标准,字体也是繁体,但跟Big5有所不同.
             这3套编码标准都采用了两个扩展ASCII的方法,因此,几套编码互不兼容,而且编码区间也各有不同。
            --------------------
             UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:
             UCS-2编码(16进制) UTF-8 字节流(二进制)
  0000 - 007F 0xxxxxxx
  0080 - 07FF 110xxxxx 10xxxxxx
  0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
            例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。
           将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,
           即E6 B1 89.
            UTF-16以16位为单元对UCS进行编码。对于小于0x10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不小于
           0x10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以认为
           UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题.
            UTF的字节序和BOM[ Byte Order Mark ]
            UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元
           的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这
           是“奎”还是“乙”?
            Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有
           点小聪明的想法:
            在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK   SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该
           出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO   WIDTH NO-BREAK SPACE"。
            这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符
           "ZERO WIDTH NO-BREAK SPACE"又被称作BOM.
           UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是
           EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB   BF开头的字节流,就知道这是UTF-8编码了.
            Windows就是使用BOM来标记文本文件的编码方式的.
        6> GBK
            1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符.
            国际上又制定了针对中文的统一字符集GBK和GB18030,其中GBK已经在Windows、Linux等多种操作系统中被实现.
            GBK兼容GB2312,并增加了大量不常用汉字,还加入了几乎所有的Big5中的繁体汉字。但是GBK中的繁体汉字和Big5中的几乎不兼容.
       7> GB18030
             GB18030相当于是GBK的超集,比GBK包含的字符更多。据我所知目前还没有操作系统直接支持GB18030.
             2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、
            维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求.
       8> HKSCS
            HKSCS,是中国香港使用的编码标准,字体也是繁体,但跟Big5有所不同.
     PS:
      big endian和little endian
      endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,
     还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian.
      字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,
     程序员设计了用于简体中文的GB2312和用于繁体中文的big5.
   
    其实任何平台上都是同样的过程:把font.c文件添加到对应的编译目录下就可以了。
   
3>系统编译好之后,运行时如何找到并正确显示出来对应的字符?
    the font use the unicode Character coding standard[字符编码规范].
    u4E00_4E5A_font.h  //Just include all font information from 0X4E00~0X4E5A.
 
    //The font information include:
     //Ex, 4E00 is the chinese character “一”
     bbw=16, bbh=16, bbx=0, bby=0, width=16
     //Comments: we can image the screen is big area, a font will take a rectangular
     //which have start coordination< x,y >, with and height.  the font are a series binary data which 1 is
     //showing   a point in current screen, 0 is showing nothing on the screen on the 16X16 screen erea.
0x0000, //16 bit size                                
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0xfffe,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,                                  
0x0000,
    u4E00_4E5A_font_offset.h  //Just include the value of a series font offset from 0X4E00~0X4E5A.
    // Ex,
       11904,      /* (0x4e00) */
       .....
       0              /* (0x4e5a) */ “乙”
    u4E00_4E5A_font_width.h  //Just include the value of a series font with
       16,   /* (0x4e00) */
       ......
        8     /* (0x4e5a) */    “乙”

---------------------------------------
    
T_FontBmInfo MMI_lcd_get_font_Bm_data(UINT16 wUnicode)
{
    UINT8 i = 0;
    INT32 wOffset = -1;
    INT32 wLocalOffset = -1;
    T_FontBmInfo tFontBmInfo;
    //Please add the detail comments at here!!
    for (i = 0;  g_tFontTable[i].bCodeType != 0xFF ; i++)
    {   //Please add the detail comments at here!!
        if (wUnicode >= g_tFontTable[i].bCodeStart && wUnicode <= g_tFontTable[i].bCodeEnd)
        {
            //Please add the detail comments at here!!
            wOffset = wUnicode - g_tFontTable[i].bCodeStart;
            if(g_tFontTable[i].bdwOffset[wOffset]) //check all table until find it.
            {
                break;
            }
            else
            {  //Please add the detail comments at here!!
                wOffset = -1;
            }
        }
	else
	{      //Please add the detail comments at here!!
		wOffset = -1;
	}
	
    }

    if (-1 == wOffset)
    {
        wOffset = 32;
        i = 0;
    }
    wLocalOffset = g_tFontTable[i].bdwOffset[wOffset]-g_tFontTable[i].bdwOffset[0];
    tFontBmInfo.bWidth = g_tFontTable[i].baWidth[wOffset];
    tFontBmInfo.pwFontBm = (UINT16 *)(&g_tFontTable[i].baFontRowData[wLocalOffset]);
    tFontBmInfo.bHeight = LCD_DEFAULT_FONT_HEIGHT;
    return tFontBmInfo;
}

4>把找到的字符显示到LCD屏幕上
    
void MMI_lcd_show_font_Bm(UINT16 wShowPos, T_FontBmInfo *ptFontBmInfo, UINT16 wFwdColor, UINT16 wBackColor)
{
    UINT8 bLoopHeight = 0;
    UINT8 bLoopWidth = 0;
    UINT8 i = 0;
    UINT16 wFontword;
    UINT16 wOffset = 0;
    UINT16 wLcdPointIndex = wShowPos;
    T_ALLCDRect tRect;

    //write font bitmap to lcd
    //Please add the detail comments at here!!
    for (bLoopHeight = 0; bLoopHeight < ptFontBmInfo->bHeight; bLoopHeight++)
    {   //Please add the detail comments at here!!
        for (bLoopWidth = 0; bLoopWidth < ptFontBmInfo->bWidth; bLoopWidth+=16)
        {   //Please add the detail comments at here!!
            wFontword = ptFontBmInfo->pwFontBm[wOffset];
            //Please add the detail comments at here!!
            for (i = 0; i < min(16, ptFontBmInfo->bWidth-bLoopWidth); i++)
            {  //Please add the detail comments at here!!
                if (((wLcdPointIndex) > (AL_PLCD_MAX_WIDTH * AL_PLCD_MAX_HEIGHT - 1)) || (wLcdPointIndex < 0))
                {
                    return;
                }
                if (wFontword & 0x8000)//Please add the detail comments at here!!
                {
                    g_waLcdPanelBuf[wLcdPointIndex] = wFwdColor;
                }
                else
                {
                    if (wFwdColor != wBackColor)
                    {
                        g_waLcdPanelBuf[wLcdPointIndex] = wBackColor;
                    }
                }
                wFontword <<= 1;
                wLcdPointIndex++;
            }// for (i = 0; i < min(16, ptFontBmInfo->bWidth-bLoopWidth); i++)
            wOffset++;
        }// for (bLoopWidth = 0; bLoopWidth < ptFontBmInfo->bWidth; bLoopWidth+=16)
        wLcdPointIndex += (AL_PLCD_MAX_WIDTH - ptFontBmInfo->bWidth);
    }// for (bLoopHeight = 0; bLoopHeight < ptFontBmInfo->bHeight; bLoopHeight++)
    //Please add the detail comments at here!!
    Mmi_lcd_request_refresh(tRect);
}   



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值