ASCII字符点阵和汉字库点阵显⽰
字符编码⽅式有ASCII,GBK和Unicode等,ASCII编码⽅式⽤ 1 byte来表⽰⼀个字符,ASCII 码使⽤指定的7 位或8 位⼆进制数组合来表⽰128 或256 种可能的字符。标准ASCII 码也叫基础ASCII码,使⽤7 位⼆进制数来表⽰所有的⼤写和⼩写字母,数字0 到9、标点符号,以及在美式英语中使⽤的特殊控制字符。
GBK码⽤两个字节表⽰⼀个汉字。
Unicode码把全世界的字符与编码统⼀地对应起来,⼀个Unicode编码值唯⼀地对应着世界上的⼀个字符,例如Unicode编码值4E25,在世界各地都表⽰着汉字“严”。⽤多少个字节表⽰⼀个字符呢?它是不确定的,根据Unicode码的存储⽅式的不同⽽不同,有UTF-
8,Unicode big endian等存储⽅式。
点阵显⽰⽅式主要⽤来显⽰ASCII码字符的点阵和汉字库点阵。当然,freetype最终也是通过字体的点阵来显⽰,只是freetype获得点阵需要⼀个过程,⽽ASCII和汉字库点阵是现成的,根据ASCII码或GBK码在点阵数组或汉字库中直接获取字体的点阵。
ASCII码对应的字符最多就256个字符,可以⽤⼀个unsigned char类型点阵数组fontdata_8x16[]来实现所
有ASCII码字符的点阵形状,每⼀个字符的点阵由16个元素构成。即⼀个ASCII点阵在显⽰屏上的总像素数就是8*16=128个,是固定的,点阵的字体的⼤⼩,长*宽就是 8*16像素。对fontdata_8x16数组,当然不是由我们⾃⼰来⼀个⼀个字符地去实现它的点阵,那⼯程量将是⾮常⼤的,别⼈早实现好了,可到linux 3.4.2内核⽬录 drivers/video/console/font_8x16.c拷贝⼀份。
下⾯是fontdata_8x16[]数组的部分内容:
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
/
* 1 0x01 '^A' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x7e, /* 01111110 */
0x81, /* 10000001 */
0xa5, /* 10100101 */
0x81, /* 10000001 */
0x81, /* 10000001 */
0xbd, /* 10111101 */
0x99, /* 10011001 */
0x81, /* 10000001 */
0x81, /* 10000001 */
0x7e, /* 01111110 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
......
/* 65 0x41 'A' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x10, /* 00010000 */
0x38, /* 00111000 */
0x6c, /* 01101100 */
0xc6, /* 11000110 */
0xc6, /* 11000110 */
0xfe, /* 11111110 */
0xc6, /* 11000110 */
0xc6, /* 11000110 */
0xc6, /* 11000110 */
0xc6, /* 11000110 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
......
}
字符点阵的⾸地址索引值即为字符的ASCII码值,即可根据字符的ASCII码值得到字符点阵⾸地址,⾸地址为:fontdata_8x16[ASCII码值*16]的地址。如字符'^A',ASCII码值为1,索引值也为1,其点阵第⼀⾏为fontdata_8x16[1*16];字符‘A’的ASCII码值为65,索引值也为65,其点阵第⼀⾏为fontdata_8x16[65*16],也即字符‘A’由
fontdata_8x16[1040],fontdata_8x16[1041]......fontdata_8x16[1055] 共16个元素共同表⽰。
我们怎么通过数组元素的内容把字符在LCD上显⽰出来呢?
以‘A’字符为例,由于这些元素中的那些为1的位描绘了'A'的字形,每⼀位对应这⼀个像素,我们把所有位0的位⽤同⼀种颜⾊的像素显⽰,把所有为1的位⽤另⼀种颜⾊的像素显⽰,这样就在LCD上把'A'字符显⽰出来了。重点是能把每⼀个0或1,在LCD正确的位置上⽤不同的颜⾊描绘出来。
汉字库点阵与ASCII字符点阵原理⼀样,把所有汉字的字形点阵都预先设计好,获得要显⽰的汉字的点阵的内存⾸地址(或点阵⽂件中的位置),把内存的内容转换为RGB值后正确地写到framebuffer正确的对应位置上即可。只是这个汉字的点阵不是⽤数组来实现,⽤⽂件的形式来保存所有汉字的点阵,这个⽂件叫汉字库点阵⽂件,常⽤的⼀种实现是HZK16,这个汉字库⽂件实现的汉字点阵是16*16像素。根据GBK码在汉字库中检索汉字及汉字显⽰,在细节上与ASCII码有些区别,也不难,具体看我代码注释。
下⾯是⼀个ASCII码点阵和汉字库点阵的实例show_font.c:
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#define FONTDATAMAX 4096
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
/
* 1 0x01 '^A' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x7e, /* 01111110 */
0x81, /* 10000001 */
0xa5, /* 10100101 */
0x81, /* 10000001 */
0x81, /* 10000001 */
0xbd, /* 10111101 */
0x99, /* 10011001 */
0x81, /* 10000001 */
0x81, /* 10000001 */
0x7e, /* 01111110 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
......
}
int fd_fb;
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;
int fd_hzk16;
struct stat hzk_stat;//⽂件stat结构体
unsigned char *hzkmem;//把⽂件映射到hzkmem
/* color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;
/
/到对应的像素在内存中的位置,后⾯向其(*pen_8)写颜⾊值。
//通过pen_8来操作fbmem,实现LCD显⽰
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)
//不同的像素位数,颜⾊值格式不同。根据像素位数设置对应的颜⾊值格式,并写值。 {
case 8:
{
*pen_8 = color;//8位像素的话,颜⾊值直接赋给这个内存中即可。
*pen_8 = color;//8位像素的话,颜⾊值直接赋给这个内存中即可。
break;
}
case 16:
{
/* color : 0x00RRGGBB ,unsigned int 32位color的格式*/
/* 565 */
red  = (color >> 16) & 0xff;
//右移16位后剩下⾼16位,再&0xff,⼜剩下低8位。即取出32位color的16-23位  green = (color >> 8) & 0xff;//取出32color的8-15位
blue  = (color >> 0) & 0xff;//取出32color的0-7位
color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
//取出对应的组成565
*pen_16 = color;
break;
}
case 32:
{
*pen_32 = color;//32位像素也直接写即可。
break;
}
default:
{
printf("can't surport %dbpp\n", var.bits_per_pixel);
break;
}
}
}
void lcd_put_ascii(int x, int y, unsigned char c)
{
unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
//从fontdata_8x16[FONTDATAMAX]数组中获得点阵起始位置
int i, b;
unsigned char byte;
for (i = 0; i < 16; i++)//点阵有16⾏
{
byte = dots[i];
for (b = 7; b >= 0; b--)//点阵有8列
{
if (byte & (1<<b))//判断点阵中的各个点是否为1
{
/* show */
lcd_put_pixel(x+7-b, y+i, 0xffffff); /* ⽩ */
}
else
{
/* hide */
lcd_put_pixel(x+7-b, y+i, 0); /* ⿊ */
}
}
}
}
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++)//16⾏
for (j = 0; j < 2; j++)
{
{
byte = dots[i*2 + j];
for (b = 7; b >=0; b--)
{
if (byte & (1<<b))
{
/* show */
lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff); /* ⽩ */
}
else
{
/* hide */
lcd_put_pixel(x+j*8+7-b, y+i, 0); /* ⿊ */
}
}
}
}
ascii共有多少个字符int main(int argc, char **argv)
{
unsigned char str[] = "中";//汉字库起始位置+偏移值=点阵实际位置,
//这⾥的汉字库点阵是16*16的,意思是每⾏是16 bit,即2 Byte,总共16列。
//即⼀个汉字点阵的长度是2 byte *16= 32 Byte.
//偏移值就是(area * 94 + where)*32 ,⼀个区(area)有94个汉字,这是固定的。
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))
{
printf("can't get fix\n");
return -1;
}
line_width  = s * var.bits_per_pixel / 8;
//分辨率 * 每像素位数 /8 =xxx字节。⼀⾏多少字节。即line_width是⾏宽,是以字节为单位的。
pixel_width = var.bits_per_pixel / 8;  //每像素⼤⼩,字节为单位。
screen_size = s * s * var.bits_per_pixel / 8;
fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); if (fbmem == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
fd_hzk16 = open("HZK16", O_RDONLY);
if (fd_hzk16 < 0)
{
printf("can't open HZK16\n");
return -1;
}
if(fstat(fd_hzk16, &hzk_stat))

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。