Linux Framebuffer(帧缓冲)与基本 UI 绘制技术
1. UI 技术简介
UI(User Interface):用户界面技术,用于实现图形化交互。
在 Linux 中,**framebuffer(帧缓冲/帧缓存)**是内核提供的一套图形显示接口,使用户程序可以直接操作显存实现显示效果。
2. 帧缓冲基础
分辨率
800 × 600
像素格式
格式 | 字节数 | 说明 |
---|---|---|
RGB888 | 3 → 4 | 每个像素 3 个字节,通常对齐到 4 字节 |
RGB565 | 2 | 每个像素 2 个字节 |
显存访问示例
unsigned int *pmem;
*(pmem + 800 * y + x) = 0x00FF0000; // 将 (x,y) 位置像素设为红色
3. framebuffer 使用流程
打开显示设备
int fd = open("/dev/fb0", O_RDWR);
获取显示参数
ioctl(fd, FBIOGET_VSCREENINFO, &vinfo); // 获取分辨率、像素格式等信息
建立显存和用户空间的内存映射
void *addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
参数说明:
addr
:用户空间首地址,NULL
由系统分配length
:映射长度prot
:访问权限,如PROT_READ | PROT_WRITE
flags
:映射类型,如MAP_SHARED
fd
:设备文件描述符offset
:从显存的偏移量,一般为 0
返回值:
成功:映射的用户空间首地址
失败:
MAP_FAILED
((void *)-1
)
写入像素数据
向映射的内存写入颜色值即可实现绘图
示例:
*(pmem + 800*y + x) = 0x00FF0000;
解除映射
munmap(addr, length);
关闭显示设备
close(fd);
4. 基本绘图封装函数
绘制横线
绘制竖线
绘制矩形
绘制圆
绘制 BMP 图片
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <sys/ioctl.h> #include <linux/fb.h> #include <sys/mman.h> #include "framebuffer.h" #include <math.h>void *pmem = NULL; int fb; struct fb_var_screeninfo vinfo;int init_fb(char *devname) {//1. 打开显示设备(/dev/fb0)fb = open(devname, O_RDWR);if (-1 == fb){perror("open fb error");return -1;}//2. 获取显示设备相关参数(分辨率,像素格式)int ret = ioctl(fb, FBIOGET_VSCREENINFO, &vinfo);if (ret < 0){perror("ioctl error");return -1;}printf("xres = %d, yres = %d\n", vinfo.xres, vinfo.yres);printf("xres_virtual = %d, yres_virtual = %d\n", vinfo.xres_virtual, vinfo.yres_virtual);printf("bits_per_pixel = %d\n", vinfo.bits_per_pixel);//3. 建立显存空间和用户空间的内存映射size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);if (pmem == MAP_FAILED){perror("mmap error");return -1;}return 0; }int uninit_fb() {//5. 解除映射关系//6. 关闭显示设备size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;munmap(pmem, len);close(fb);return 0; }void draw_point(int x, int y, unsigned int col) {if (x >= vinfo.xres || y >= vinfo.yres){return ;}if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;*(p+vinfo.xres_virtual *y+x) = col;}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;*(p+vinfo.xres_virtual*y+x) = col;} }void draw_row_line(int x, int y, unsigned int col) {if (x >= vinfo.xres || y >= vinfo.yres){return ;}if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;while(x != 799){*(p+vinfo.xres_virtual *y+x) = col;++x;}}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;while(x != 799){*(p+vinfo.xres_virtual*y+x) = col;++x;}} }void draw_clos_line(int x, int y, unsigned int col) {if (x >= vinfo.xres || y >= vinfo.yres){return ;}if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;while(y != 599){// *(p+vinfo.xres_virtual*y+x) = col;// ++x;*(p+vinfo.xres_virtual*y+x) = col;++y;}}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;while(y != 599){// *(p+vinfo.xres_virtual*y+x) = col;// ++x;*(p+vinfo.xres_virtual*y+x) = col;++y;}} }void draw_round(int cx, int cy, int r,unsigned int col) {if (cx >= vinfo.xres || cy >= vinfo.yres){return ;}if(r > cx || r > cy || r + cx > vinfo.xres || r + cy > vinfo.yres){return ;}double PI = 3.1415926;if (vinfo.bits_per_pixel == RGB_FMT_888){for(double angle = 0;angle <2 * PI;angle += 0.01){int x = (int)(cx + r * cos(angle));int y = (int)(cy + r * sin(angle));draw_point(x, y, col);}}else if (vinfo.bits_per_pixel == RGB_FMT_565){for(double angle = 0;angle < 2 * PI;angle += 0.01){int x = (int)(cx + r * cos(angle));int y = (int)(cy + r * sin(angle));draw_point(x, y, col);}} }int get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo) {FILE *fp = fopen(bmpname, "r");if (NULL == fp){perror("fopen error");return -1;}fread(pheadinfo, sizeof(Bmp_file_head_t), 1, fp);fread(pbmpinfo, sizeof(Bmp_info_t), 1, fp);fclose(fp);return 0; }void draw_bmp(int x, int y, char *bmpname) {Bmp_file_head_t headinfo;Bmp_info_t bmpinfo;get_bmp_head_info("./1.bmp", &headinfo, &bmpinfo);int fd = open(bmpname, O_RDONLY);if (-1 == fd){perror("open bmp error");return ;}lseek(fd, 54, SEEK_SET);unsigned char *buff = malloc(bmpinfo.biHeight*bmpinfo.biWidth*bmpinfo.biBitCount/8);read(fd, buff, bmpinfo.biHeight*bmpinfo.biWidth*bmpinfo.biBitCount/8);close(fd);unsigned char *p = buff;unsigned char r, g, b;for (int j = bmpinfo.biHeight-1; j >= 0; j--){for (int i = 0; i < bmpinfo.biWidth; i++){b = *p;++p;g = *p;++p;r = *p;++p;if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int col = (r << 16) | (g << 8) | (b << 0);draw_point(i+x, j+y, col);}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short col = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);draw_point(i+x, j+y, col);}}}free(buff);}//w = 2, h = 19 void draw_word(int x, int y, unsigned char *pword, int w, int h, unsigned int col) {for (int j = 0; j < h; j++){for (int i = 0; i < w; i++){unsigned char tmp = pword[i+j*w];for (int k = 0; k < 8; k++){if (tmp & 0x80){draw_point(x+i*8+k, y+j, col);}else{}tmp = tmp << 1;}}} }
绘制文字