中文字符的显示

    技术2022-05-11  13

    作者:xujiwei

     

     

    作为中国人,在写编程或系统的时候需要处理两种字符,一种是英文字符,一种是汉字。在实模式下,如果不处理汉字,而且想简便行事,那么也可以不处理英文字符,可以直接使用BIOS中断来显示,BIOS的显示中断INT 10H可以显示英文,已经内置(好像不太准:)了英文字符的点阵,所以就方便很多了。但是如果想自己处理字符的显示,不使用INT 10H,这样该怎么做呢?接下来我就讲讲字符编码以及显示的问题。

          这里我假定你的系统已经把显示模式切换到VGA12,在这个模式下,可以很方便的显示点阵字符,并且英文采用8x16点阵,汉字采用16x16点阵。

    1. 英文字符的显示

          英文字符是很简单的,因为它一个字符只有一个字节,这个字节的值就是这个字符的编码,将这个值乘以点阵里每个字符所占的字节数,就是这个字符在点阵里的偏移了。例如字母“A”,它的ASCII code是0x41,那么它在8x16点阵里的偏移就是0x41*(8*16/8)=1040,将1040加上英文字库的起始地址就可以得到字母“A”的点阵数据的起始地址了,然后我们就可以来显示“A”了。

    showA:

    ; 在1行1列显示“A”

    ; DS:SI 指向点阵数据

      push es    ; 保护ES

      mov ax,0xA000   ; 将ES指向显示缓冲区

      mov es,ax

      mov di,0    ; 指向1行1列

      mov cx,16 ; 高为16点

    .loop:

      movsb   ; 移动1个字节,英文字符宽为8点,在VGA12下就是1个字节,就是为什么在VGA12下显示方便了

      add di,79 ; 将指针指向下1行像素

      loop .loop  ; 继续下一行

      pop es ; 恢复ES

          总的来说,英文显示是比较容易的,在上一节里也有些提及。

    2. 汉字的显示

          作为我们自己的系统,当然要支持汉字显示了,对着满屏的英文多少有点不舒服:)

          汉字的编码有很多种,最常用的是GB2312,其他的还有……记不住,呵呵,大家自己去网上找找吧~~在GB2312总共收录了6000多个汉字及符号,被分为94个区,其中1-10区为符号,其他为汉字,在每个区里最多有94个汉字,这就是汉字编码的基础了,以前的区位码输入法就是这样来的。

          GB2312里每个汉字有2个字节,编码采用区位码,即第1个字节为区号,第2个字节为位号,为了与ASCII区分开,编码的每个字节的最高位即第7位都置1,即编码最小值为0x8080,但在编码中区号和位号都被加上了32,又因为区位都是以1开始而不是0,所以在应用时需要把编码减去0xA1A1才能用到计算偏移当中。

          更详细的内容可以参考系统地带开发资源里的“点阵汉字的显示”。

          好了,有了基本的知识,就可以开始实验了:)

         现在,假如我们要显示汉字“字”,那么先需要得到它的内码即编码,在存储时汉字就以字节存放,可以很方便地得到,例子如下:

    showZi:

    ; DS:SI  指向“字”的起始地址

    ; 假定字库载入到内存512K处,因为字库载入涉及到文件读取,所以这里就

    ; 假定字库已经载入到内存

      push ds    ; 保护段寄存器

      push es

      mov ax,[si]    ; 得到“字”的编码

      sub ax,0xA1A1  ; 减去0xA1A1,得到以0开始的区位号

      movzx bx,ah   ; 将区号以0扩展到BX

    ;===========================

      imul bx,94*32/16

    ; 这里将区号乘上94*32/4,是因为在实模式下,每个段只有64K,这对于汉字字库来说是太小了

    ; 所以我将汉字所在区的偏移放到段寄存器里,这样就可以显示所有汉字了

    ; 因为每个区有94个汉字,而点阵为16x16,所以每个汉字点阵数据占16*16/2=32个字节

    ; 再因为在实模式下,段寄存器放的值为物理地址右移4位,所以再除以16

    ;===========================

      add bx,0x8000 ; 字库在内存512K处

      mov ds,bx    ; 将数据段指向“字”所在区的点阵数据起始地址

      and ax,0xFF   ; 取位号

      imul ax,32  ; 每个汉字点阵占32个字节

      mov si,ax   ; 将SI指向“字”在区内偏移

      mov ax,0xA000

      mov es,ax    ; 将ES指向显示缓冲区

      mov cx,16  ; 16行像素

    .loopline:

      movsw    ; 汉字1行点阵点2个字节,这点跟英文显示中不同,需要注意

      add di,78 ; 同上

      loop .loopline

          好了,一个汉字就显示完毕了,具体应用中还需要处理英文中文的判断,这个可以通过判断编码的最高位是否为1的决定,还有字符串的结束等。


    最新回复(0)