Chinaunix首页 | 论坛 | 博客
  • 博客访问: 221049
  • 博文数量: 46
  • 博客积分: 2510
  • 博客等级: 少校
  • 技术积分: 320
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-11 13:48
文章分类

全部博文(46)

文章存档

2010年(1)

2009年(19)

2008年(26)

我的朋友

分类:

2008-07-14 22:03:02

要解决这个问题,首先需要了解汉字在计算机中是如何表示的。在计算机中英文可以使用 ASCII 码来表示,而汉字使用的是扩展 ASCII 码,并且使用两个扩展 ASCII 码来表示一个汉字。一个 ASCII 码使用一个字节表示,所谓扩展 ASCII 码,也就是 ASCII 码的最高位是1的 ASCII 码,简单的说就是码值大于等于 128 的 ASCII 码。一个汉字由两个扩展 ASCII 码组成,第一个扩展 ASCII 码用来存放区码,第二个扩展 ASCII 码用来存放位码。在 GB2312-80 标准中,将所有的汉字分为94个区,每个区有94个位可以存放94个汉字,形成了人们常说的区位码,这样总共就有 94*94=8836 个汉字。在点阵字库中,汉字点阵数据就是按照这个区位的顺序来存放的,也就是最先存放的是第一个区的汉字点阵数据,在每一个区中有是按照位的顺序来存放的。在汉字的内码中,汉字区位码的存放实在扩展 ASCII 基础上存放的,并且将区码和位码都加上了32,然后存放在两个扩展 ASCII 码中。具体的说就是:
    第一个扩展ASCII码 = 128+32 + 汉字区码
    第二个扩展ASCII吗 = 128+32 + 汉字位码
如果用char hz[2]来表示一个汉字,那么我可以计算出这个汉字的区位码为:
    区码 = hz[0] - 128 - 32 = hz[0] - 160
    位码 = hz[1] - 128 - 32 = hz[1] - 160。

    这样,我们可以根据区位码在文件中进行殉职了,寻址公式如下:
    汉字点阵数据在字库文件中的偏移 = ((区码-1) * 94 + 位码) * 一个点阵字模占用的字节数
在寻址以后,即可读取汉字的点阵数据到缓冲区进行显示了。以下是实现代码:

/* 输出一个汉字的函数 */
void  _draw_hz(char hz[2], FILE *fp, int x, int y, int w, int h, int color)
{
    char fontbuf[128];   /* 足够大的缓冲区,也可以动态分配 */
    int ch0 = (BYTE)hz[0]-0xA0;  /* 区码 */
    int ch1 = (BYTE)hz[1]-0xA0;  /* 位码 */

    /* 计算偏移 */
    long offset = (long)pf->_hz_buf_size * ((ch0 - 1) * 94 + ch1 - 1);

    fseek(fp, offset, SEEK_SET);              /* 进行寻址 */
    fread(fontbuf, 1, (w + 7) / 8 * h, fp);   /* 读入点阵数据 */
    _draw_model(fontbuf, w, h, x, y, color);  /* 绘制字模 */
}

    以上介绍完了中文点阵字库的原理,当然还有英文点阵字库了。英文点阵字库中单个点阵字模数据的存放方式与中文是一模一样的,也就是对我们所写的 _draw_model 函数同样可以使用到英文字库中。唯一不同的是对点阵字库的寻址上。英文使用的就是 ASCII 码,其码值是0到127,寻址公式为:
    英文点阵数据在英文点阵字库中的偏移 = 英文的ASCII码 * 一个英文字模占用的字节数

    可以看到,区分中英文的关键就是,一个字符是 ASCII 码还是扩展 ASCII 码,如果是 ASCII 码,其范围是0到127,这样是使用的英文字库,如果是扩展 ASCII 码,则与其后的另一个扩展 ASCII 码组成汉字内码,使用中文字库进行显示。只要正确区分 ASCII 码的类型并进行分别的处理,也就能实现中英文字符串的混合输出了。

另外,一个 m*n 的点阵所占用的字节数为 (m+7)/8*n
阅读(1585) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~