好多年前写的东西了,翻出来玩玩,当时是为了在ARM板的触摸屏上显示汉字,用到了16x16的字模HZK16,它里面包含了很多汉字的字模,符合GB2312标准。
HZK16可以到这里下载http://download.csdn.net/detail/chenxupro/6349685
字模的使用以及原理可以参考这里http://www.chinaunix.net/old_jh/4/1064637.html
这里与其说显示汉字倒不如说“画”比较合适,其实就是按照字模在SDL_Surface上画点,组成汉字
下面的代码可以这样编译
gcc -o SDLDrawChinese SDLDrawChinese.c -I./SDL-1.2.15/include -lmingw32 -L./SDL-1.2.15/lib -lSDLmain -lSDL
代码如下
#include "SDL/SDL.h"
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static void quit(int rc);
Uint32 getpixel(SDL_Surface *surface, int x, int y);
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel);
void DrawOnePoint(SDL_Surface *screen,int x,int y);
void DrawChineseCharacter(SDL_Surface *screen,int ShowX,int ShowY,unsigned char InCode0,unsigned char InCode1);
int main(int argc, char *argv[])
{
SDL_Surface *screen;
/* Initialize the SDL library */
if( SDL_Init(SDL_INIT_VIDEO) < 0 )
{
fprintf(stderr,"Couldn't initialize SDL: %s\n", SDL_GetError());
exit(1);
}
/*
* Initialize the display in a 240x320 8-bit palettized mode,
* requesting a software surface
*/
screen = SDL_SetVideoMode(240, 320, 8, SDL_SWSURFACE);
if ( screen == NULL )
{
fprintf(stderr, "Couldn't set 320x240x8 video mode: %s\n",SDL_GetError());
exit(1);
}
DrawChineseCharacter(screen,30, 50, 0xD1, 0xAF);
SDL_Delay(4*1000);
SDL_Quit();
return 0;
}
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
static void quit(int rc)
{
SDL_Quit();
exit(rc);
}
/*
* Return the pixel value at (x, y)
* NOTE: The surface must be locked before calling this!
*/
Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp)
{
case 1:
return *p;
case 2:
return *(Uint16 *)p;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 16;
case 4:
return *(Uint32 *)p;
default:
return 0; /* shouldn't happen, but avoids warnings */
}
}
/*
* Set the pixel at (x, y) to the given value
* NOTE: The surface must be locked before calling this!
*/
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->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 DrawChineseCharacter(SDL_Surface *screen,int ShowX,int ShowY,unsigned char InCode0,unsigned char InCode1)
{
int x=ShowX;
int y=ShowY; // 显示位置设置
int i,j,k;
unsigned char incode[3]={0}; // 要读出的汉字
incode[0]=InCode0;
incode[1]=InCode1; // GBK内码
unsigned char qh,wh;
unsigned long offset;
FILE *HZK;
char mat[32];
// 占两个字节,取其区位号
qh=incode[0]-0xa0;
wh=incode[1]-0xa0;
offset=(94*(qh-1)+(wh-1))*32;
if((HZK=fopen("HZK16","rb"))==NULL)
{
printf("Can't Open hzk16\n");
exit(0);
}
fseek(HZK,offset,SEEK_SET);
fread(mat,32,1,HZK);
for(j=0;j<16;j++)
{
for(i=0;i<2;i++)
{
for(k=0;k<8;k++)
{
if(((mat[j*2+i]>>(7-k))&0x1)!=0)
{
DrawOnePoint(screen,x+8*i+k,y+j);
}
}
}
}
x+=30;
fclose(HZK);
}
void DrawOnePoint(SDL_Surface *screen,int x,int y)
{
Uint32 yellow;
/* Map the color yellow to this display (R=0xff, G=ff, B=0x00)
Note: If the display is palettized, you must set the palette first.
*/
yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0x00);
/* Lock the screen for direct access to the pixels */
if ( SDL_MUSTLOCK(screen) ) {
if ( SDL_LockSurface(screen) < 0 ) {
fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
return;
}
}
putpixel(screen, x, y, yellow);
if ( SDL_MUSTLOCK(screen) ) {
SDL_UnlockSurface(screen);
}
/* Update just the part of the display that we've changed */
SDL_UpdateRect(screen, x, y, 1, 1);
return;
}
效果如下