从一个例子看ASCII点阵字库的应用原理
Linux内核中使用了内建的字库用于在framebuffer上显示ascii码字形信息,具体定义在文件
linux-stable/lib/fonts/fonts.c
通过fbcon=符号指定,
fbcon=font:VGA8x16
fbcon指定的信息在内核中会被以下函数解析:
内核的自形库数据组织结构:
以其中的font_vga_8x16为例:
其结构中内部指定了fontdata_8x16字库文件,字库文件中存储有字形信息:
下面以一个程序为例,来说明字形库的用法:
Framebuffer书写字符A的代码:
- #include <unistd.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <linux/fb.h>
- #include <sys/mman.h>
- #include <stdlib.h>
- #include <string.h>
-
- #define RED 0xF800
- #define YELLOW 0xFFE0
- #define BLUE 0x001F
- #define WHITE 0xFFFF
- #define BLACK 0x0000
-
- struct fb_var_screeninfo vinfo;
- static const unsigned char fontdata_8x16[16] = {
- 0x00,
- 0x00,
- 0x10,
- 0x38,
- 0x6c,
- 0xc6,
- 0xc6,
- 0xfe,
- 0xc6,
- 0xc6,
- 0xc6,
- 0xc6,
- 0x00,
- 0x00,
- 0x00,
- 0x00,
- };
- unsigned char *fbmem;
- /* color : 0x00RRGGBB */
- void lcd_put_pixel(int x, int y, unsigned int color)
- {
- unsigned char *pen_8 = fbmem+y*4 + x*vinfo.xres*4;
- //找到对应的像素在内存中的位置,后面向其(*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 (vinfo.bits_per_pixel)
- //不同的像素位数,颜色值格式不同。根据像素位数设置对应的颜色值格式,并写值。
- {
- case 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
", vinfo.bits_per_pixel);
- break;
- }
- }
- }
-
- void fill_color16(short *fb_addr, short bit_map, int psize)
- {
- int i;
- for(i=0; i<psize; i++) {
- *fb_addr = bit_map;
- fb_addr++;
- }
- }
-
- void lcd_put_ascii(int x, int y, unsigned char c)
- {
- c = 0;
- 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, 0xffff0000); /* 白 */
- }
- else
- {
- /* hide */
- lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
- }
- }
- }
- }
-
-
- int main ()
- {
- int fp=0;
- struct fb_fix_screeninfo finfo;
- long screensize=0;
- char *fbp = NULL, *test_fbp=NULL;
- int x = 0, y = 0;
- long location = 0;
- int i;
- int num = 5;
- int pix_size=0;
-
- fp = open("/dev/fb0", O_RDWR);
-
- if(fp < 0) {
- printf("Error : Can not open framebuffer device/n");
- exit(1);
- }
-
- if(ioctl(fp, FBIOGET_FSCREENINFO, &finfo)){
- printf("Error reading fixed information/n");
- exit(2);
- }
-
- if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)){
- printf("Error reading variable information/n");
- exit(3);
- }
-
- screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
-
- printf("The phy mem = 0x%%lx, total size = %%d(byte)
", finfo.smem_start, finfo.smem_len);
- printf("xres = %%d, yres = %%d, bits_per_pixel = %%d
", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
- printf("So the screensize = %%ld(byte), using %%ld frame
", screensize, finfo.smem_len/screensize);
- printf("vinfo.xoffset = %%d, vinfo.yoffset = %%d
", vinfo.xoffset, vinfo.yoffset);
- printf("vinfo.vmode is :%%d
", vinfo.vmode);
- printf("finfo.ypanstep is :%%d
", finfo.ypanstep);
- printf("vinfo.red.offset=0x%%x
", vinfo.red.offset);
- printf("vinfo.red.length=0x%%x
", vinfo.red.length);
- printf("vinfo.green.offset=0x%%x
", vinfo.green.offset);
- printf("vinfo.green.length=0x%%x
", vinfo.green.length);
- printf("vinfo.blue.offset=0x%%x
", vinfo.blue.offset);
- printf("vinfo.blue.length=0x%%x
", vinfo.blue.length);
- printf("vinfo.transp.offset=0x%%x
", vinfo.transp.offset);
- printf("vinfo.transp.length=0x%%x
", vinfo.transp.length);
-
-
- fbp =(char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);
- if ((int)fbp == -1)
- {
- printf ("Error: failed to map framebuffer device to memory.
");
- exit (4);
- }
- printf("Get virt mem = %%p
", fbp);
-
- fbmem = fbp;
-
- pix_size = vinfo.xres * vinfo.yres;
- /* using first frame, for FBIOPAN_DISPLAY
- * 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
- * 如果使用第二帧buffer -> vinfo.xoffset = 0; vinfo.yoffset = vinfo.yres;
- */
- vinfo.xoffset = 0;
- vinfo.yoffset = 0;
-
- int xx = 0, yy = 0;
- int j = 10;
-
- while(j--)
- {
- lcd_put_ascii(xx, yy, 1);
- xx = xx + 32;
- yy = yy + 32;
- }
-
- #if 0
- /* show color loop */
- while(num--) {
- printf("
drawing YELLOW......
");
- fill_color16((short *)fbp, YELLOW, pix_size);
- //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
- sleep(3);
-
- printf("
drawing BLUE......
");
- fill_color16((short *)fbp, BLUE, pix_size);
- //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
- sleep(3);
-
- printf("
drawing RED......
");
- fill_color16((short *)fbp, RED, pix_size);
- //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
- sleep(3);
- }
- #if 1
- /*这是你想画的点的位置坐标,(0,0)点在屏幕左上角*/
- x = 10;
- y = 10;
- location = x * (vinfo.bits_per_pixel / 8) + y * finfo.line_length;
- test_fbp = fbp + location;
- printf("draw line.......
");
- for(i = 0; i < (vinfo.xres - x); i++)
- *test_fbp++ = i+30;
-
- //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
- #endif
- #endif
-
- munmap(fbp, screensize); /*解除映射*/
-
- close (fp);
- return 0;
- }
结果:
至于为什么是躺着的,还不清楚原因。
结束!
推荐阅读