字符编码及字体显示

字符编码

计算机的所有信息都以二进制表示(二进制数字)
如:程序中puts(“Hello 你好”)
输出字符串信息,字符串在计算机里面保存为二进制数值48 65 6C 6C 57 C4E3 BAC3,计算机中传输的只是数字,显示为Hello 你好。
字符显示: 数字 -> 代表什么 ->显示为“什么”
      字符编码  字体文件

字符编码:用什么数字表示哪个字符
ASCII码-1个字节
GBK码-2个字节  ->编码方式不同,导致相同数字代表不同的字符->unicode码
BIG5码

Unicode只是一个符号集,它只规定了符号和二进制代码的对应关系,却没有规定二进制代码应该如何存储。UTF-8是Unicode的实现方式之一(UTF-16LE,UTF-16BE),是一种可变长的编码方式。优点:使用1~4个字节表示一个符号,根据不同的符号而变化字节长度,节省了空间。EE BB BF开头,每个字符以n个1开头,编码容错性高。
UTF-8的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

如:"abc中"以不同编码方式存储
ASSIC:61 62 63 D6D0
UTF-8:EF BB BF 61 62 63 E4 B8 AD
UTF-16BE(大端):FE FF 0061 0062 0063 4E2D
UTF-16LE(小端):FF FE 6100 6200 6300 2D4E
其中unicode码的“中”表示为E4 B8 AD,二进制为:
1110 0100,10 111000,10 101101
而这些剩下的组合起来表示unicode值:4E2D

字体文件:显示为什么,包含编码表和字体数据(根据编码表找到对应的字符点阵)。

源文件中字符串用不同的编码方式保存,会导致执行时打印结果不一样。
怎么解决?可以通过参数来设置,编译程序时,要指定字符集
man gcc , /charset 搜索到参数帮助
-finput-charset = charset 表示源文件的编码方式, 默认以UTF-8来解析 输入文件a.c中的字符串在电脑中保存的数值编码方式
-fexec-charset = charset 表示可执行程序里的字符以什么编码方式来表示,默认是UTF-8
gcc -o a a.c
gcc -finput-charset=GBK -fexec-charset=UTF-8 -o utf-8_2 ansi.c //指定输入字符集为GBK,指定输出字符集为UTF-8。

字体显示

注意:LCD的坐标系和笛卡尔坐标系是倒着的!坐标计算时要转换

int main(int argc, char **argv){
	unsigned char str[] = "中";
	
	fd_fb = open("/dev/fb0", O_RDWR);	//打开设备
	ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);  //获取LCD可变信息:x,y分辨率和bpp等
	ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix;	//获得LCD固定信息

	line_width  = var.xres * var.bits_per_pixel / 8;
	pixel_width = var.bits_per_pixel / 8;
	screen_size = var.xres * var.yres * var.bits_per_pixel / 8;	//屏幕大小
	fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);//参数:NULL,大小,可读可写,文件

	fd_hzk16 = open("HZK16", O_RDONLY);	//打开汉字库16
	fstat(fd_hzk16, &hzk_stat);	//获取文件统计信息
	hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);	//映射文件,当做内存使用
	
	memset(fbmem, 0, screen_size);	/* 清屏: 全部设为黑色 */
	lcd_put_ascii(var.xres/2, var.yres/2, 'A');	//在中间显示
	printf("chinese code: %02x %02x\n", str[0], str[1]);
	lcd_put_chinese(var.xres/2 + 8,  var.yres/2, str);
	return 0;	
}

显示字母

void lcd_put_ascii(int x, int y, unsigned char c){
	unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16]; //从点阵数组中找到点阵
	int i, b;
	unsigned char byte;
	for (i = 0; i < 16; i++){	//显示8X16的点阵
		byte = dots[i];
		for (b = 7; b >= 0; b--){
			if (byte & (1<<b))				
				lcd_put_pixel(x+7-b, y+i, 0xffffff); /* 白 *//* show */
			else				
				lcd_put_pixel(x+7-b, y+i, 0); /* 黑 *//* hide */
		}
	}
}

显示汉字
HZK16字库里16×16的汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。一个GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。
区码:区号(汉字的第一个字节)-0xa0 (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)
位码:位号(汉字的第二个字节)-0xa0
一个汉字占两个字节,前一个字节为该汉字的区号,后一个字节为该汉字的位号。每一个区有94个字符。
汉字在HZK16文件中的绝对偏移位置:offset=(94*(区码-1)+(位码-1))*32

void lcd_put_chinese(int x, int y, unsigned char *str){
	unsigned int area  = str[0] - 0xA1;	//区码
	unsigned int where = str[1] - 0xA1;	//位码
	unsigned char *dots = hzkmem + (area * 94 + where)*32; //字符在汉字库中位置
	unsigned char byte;
	int i, j, b;
	for (i = 0; i < 16; i++)	//16x16
		for (j = 0; j < 2; j++){	//两个字节
			byte = dots[i*2 + j];
			for (b = 7; b >=0; b--){
				if (byte & (1<<b))					
					lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff); /* 白 *//* show */
				else		
					lcd_put_pixel(x+j*8+7-b, y+i, 0); /* 黑 *//* hide */		
			}
		}
	}
}

像素显示

/* color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color){
	unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width; //计算出(x,y)在fbmem中的位置
	unsigned short *pen_16;	
	unsigned int *pen_32;	
	unsigned int red, green, blue;	
	pen_16 = (unsigned short *)pen_8;
	pen_32 = (unsigned int *)pen_8;
	switch (var.bits_per_pixel){	//lcd的bpp,
		case 8:{
			*pen_8 = color;
			break;
		}
		case 16:{	/* 红绿蓝565 */
			red   = (color >> 16) & 0xff;
			green = (color >> 8) & 0xff;
			blue  = (color >> 0) & 0xff;
			color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
			*pen_16 = color;
			break;
		}
		case 32:{
			*pen_32 = color;
			break;
		}
		default:{
			printf("can't surport %dbpp\n", var.bits_per_pixel);
			break;
		}
	}
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值