编程小技巧

    返回首页    发表留言
本文作者:李德强
          技巧二十一:显示汉字
 
 

        今天跟大家分享的小技巧是关于显示汉字的。早期的计算机只能显示数字、英文字母和一些特定的符号,也就是ASCII码中所定义的128个字符,其中编号在32-126之间95个字符为可显示字符。这些字符在显示器上可以通过预先设置好的字符显示点阵来显示出来,这些ASCII都是8×16的点阵,也就是说一个可显字符需要16个字节(一个字节有8个bit位)来记录它们的点阵,95个可显字符需要1520个字节来存放。对于早期的计算机来说,可以直接烧录在显示设备的硬件芯片里,当显示设备收到ASCII码时,可根据其ASCII到这1520个字节的字库里找到对应的点阵并显示出来。这也就是ASCII码可显字符的显示过程。

        但对于汉字或其它非拉丁系文字来说,文字的数量很多。例如常用汉字大概有3000多个,由于汉字的方形特点,一个汉字需要16×16的点阵来表示,也就是说一个汉字需要32个字节来表示,3000个汉字就需要96000个字节来表示,大约需要94KB存储空间,而这样大小的存储空间在早期计算机里是非常庞大的。通常的做法是将这些点阵写入外存,然后在需要时将这些点阵字库载入到内存中。当需要显示一个汉字时,根据其编码找到这个汉字在字库中的位置,找到它的点阵数据,按16×16的点阵将这个汉字显示出来。GB2312-80标准中,将所有的汉字分为94个区,每个区有94个位可以存放94个汉字,形成了人们常说的区位码,这样总共就有 94×94=8836 个汉字。

        如果用char word[2]来表示一个汉字,那么我可以计算出这个汉字的区位码为:

区码 = word[0] - 128 - 32 = word[0] - 160 = word[0] - 0xA0
位码 = word[1] - 128 - 32 = word[1] - 160 = word[1] - 0xA0

        汉字点阵数据在字库文件中的偏移 = ((区码-1) × 94 + 位码) × 一个点阵字模占用的字节数(汉字为32 = 0x20)。我们以“问渠网”中的“问”字为例看一看如何显示这个汉字:

        “问”字在GB2312-80标准中的编码为0xCECA,于是它的区码为 0xCE - 0xA0 = 0x2E;它的位码为0xCA - 0xA0 = 0x2A。于是“问”字的点阵数据在字库文件中的偏移为(0x5e × (0x2E - 1) + 0x2A -1) × 0x20 = 0x215E0 = 136672于是我们就可以找到字库文件中这个偏移位置,并连续读出32个字节:

 

00100000 00000100 
00011011 11111110 
00001000 00000100 
01000000 00000100 
01000000 00100100 
01001111 11110100 
01001000 00100100 
01001000 00100100 
01001000 00100100 
01001000 00100100 
01001000 00100100 
01001111 11100100 
01001000 00100100 
01000000 00000100 
01000000 00010100 
01000000 00001000 

        这32个字节的二进制表示我们看起来不是很直观,1表示当前像素有效,0表示当前像素无效。我们可以使用一个点阵的方式来将这些二进制数显示成如下内容:

        也就是说我们在这32个字节的点阵数据中从高位向低位逐个读取,当其为1时显示一个点,当其为0是不显示,则汉字即可显示出来。由于显示设备的像素点尺寸很小,32×32的点阵通常只有小指甲大小,像素与像素之间也没有明显的分隔线,所以显示效果还是很好的。接下来我们通过读取汉字字库的点阵数据来显示“问渠网”这三个字,我们无需使用像素显示,只使用printf函数打印一个32 × 32的显示区域即可,代码如下:

 

#include <stdio.h>
#include <stdlib.h>

unsigned char *buff = NULL;

void word_init(const char *hzk_path)
{
	FILE* fp = fopen(hzk_path, "rb");
	if (fp == NULL)
	{
		return;
	}

	fseek(fp, 0L, SEEK_END);
	int size = ftell(fp);
	buff = malloc(size);
	if (buff == NULL)
	{
		goto _label_fp;
	}

	fseek(fp, 0L, SEEK_SET);
	fread(buff, sizeof(char), size, fp);

	_label_fp: ;
	fclose(fp);
}

void word_display(unsigned char *word)
{
	unsigned int offset = (0x5e * (unsigned int) (word[0] - 0xa0 - 1) + (word[1] - 0xa0 - 1)) * 0x20;
	for (int i = 0; i < 16; i++)
	{
		for (int j = 0; j < 2; j++)
		{
			for (int k = 7; k >= 0; k--)
			{
				printf("%s", (buff[offset + i * 2 + j] >> k) & 1 ? "* " : "  ");
			}
		}
		printf("\n");
	}
}

void string_display(char *string, int length)
{
	for (int i = 0; i < length; i++)
	{
		word_display(string + i * 2);
		printf("\n\n");
	}
}

int main(int argc, char *argv[])
{
	unsigned char str[6] = { 0xCE, 0xCA, 0xc7, 0xfe, 0xcd, 0xf8 };

	word_init("/data/document/sdata/important/WordDB/HZK16");
	string_display(str, 3);

	return 0;
}

        运行结果如下:

 



    *                     *     
      * *   * * * * * * * * *   
        *                 *     
  *                       *     
  *                 *     *     
  *     * * * * * * * *   *     
  *     *           *     *     
  *     *           *     *     
  *     *           *     *     
  *     *           *     *     
  *     *           *     *     
  *     * * * * * * *     *     
  *     *           *     *     
  *                       *     
  *                   *   *     
  *                     *       


    *       * * * * * * * *     
      *     *                   
  *         * * * * * * *       
    *       *           *       
        *   *           *       
      *     * * * * * * *       
  * *       *                   
    *       * * * * * * * *     
    *                           
                          *     
* * * * * * * * * * * * * * *   
          *   *   *             
        *     *     *           
      *       *       * * *     
  * *         *         *       
              *                 


                          *     
  * * * * * * * * * * * * * *   
  *                       *     
  *         *           * *     
  * *       *   *       * *     
  *   *   *       *   *   *     
  *   *   *       *   *   *     
  *     *           *     *     
  *     *           *     *     
  *   *   *       *   *   *     
  *   *     *     *     * *     
  * *       *   *       * *     
  * *         *           *     
  *         *             *     
  *                   *   *     
  *                     *       

 

        今天的小技巧你学会了吗?

    返回首页    返回顶部
  看不清?点击刷新

 

  Copyright © 2015-2023 问渠网 辽ICP备15013245号