WHCSRL 技术网

从一个例子看ASCII点阵字库的应用原理

Linux内核中使用了内建的字库用于在framebuffer上显示ascii码字形信息,具体定义在文件

linux-stable/lib/fonts/fonts.c

通过fbcon=符号指定,

fbcon=font:VGA8x16

fbcon指定的信息在内核中会被以下函数解析:

内核的自形库数据组织结构:

 以其中的font_vga_8x16为例:

 其结构中内部指定了fontdata_8x16字库文件,字库文件中存储有字形信息:

下面以一个程序为例,来说明字形库的用法: 

Framebuffer书写字符A的代码:

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <fcntl.h>
  4. #include <linux/fb.h>
  5. #include <sys/mman.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #define RED 0xF800
  9. #define YELLOW 0xFFE0
  10. #define BLUE 0x001F
  11. #define WHITE 0xFFFF
  12. #define BLACK 0x0000
  13. struct fb_var_screeninfo vinfo;
  14. static const unsigned char fontdata_8x16[16] = {
  15. 0x00,
  16. 0x00,
  17. 0x10,
  18. 0x38,
  19. 0x6c,
  20. 0xc6,
  21. 0xc6,
  22. 0xfe,
  23. 0xc6,
  24. 0xc6,
  25. 0xc6,
  26. 0xc6,
  27. 0x00,
  28. 0x00,
  29. 0x00,
  30. 0x00,
  31. };
  32. unsigned char *fbmem;
  33. /* color : 0x00RRGGBB */
  34. void lcd_put_pixel(int x, int y, unsigned int color)
  35. {
  36. unsigned char *pen_8 = fbmem+y*4 + x*vinfo.xres*4;
  37. //找到对应的像素在内存中的位置,后面向其(*pen_8)写颜色值。
  38. //通过pen_8来操作fbmem,实现LCD显示
  39. unsigned short *pen_16;
  40. unsigned int *pen_32;
  41. unsigned int red, green, blue;
  42. pen_16 = (unsigned short *)pen_8;
  43. pen_32 = (unsigned int *)pen_8;
  44. switch (vinfo.bits_per_pixel)
  45. //不同的像素位数,颜色值格式不同。根据像素位数设置对应的颜色值格式,并写值。
  46. {
  47. case 8:
  48. {
  49. *pen_8 = color;//8位像素的话,颜色值直接赋给这个内存中即可。
  50. break;
  51. }
  52. case 16:
  53. {
  54. /* color : 0x00RRGGBB ,unsigned int 32位color的格式*/
  55. /* 565 */
  56. red = (color >> 16) & 0xff;
  57. //右移16位后剩下高16位,再&0xff,又剩下低8位。即取出32位color的16-23位
  58. green = (color >> 8) & 0xff;//取出32color的8-15位
  59. blue = (color >> 0) & 0xff;//取出32color的0-7位
  60. color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
  61. //取出对应的组成565
  62. *pen_16 = color;
  63. break;
  64. }
  65. case 32:
  66. {
  67. *pen_32 = color;//32位像素也直接写即可。
  68. break;
  69. }
  70. default:
  71. {
  72. printf("can't surport %%dbpp ", vinfo.bits_per_pixel);
  73. break;
  74. }
  75. }
  76. }
  77. void fill_color16(short *fb_addr, short bit_map, int psize)
  78. {
  79. int i;
  80. for(i=0; i<psize; i++) {
  81. *fb_addr = bit_map;
  82. fb_addr++;
  83. }
  84. }
  85. void lcd_put_ascii(int x, int y, unsigned char c)
  86. {
  87. c = 0;
  88. unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
  89. //从fontdata_8x16[FONTDATAMAX]数组中获得点阵起始位置
  90. int i, b;
  91. unsigned char byte;
  92. for (i = 0; i < 16; i++)//点阵有16行
  93. {
  94. byte = dots[i];
  95. for (b = 7; b >= 0; b--)//点阵有8列
  96. {
  97. if (byte & (1<<b))//判断点阵中的各个点是否为1
  98. {
  99. /* show */
  100. lcd_put_pixel(x+7-b, y+i, 0xffff0000); /* 白 */
  101. }
  102. else
  103. {
  104. /* hide */
  105. lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
  106. }
  107. }
  108. }
  109. }
  110. int main ()
  111. {
  112. int fp=0;
  113. struct fb_fix_screeninfo finfo;
  114. long screensize=0;
  115. char *fbp = NULL, *test_fbp=NULL;
  116. int x = 0, y = 0;
  117. long location = 0;
  118. int i;
  119. int num = 5;
  120. int pix_size=0;
  121. fp = open("/dev/fb0", O_RDWR);
  122. if(fp < 0) {
  123. printf("Error : Can not open framebuffer device/n");
  124. exit(1);
  125. }
  126. if(ioctl(fp, FBIOGET_FSCREENINFO, &finfo)){
  127. printf("Error reading fixed information/n");
  128. exit(2);
  129. }
  130. if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)){
  131. printf("Error reading variable information/n");
  132. exit(3);
  133. }
  134. screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
  135. printf("The phy mem = 0x%%lx, total size = %%d(byte) ", finfo.smem_start, finfo.smem_len);
  136. printf("xres = %%d, yres = %%d, bits_per_pixel = %%d ", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
  137. printf("So the screensize = %%ld(byte), using %%ld frame ", screensize, finfo.smem_len/screensize);
  138. printf("vinfo.xoffset = %%d, vinfo.yoffset = %%d ", vinfo.xoffset, vinfo.yoffset);
  139. printf("vinfo.vmode is :%%d ", vinfo.vmode);
  140. printf("finfo.ypanstep is :%%d ", finfo.ypanstep);
  141. printf("vinfo.red.offset=0x%%x ", vinfo.red.offset);
  142. printf("vinfo.red.length=0x%%x ", vinfo.red.length);
  143. printf("vinfo.green.offset=0x%%x ", vinfo.green.offset);
  144. printf("vinfo.green.length=0x%%x ", vinfo.green.length);
  145. printf("vinfo.blue.offset=0x%%x ", vinfo.blue.offset);
  146. printf("vinfo.blue.length=0x%%x ", vinfo.blue.length);
  147. printf("vinfo.transp.offset=0x%%x ", vinfo.transp.offset);
  148. printf("vinfo.transp.length=0x%%x ", vinfo.transp.length);
  149. fbp =(char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);
  150. if ((int)fbp == -1)
  151. {
  152. printf ("Error: failed to map framebuffer device to memory. ");
  153. exit (4);
  154. }
  155. printf("Get virt mem = %%p ", fbp);
  156. fbmem = fbp;
  157. pix_size = vinfo.xres * vinfo.yres;
  158. /* using first frame, for FBIOPAN_DISPLAY
  159. * 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
  160. * 如果使用第二帧buffer -> vinfo.xoffset = 0; vinfo.yoffset = vinfo.yres;
  161. */
  162. vinfo.xoffset = 0;
  163. vinfo.yoffset = 0;
  164. int xx = 0, yy = 0;
  165. int j = 10;
  166. while(j--)
  167. {
  168. lcd_put_ascii(xx, yy, 1);
  169. xx = xx + 32;
  170. yy = yy + 32;
  171. }
  172. #if 0
  173. /* show color loop */
  174. while(num--) {
  175. printf(" drawing YELLOW...... ");
  176. fill_color16((short *)fbp, YELLOW, pix_size);
  177. //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
  178. sleep(3);
  179. printf(" drawing BLUE...... ");
  180. fill_color16((short *)fbp, BLUE, pix_size);
  181. //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
  182. sleep(3);
  183. printf(" drawing RED...... ");
  184. fill_color16((short *)fbp, RED, pix_size);
  185. //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
  186. sleep(3);
  187. }
  188. #if 1
  189. /*这是你想画的点的位置坐标,(0,0)点在屏幕左上角*/
  190. x = 10;
  191. y = 10;
  192. location = x * (vinfo.bits_per_pixel / 8) + y * finfo.line_length;
  193. test_fbp = fbp + location;
  194. printf("draw line....... ");
  195. for(i = 0; i < (vinfo.xres - x); i++)
  196. *test_fbp++ = i+30;
  197. //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
  198. #endif
  199. #endif
  200. munmap(fbp, screensize); /*解除映射*/
  201. close (fp);
  202. return 0;
  203. }

结果:

至于为什么是躺着的,还不清楚原因。

结束!

推荐阅读