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 图片
cs
#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;
}
}
}
}
绘制文字