zoukankan      html  css  js  c++  java
  • 文件浏览器及数码相框 -2.2-字符点阵及汉字库

    FrameBuffer的原理     FrameBuffer 是出现在 2.2.xx 内核当中的一种驱动程序接口。

        Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出 FrameBuffer这个设备来供用户态进程实现直接写屏。Framebuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过 Framebuffer的读写直接对显存进行操作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由 Framebuffer设备驱动来完成的。

        但Framebuffer本身不具备任何运算数据的能力,就只好比是一个暂时存放水的水池.CPU将运算后的结果放到这个水池,水池再将结果流到显示器. 中间不会对数据做处理. 应用程序也可以直接读写这个水池的内容.在这种机制下,尽管Framebuffer需要真正的显卡驱动的支持,但所有显示任务都有CPU完成,因此CPU 负担很重

    framebuffer的设备文件一般是 /dev/fb0、/dev/fb1 等等。

    可以用命令: #dd if=/dev/zero of=/dev/fb 清空屏幕. 如果显示模式是 1024x768-8 位色,

    用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕;

    用命令: #dd if=/dev/fb of=fbfile  可以将fb中的内容保存下来;

    可以重新写回屏幕: #dd if=fbfile of=/dev/fb;

    在使用Framebuffer时,Linux是将显卡置于图形模式下的.

        在应用程序中,一般通过将 FrameBuffer 设备映射到进程地址空间的方式使用,比如下面的程序就打开 /dev/fb0 设备,

    并通过 mmap 系统调用进行地址映射,随后用 memset 将屏幕清空(这里假设显示模式是 1024x768-8 位色模式,线性内存模式):

    int fb;

    unsigned char* fb_mem;

    fb = open ("/dev/fb0", O_RDWR);

    fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);

    memset (fb_mem, 0, 1024*768); //这个命令应该只有在root可以执行

    仿照写一个

    1     fd_fb = open("/dev/fb0",O_RDWR);
     2     if(fd_fb < 0)
     3     {
     4         printf("can't open /dev/fb0 
    ");
     5         return -1;
     6     }
     7     if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))            //取出可变信息
     8     {
     9         printf("can't get var 
    ");
    10         return -1;    
    11     }
    12     if(ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))            //取出固定信息
    13     {
    14         printf("can't get fix 
    ");
    15         return -1;    
    16     }
    17     screen_size = var.xres * var.yres * var.bits_per_pixel / 8;    //占内存大小 单位字节
    18     line_width = var.xres *  var.bits_per_pixel / 8;         //一行像素大小
    19     pixel_width =  var.bits_per_pixel / 8;               //一点像素大小
    20     
    21     fb_mem = (unsigned char *)mmap(NULL, screen_size,        //mmap 系统调用进行地址映射
    22         PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
    23     if(fb_mem == (unsigned char *) -1)
    24     {                                      
    25         printf("can't mmap 
    ");
    26         return -1;
    27     }
    28     memset(fb_mem, 0, screen_size);                   //清屏,黑色

    字符点阵显示

    8*16像素的字符点阵

    一个字节8位来表示一行的8个像素是否被选中点亮

    每个字符由16个字节表示

    仅需要用asii码值乘以16就可以定位到当前字符的点阵位置

    1 static const unsigned char fontdata_8x16[FONTDATAMAX] = {
     2 
     3     /* 0 0x00 '^@' */
     4     0x00, /* 00000000 */
     5     0x00, /* 00000000 */
     6     0x00, /* 00000000 */
     7     0x00, /* 00000000 */
     8     0x00, /* 00000000 */
     9     0x00, /* 00000000 */
    10     0x00, /* 00000000 */
    11     0x00, /* 00000000 */
    12     0x00, /* 00000000 */
    13     0x00, /* 00000000 */
    14     0x00, /* 00000000 */
    15     0x00, /* 00000000 */
    16     0x00, /* 00000000 */
    17     0x00, /* 00000000 */
    18     0x00, /* 00000000 */
    19     0x00, /* 00000000 */
    20 
    21     /* 1 0x01 '^A' */
    22     0x00, /* 00000000 */
    23     0x00, /* 00000000 */
    24     0x7e, /* 01111110 */
    25     0x81, /* 10000001 */
    26     0xa5, /* 10100101 */
    27     0x81, /* 10000001 */
    28     0x81, /* 10000001 */
    29     0xbd, /* 10111101 */
    30     0x99, /* 10011001 */
    31     0x81, /* 10000001 */
    32     0x81, /* 10000001 */
    33     0x7e, /* 01111110 */
    34     0x00, /* 00000000 */
    35     0x00, /* 00000000 */
    36     0x00, /* 00000000 */
    37     0x00, /* 00000000 */
    38 
    39         /*****
    40     ****
    41     ****
    42     ****
    43     ****
    44     ****
    45     ****
    46     ****
    47     *****/
    48 
    49     /* 255 0xff '' */
    50     0x00, /* 00000000 */
    51     0x00, /* 00000000 */
    52     0x00, /* 00000000 */
    53     0x00, /* 00000000 */
    54     0x00, /* 00000000 */
    55     0x00, /* 00000000 */
    56     0x00, /* 00000000 */
    57     0x00, /* 00000000 */
    58     0x00, /* 00000000 */
    59     0x00, /* 00000000 */
    60     0x00, /* 00000000 */
    61     0x00, /* 00000000 */
    62     0x00, /* 00000000 */
    63     0x00, /* 00000000 */
    64     0x00, /* 00000000 */
    65     0x00, /* 00000000 */
    66 
    67 };

    刷写8*16字符点阵

    1 lcd_put_ascii(int x, int y, unsigned char c )
     2 {
     3     unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
     4     int i, b;
     5     unsigned char byte;
     6     
     7     for(i = 0; i < 16; i++)
     8     {
     9         byte = dots[i];
    10         
    11         for(b = 7; b >= 0; b --)
    12         {
    13             if(byte & (1<<b))
    14             {
    15                 /* 显示 */
    16                 lcd_put_pixel(x + 7 - b, y + i, 0xffffff);//
    17             }
    18             else
    19             {
    20                         /* 不显示 */
    21                 lcd_put_pixel(x + 7 - b, y + i, 0);//
    22             
    23             }
    24         }
    25     }
    26     

    使用HZK16 字库,将它拷贝到内存中,使用时直接用数组指向某个汉字所在地址

     使用#include <sys/stat.h>中的fstat()函数来统计HZK16文件信息

        
        fd_hzk16 =  open("HZK16",O_RDWR);
        if(fd_hzk16 < 0)
        {
            printf("can't open HZK16 
    ");
            return -1;
        }
        
    if(fstat(fd_hzk16, &hzk_stat)) //得到文件统计信息 { printf("can't get fstat "); return -1; } hzk_mem = (unsigned char *)mmap(NULL, hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0); if(hzk_mem == (unsigned char *) -1) { printf("can't mmap hzk_mem "); return -1; }

    HZK16 字库是符合GB2312标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有3755个,按 声序排列,二级汉字有3008个,按偏旁部首排列。我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。

    HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。

    我们知道一个GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。下面以汉字“我”为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。

    前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的 位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到“我”在hzk16库中的位置就必须得到它的区码和位码。(为了区别使用了区码 和区号,其实是一个东西,别被我误导了)

    区码:区号(汉字的第一个字节)-0xa0    (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)

    位码:位号(汉字的第二个字节)-0xa0

    这样我们就可以得到汉字在HZK16中的绝对偏移位置:

    offset=(94*(区码-1)+(位码-1))*32

    注解:1、区码减1是因为数组是以0为开始而区号位号是以1为开始的

         2、(94*(区号-1)+位号-1)是一个汉字字模占用的字节数

       3、最后乘以32是因为汉字库文应从该位置起的32字节信息记录该字的字模信息(前面提到一个汉字要有32个字节显示)

     1 void lcd_put_chinese(int x, int y, unsigned char *str)
     2 {
     3     unsigned int area = str[0] - 0xa1;
     4     unsigned int where = str[1] - 0xa1;
     5     unsigned char *dots = hzk_mem + (area * 94 + where) * 32;
     6     unsigned char byte;
     7     int i,j,b;
     8 
     9     for(i=0; i < 16; i++)
    10         for(j=0; j < 2; j++)
    11         {
    12             byte = dots[i*2 + j];
    13             for(b=7; b >=0; b--)
    14             {
    15                 if(byte & (1<<b))
    16                 {
    17                     /* 显示 */
    18                     lcd_put_pixel(x + j * 8 + 7 - b, y + i, 0xffffff);//
    19                 }
    20                 else
    21                 {
    22                             /* 不显示 */
    23                     lcd_put_pixel(x + j * 8 + 7 - b, y + i, 0);//
    24                 
    25                 }
    26             }
    27         }
    28 
    29 }

    对像素进行瞄颜色

     1 void lcd_put_pixel(int x, int y, unsigned int color)
     2 {
     3     unsigned char *pen_8 = fb_mem + y * line_width + x * pixel_width;     //当前像素对应内存位置
     4     unsigned short *pen_16;
     5     unsigned int *pen_32;
     6 
     7     unsigned int red, blue, green;
     8     
     9     pen_16 = (unsigned short *)pen_8;
    10     pen_32 = (unsigned int *)pen_8;
    11     
    12     switch(var.bits_per_pixel)
    13     {
    14         case 8:
    15         {
    16             *pen_8 = color;            //对应调色板颜色
    17             
    18             break;
    19         }
    20         case 16:
    21         {
    22             /* 5*6*5 */
    23             red   = (color >> 16) & 0xff;
    24             green = (color >> 8) & 0xff;
    25             blue  = (color >> 0) & 0xff;
    26 
    27             color = ((red >> 3 ) << 11) | ((green >> 2) << 5) | ( blue >> 3);
    28             
    29             /* 颜色数据为高位 */
    30             *pen_16 = color;
    31             
    32             break;
    33         }
    34         case 32:
    35         {
    36             *pen_32 = color;
    37             break;
    38         }
    39         
    40     }
    41 
    42 }
        lcd_put_ascii(var.xres / 2, var.yres / 2, 'a');
        printf("中: chinese code: %02x %02x
    ", str[0], str[1]);
        lcd_put_chinese(var.xres / 2 + 32, var.yres / 2, str);
        

    屏幕输出‘a’,“中”

  • 相关阅读:
    Linux下安装confluence汉化破解版
    某种可以解决一切问题的方法
    普通平衡树(treap)
    文艺平衡树(splay模板)
    [CQOI2015]任务查询系统
    [NOIP2016]天天爱跑步
    NOI2018_Day1_T1_归程
    Picture
    bzoj3524 Couriers
    bzoj2588 counting on a tree
  • 原文地址:https://www.cnblogs.com/CZM-/p/5315224.html
Copyright © 2011-2022 走看看