正文

GBK点阵字体的显示2007-01-18 20:17:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/tonyhu/22670.html

分享到:

下文转自SOHU论坛   ,   软件开发   ->   C/C++版原著者为该版副版主     爱在远方  

一、汉字在计算机中的编码形式  
          我们都知道,在计算机中英文字符是用一个字节的ASCII码表示,该字节最高位一般用做奇偶校验,故实际是用7位码来代表128个字符的,但是对于众多的汉字,只有用两个字节才能表示,这样用两个字节来表示一个汉字的体制,国家制定了统一的标准,称为国标码。国标码规定,组成两个汉字代码的各字节最高位为0,这和英文字符表示方法相同,这就有可能把汉字的国标码看作两个ASCII码,为此又规定在计算机里表示汉字时,把最高位置1,表示该码是汉字,这种最高位为1的代码称为机器内的汉字代码,简称内码。计算机里汉字就是用内码表示的。  
          例如:“大”这个汉字,  
                  国标码   3473             00110100   01110011  
                  内码       B4F3             10110100   11110011  
          知道汉字在计算机里是用内码表示的以后,还需要知道具体汉字的结构。我国在1981年公布了《通讯用汉字字符集及其交换码标准》GB2312-80方案,里面规定了高频字、常用字、次常用字集合成汉字基本字符集(共6763个),再加上一些西文字母,希腊字母、日文字符、图形符号等一共700个。国家标准的汉字字符集在汉字操作系统中是以汉字库的形式提供的。汉字库规定,把字库分为94个区(区号),每个区有94个汉字(位号),这就是所谓的区位码(区位码第一字节是区号,第二字节是位号,因为知道了区位码就等于知道了该汉字在字库中的位置)。每个汉字在字库中是以点阵字模形式存储的,如一般采用16*16点阵形式,这样就需要32字节。在16*16点阵里,存1的点在显示时为一个亮点,存0的点不显示,这样汉字就显示出来了。简单写一下“大”这个字的字模:  
    0000001100000000  
    0000001100000000  
    0000001100000000  
    0000001100000010  
    1111111111111110  
    0000001100000000  
    0000001100000000  
    0000001100000000  
    0000001100000000  
    0000001110000000  
    0000011001000000  
    0000110000100000  
    0001100000010000  
    0001000000011000  
    0010000000001110  
    1100000000000100  
          这样当需要显示“大”这个汉字时,首先把这个字模取出,然后逐位显示,1显示0不显示,屏幕上就会出现“大”这个汉字。  
          那么我们怎么知道汉字的区位码呢?前面说了,汉字在计算机里是用内码存储的。内码和区位码的转换关系是(还以“大”为例):  
                  区号:B4-A0               位号:F3-A0  
          也就是说,把内码减去A0就是区位码,那么“大”这个汉字的区位码就出来了,是在14H区53H号,也就是第20区第83号。那么由于每个区有94个汉字,“大”这个字应该就是在汉字库的第(20-1)*94+(83-1)个汉字位置(每个汉字字模占32字节)。那么现在又要问了,内码又是怎样得到的呢?看下面的程序:  
                  main()  
                  {  
                          unsigned   char   *s="大";  
                          printf("%x,%x\n",s[0],s[1]);  
                          getch();  
                  }  
          运行程序发现,输出就是b4,f3。  
   
  二、西文方式下显示中文  
          说到这儿,大家应该有个思路了吧。要想显示汉字:  
              (1)   获得汉字内码  
              (2)   换算成区位码  
              (3)   在字库中取出该汉字的字模(共32字节)  
              (4)   1显示0不显示  

以下为自己写的小程序:

#include <iostream>
#include <SDL/SDL.h>

using namespace std;

char shape[32], in[256] = "中华人民共和国";
SDL_Surface *screen;
FILE *fp;

void
putpixel (SDL_Surface * img, int x, int y, Uint32 pixel)
{
 int bpp = img->format->BytesPerPixel;
 Uint8 *p = (Uint8 *) img->pixels + y * img->pitch + x * bpp;

 switch (bpp)
 {
 case 1:
  *p = pixel;
  break;
 case 2:
  *(Uint16 *) p = pixel;
  break;
 case 3:
  if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
  {
   p[0] = (pixel >> 16) & 0xff;
   p[1] = (pixel >> 8) & 0xff;
   p[2] = pixel & 0xff;
  }
  else
  {
   p[0] = pixel & 0xff;
   p[1] = (pixel >> 8) & 0xff;
   p[2] = (pixel >> 16) & 0xff;
  }
  break;
 case 4:
  *(Uint32 *) p = pixel;
  break;
 };
}

void
PutShape (unsigned char left, unsigned char right, int x, int y)
{
 unsigned char bits[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
 int pos = 32 * ((left - 161) * 94 + (right - 161)), i, j;
 Uint32 pixel = SDL_MapRGB (screen->format, 255, 255, 255);

 fseek (fp, pos, SEEK_SET);
 fread (shape, 32, 1, fp);
 for (i = 0; i < 16; i++)
  for (j = 0; j < 8; j++)
  {
   if (shape[2 * i] & bits[j])
    putpixel (screen, x + j, i + y, pixel);
   if (shape[2 * i + 1] & bits[j])
    putpixel (screen, x + j + 8, i + y, pixel);
  }
}

void
PutStr (int x, int y)
{
 int length = strlen (in), i;

 for (i = 0; i < length; i += 2)
 {
  PutShape (in[i], in[i + 1], x, y);
  x += 16;
  if (x > 640)
  {
   x = 0;
   y += 16;
  }
 }
}
void
loop ()
{
 SDL_Event event;
 int running = 1;

 while (running)
 {
  SDL_Delay (50);
  while (SDL_PollEvent (&event))
  {
   switch (event.type)
   {
   case SDL_QUIT:
    running = 0;
    break;
   };
  }

  SDL_UpdateRect (screen, 0, 0, 0, 0);
 }
}

int
main ()
{
 if (SDL_Init (SDL_INIT_VIDEO) < 0)
  fprintf (stderr, "init error\n");
 if ((screen =
   SDL_SetVideoMode (640, 480, 32,
         SDL_HWSURFACE | SDL_DOUBLEBUF)) == NULL)
  fprintf (stderr, "setvideomode error\n");
 if ((fp = fopen ("HZK16", "r")) == NULL)
  fprintf (stderr, "open HZK16 error\n");
 atexit (SDL_Quit);
 PutStr (32, 2);
 loop ();
 fclose (fp);
 return 0;
}

阅读(5824) | 评论(2)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册