ASCII码点阵字库的显示

 早在阅读tslib源代码时就注意到里面有font_8x8.c和font_8x16.c两个文件(后来才得知,它们来自Linux内核,具体目录是./drivers/video/console),它们包含了在屏幕上显示所需的所有字符(当然,是可打印字符),由此也看了一下tslib显示字符的代码。对将来在触摸屏上显示汉字有所帮助,——这是后话,暂且按下不提。
        上面所说的字符当然是ASCII码了,这种编码学过计算机的人可能会很熟悉,就不多讲了。本文所述者,就是通过ASCII码字库文件(网上有下载)和上面提到的其中之一的文件在终端上显示ASCII字符。这也为研究汉字显示打下基础(此为假话,写文章及做作所需也,实际上本文作者是先研究汉字显示再研究ASCII码显示的,勿模仿,切切)。
        本文中使用的字库是8x16,每个字符占用内存空间为16字节(后面不再提及),文中显示字符所做工作有下面几步(显示汉字也差不多,当然,这又是后话 ):
        1、打开字库文件(似乎是废话);
        2、计算出要打印的字符在字库文件中的偏移量(亦即网上所说的“寻址”);
        3、将这个偏移地址的数据(16字节)读取缓冲区中;
        4、显示这个缓冲区,为1者打印,为0者留空。(由于是在终端上显示,因此,可以使用如“#”、“*”等字符代替。)

        先说说如何找到某个字符在字库文件中的偏移量。字库里的字符排序是符合ASCII码顺序的,而每个字符占16字节,因此,将要打印的字符与16相乘,便得到这个字符在字库中的位置了,这个位置之后的16个字节的数据,就是这个字符了。比如大写字母“A”,十六进制是0x41(“A”还是十进制的65、八进制的101,其实都是一回事),它与0x10(十进制的16)相乘,得到0x410(计算机中使用十六进制十分方便,对于某些试题要求计算出某地址的十进制,我表示不理解,既不直观,又不方便,还容易出错)。使用十六进制编辑器(用UE相信会更方便些)查看这个偏移量,会发现有如下数据:
        $ hexdump -C ../HZK/ASC16 | grep 410
        00000410  00 00 10 38 6c c6 c6 fe  c6 c6 c6 c6 00 00 00 00  |...8l...........|


        所谓的字库,里面就是一些二进制数据。我们看看上面得到“A”的16个字节数据显示效果是怎样的。将上面的十六进制数据按二进制输出,一个字节一行,共占16行,如下:
        00000000
        00000000
        00010000
        00111000
        01101100
        11000110
        11000110
        11111110
        11000110
        11000110
        11000110
        11000110
        00000000
        00000000
        00000000
        00000000

        不直观,将出现0的地方留空,则变成如下形状(受网页影响,为美观起见进行调整,虽非实际中二进制所示,但形状是一致的):
                       
                       
              1      
            111     
          11  11   
        11      11
        11      11
        1111111
        11      11
        11      11
        11      11
        11      11  
                        
                        
                        
                       


        上面的便是传说中的“A”了。
        下面就用代码读取字库信息,并显示出来。完整代码如下:
        /***************************************************
         源代码文件编码:ANSI
         测试环境编码:zh_CN.UTF-8、zh_CN.gd2312
         * ************************************************/

        
        #include<stdio.h>
        #include<unistd.h>
        #include<sys/stat.h>
        #include<sys/types.h>
        #include<fcntl.h>
        #include<stdlib.h>
        #include<errno.h>
        #include<string.h>
        
        #ifdef DEBUG
        #define debug(fmt, ...) printf(fmt, #__VA_ARGS__)
        #else
        #define debug(fmt, ...)
        #endif
        
        
        void display_font_ascii(char *asc)
        {
                int i, j;
                debug("=================\n");
                for(i=0;i<16;i++)
                {
                        for(j=0;j<8;j++)
                        {
                                /* 逐位相与,为1者打印“*”,否则打印空格 */
                                if(asc & (0x80>>j))
                                        printf("*");
                                else
                                        printf(" ");
                        }
                        printf("\n");
                }
                debug("=================\n");
        }
        
        int main()
        {
                int i;
                unsigned char *p;
                unsigned char asciicode[] = "Ab";
                unsigned long offset;
                FILE *asc;
                char ascii[16];
        
                if((asc=fopen("ASC16","rb"))==NULL)
                {
                        perror("Can't Open ASC16");
                        exit(0);
                }
        
                /* ASCII字库文件 */
                for (i = 0; i < sizeof(asciicode)-1; i++)
                {
                        debug("%c %x\n", asciicode, asciicode); /* 打印数值 */
                        offset = asciicode*16;
                        debug("offset: %x\n", offset); /* 打印偏移量 */
                        fseek(asc,offset,SEEK_SET);
                        fread(ascii,16,1,asc);              /* 读取16字节 */
                        display_font_ascii(ascii);        /* 显示 */
                }
                fclose(asc);
        
                return 0;
        }


        由于是示意性代码,不必纠结于代码优化、代码风格等等问题。效果(同样进行了调整)如下:
        $ ./a.out            
                       
                       
              *      
            ***     
          **  **   
        **      **
        **      **
        *******
        **      **
        **      **
        **      **
        **      **
                       
                       
                       
                       
                       
                       
        ***         
          **         
          **         
          ****     
          **  **   
          **    **
          **    **
          **    **
          **    **
          *****   
                       
                       
                       
                        
         


        还有另一种方法,不读取字库,而是将所有的字符存放于某个数组中,比如像font_8x16.c文件中的fontdata_8x16数组。这里假设数组为ascii_code,那么,上面的代码只需修改一小部分,如下:
         for (i = 0; i < sizeof(asciicode)-1; i++)
         {
          debug("%c %x\n", asciicode, asciicode);
          offset = asciicode* 16; // 寻址
          p = ascii_code+offset;    // 查找字符在ascii_code数组中的偏移量
          debug("offset: %x\n", offset);
          display_font_ascii(p);
         }


        效果是一样的,所不同的是,前一种方法需要读取字库文件,后一种方法直接在内存中读取,完整的ASCII码占用空间为4KB。不过,ASCII中可打印的字符共96个(经过认真数那些可打印的字符,发现实际上是95个(即32号到126号),这里将127号算上了,具体的请搜索一下ASCII),占用空间为96*16,即1536字节。由于前面0x20(即32)个字符在显示中没有用到,因此是可以去掉的,这样一来,寻址方式又稍有不同,如下:
         for (i = 0; i < sizeof(asciicode)-1; i++)
         {
          debug("%c %x\n", asciicode, asciicode);
          offset = (asciicode - 0x20 )* 16; // 寻址
          p = ascii_code+offset;    // 查找字符在ascii_code数组中的偏移量
          debug("offset: %x\n", offset);
          display_font_ascii(p);
         }


        由于文中涉及知识、代码、字库文件都可以在网络上找到,因此文中就不提供下载了。

        资料:
        1、ASCII码字库,有多种形式,如8*16、8*12,名称为ASC12、ASC16,搜索一下就能找到。
        2、“字库数组”,可以在Linux内核源代码的./drivers/video/console目录下找到很多相关代码文件,如font_8x8.c、font_8x16.c、font_sun8x16.c等等。像font_8x16.c文件,代码中说是由cpi2fnt这个东西产生的,但搜索一下,没什么介绍,英文的又不想去看,对这个东西也就不了解了。
        3、可以搜索一下字库生成工具,用这些工具可以生成需要的字库。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值