[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,
...... ![[Feature phone 系列]字符信息的展示和绘制原理](http://img.reader8.net/uploadfile/jiaocheng/2014017/1438/2014011402383320825.jpg)
占用的码位是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)。
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.
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);}