当前位置: 首页 > news >正文

Linux编程 —— framebuffer

一、framebuffer概念

framebuffer:帧缓冲,帧缓存技术

                        Linux内核专门为图形化显示提供的一套应用程序接口。

 二、基本操作步骤

1. 打开显示设备(/dev/fb0)
2. 获取显示设备相关参数(分辨率,像素格式)---》ioctl
3. 建立显存空间和用户空间的内存映射
4. 向映射的用户空间写入RGB颜色值
5. 解除映射关系
6. 关闭显示设备

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;
}
#ifndef __FRAMEBUFFER_H__
#define __FRAMEBUFFER_H__#define RGB_FMT_888 32
#define RGB_FMT_565 16
#define PI   3.14
#pragma pack(1)//bmp文件相关信息
typedef struct tagBITMAPFILEHEADER {short    bfType;         // 文件类型标志int      bfSize;         // 文件大小,单位为字节short    bfReserved1;    // 保留字节short    bfReserved2;    // 保留字节int      bfOffBits;      // 数据偏移量,即实际图像数据开始的位置
}Bmp_file_head_t;
//bmp图像信息
typedef struct tagBITMAPINFOHEADER {int   biSize;         // BITMAPINFOHEADER的大小,单位为字节int    biWidth;        // 位图的宽度,单位为像素int    biHeight;       // 位图的高度,单位为像素short    biPlanes;       // 目标设备的位平面数,必须为1short    biBitCount;     // 每像素位数(颜色深度)int   biCompression;  // 图像压缩类型int   biSizeImage;    // 图像大小,单位为字节int    biXPelsPerMeter;// 水平分辨率,单位为像素/米int    biYPelsPerMeter;// 垂直分辨率,单位为像素/米int   biClrUsed;      // 实际使用颜色数int   biClrImportant; // 重要颜色数
}Bmp_info_t;
#pragma pack()extern int init_fb(char *devname);
extern int uninit_fb();
extern void draw_point(int x, int y, unsigned int col);
extern void draw_horizontal_line(int x1,int x2,int y,unsigned int col);
extern void draw_y_line(int x,int y,int ymax,unsigned int col);
extern void draw_face(int x1,int x2 ,int y1,int y2,int col);
extern void draw_Circle(int x, int y, int r, unsigned int col);
extern int get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo);
extern void draw_bmp(int x, int y, char *bmpname);
extern void draw_word(int x, int y, unsigned char *pword, int w, int h, unsigned int col);
#endif

注:此为函数接口头文件

三、mmap函数接口

void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
功能:建立内存映射
参数:
addr :映射的用户空间首地址  
NULL:让操作系统自己分配用户空间
length:要映射的空间大小
prot: 操作权限
PROT_READ  Pages may be read.
PROT_WRITE Pages may be written
flag : MAP_SHARED
fd:显示设备文件描述符
offset:偏移量
0:从显存开头映射
返回值:
成功:映射的用户空间首地址
失败:MAP_FAILED((void *)-1)

int uninit_fb()
{//5. 解除映射关系//6. 关闭显示设备size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;munmap(pmem, len);close(fb);}

四、基本操作及算法           

1.画一个点

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;}
}

注:虚拟界面视图大于实际视图         

①要保持起始点在视图范围内

②bits_per_pixel:表示每个像素所占用的位数(bit),它决定了图像的颜色深度和显示质量。数值越高,能够表示的颜色数量越多,图像的色彩表现越丰富。

RGB888:每个像素占8位,及一个字节 ,RGB888占3个字节,但在C中没有可以存储三字节的整形变量,它就会自动补为四字节,并将高位置零

RGB565:红色占5位,绿色占6位,蓝色占7位,  RGB565占2个字节

③pmem在建立内存映射时指向了显存,而我们不能直接对显存直接进行操做,所以定义相应的指针与pemp指向的地址相同,也可以理解为强转pemp,利用强转的pemp对显存所映射的用户空间进行操作   

2.画一条横线

void draw_horizontal_line(int x1,int x2,int y,unsigned int col)
{if(x1 >= vinfo.xres || x2 >=  vinfo.xres || y >= vinfo.yres){return ;}if(x1 > x2){int t = x1;x1 = x2;x2 = x1;}for(int i = 0;i <= x2 - x1 ; ++i ){if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;*(p+vinfo.xres_virtual*y+(x1+i)) = col;}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;*(p+vinfo.xres_virtual*y+(x1+i)) = col;}}
}

思想(点成面):画一条横线,横坐标改变,纵坐标不变,即绘制一条x1至x2的横线

3.画一条竖线

void draw_y_line(int x,int y,int ymax,unsigned int col)
{if(x >= vinfo.xres || y >=  vinfo.yres || ymax>= vinfo.yres){return ;}for(int i = 0;i <= ymax - y; ++i ){if (vinfo.bits_per_pixel == RGB_FMT_888){unsigned int *p = pmem;*(p+vinfo.xres_virtual*(y+i)+x) = col;}else if (vinfo.bits_per_pixel == RGB_FMT_565){unsigned short *p = pmem;*(p+vinfo.xres_virtual*(y+i)+x) = col;}}
}

4.绘制一个面 

void draw_face(int x1,int x2 ,int y1,int y2,int col)
{if(x1 > x2){int t = x1;x1 = x2;x2 = t;}if(y1 > y2){int t = y1;y1 = y2;y2 = t;}if(x1 >= vinfo.xres ||x2 >=vinfo.xres|| y1 >=  vinfo.yres || y2 >= vinfo.yres){return ;}int i = 0; if (vinfo.bits_per_pixel == RGB_FMT_888){for(i = 0;i < y2 - y1;++i){draw_horizontal_line(x1,x2,y1+i,col);draw_horizontal_line(x1,x2,y2+i,col);}       }else if (vinfo.bits_per_pixel == RGB_FMT_565){ for(i = 0;i < y2 - y1;++i){draw_horizontal_line(x1,x2,y1+i,col);draw_horizontal_line(x1,x2,y2+i,col);}}if (vinfo.bits_per_pixel == RGB_FMT_888){for(i = 0;i < x2 -x1;++i){   draw_y_line(x1 + 1,y1,y2,col);draw_y_line(x2 + 1,y1,y2,col);}}else if (vinfo.bits_per_pixel == RGB_FMT_565){for(i = 0;i < x2 -x1;++i){   draw_y_line(x1 + 1,y1,y2,col);draw_y_line(x2 + 1,y1,y2,col);}}
}

思想(线成面)

6.绘制一个圆 

void draw_Circle(int x, int y, int r, unsigned int col)
{int x0 = 0;int y0 = 0;int si = 0;for (si = 0; si <= 360; si++){x0 = r * sin(PI * 2 / 360 * si) + x; y0 = r * cos(PI * 2 / 360 * si) + y;draw_point(x0, y0, col);}
}

思想:x,y为圆心坐标,圆周上任意一点为(x0,y0)

sin(PI * 2 / 360 * si) ,cos(PI * 2 / 360 * si) 是将角度转化为弧度

7,绘制一个bmp图

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(bmpname, &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);}

                                                                                                                                                                                                                                                                          get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo)

算法思想:

文件操作:

以只读模式打开BMP文件,失败时返回错误。

头信息读取:

使用 fread 读取BMP文件头(Bmp_file_head_t)到 pheadinfo。

继续读取BMP信息头(Bmp_info_t)到 pbmpinfo。

资源释放:关闭文件句柄,返回成功状态。

draw_bmp(int x, int y, char *bmpname)

算法思想:

头信息解析:调用 get_bmp_head_info 获取BMP的宽、高、位深等信息。

像素数据加载:

打开文件并跳过54字节的文件头和信息头。

根据BMP信息头中的图像尺寸和位深(如 biWidth × biHeight × biBitCount/8),分配缓冲区 buff 并读取像素数据。

像素绘制:

BMP像素顺序:BMP文件存储顺序为从下到上,需反向遍历行(j 从 biHeight-1 到 0)。

颜色转换:

对于 RGB888格式屏幕:将BGR像素数据(BMP格式)转换为RGB888,合并为 unsigned int 后调用 draw_point。

对于 RGB565格式屏幕:将RGB分量压缩为5-6-5位,合并为 unsigned short。

绘制每个像素到屏幕坐标 (x + i, y + j)。

                                                                                                                                                             8.绘制一个字

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;}}}
}

   

思想:

字模数据解析:

字模数据 pword 为 w × h 的字节数组,每个字节表示8个水平像素点(1位1像素)。

逐行逐像素绘制:

外层循环遍历行(j 从 0 到 h-1)。

内层循环遍历列(i 从 0 到 w-1):

获取当前字节 tmp = pword[i + j * w]。

对字节的8个位(从高位到低位):

若某位为 1,调用 draw_point(x + i*8 + k, y + j, col) 绘制像素。

若为 0,跳过(透明或背景)。

效果:

将1位字模数据按指定颜色展开为8倍宽度的字符图形。

                                                                                                                                                                                                                           

                       

http://www.dtcms.com/a/329349.html

相关文章:

  • AJAX学习(2)
  • AI 创作系列(30)海狸 IM:小而全、易二开、快迭代
  • 八爪鱼和影刀的区别和优缺点
  • 【题解】[CQOI2006] 洛谷P4196 凸多边形 /【模板】半平面交
  • AI时代程序员的进化:从代码工人到创意架构师-优雅草卓伊凡引言:AI浪潮下的职业重构
  • Celery在Django中的应用
  • 排序总结---保研机试极限复习
  • 亚马逊聚焦战略2.0:从资源分散到价值聚焦的商业重构逻辑
  • 北京JAVA基础面试30天打卡09
  • Java面试宝典:ZGC
  • 【自动化运维神器Ansible】playbook主机清单变量深度解析:主机变量与组变量的实战应用
  • InfluxDB数据恢复
  • 在JVM跑JavaScript脚本 | Oracle GraalJS 简介与实践
  • MySQL数据库核心操作解析
  • 数据库基础—SQL语句总结及在开发时
  • 如何使用 Ollama 在本地设置并运行 Qwen3
  • 2025年高效能工程项目管理软件推荐榜单:AI重构工程进度可视化与资源动态调度体系
  • 【国内电子数据取证厂商龙信科技】RAID存储技术
  • Spring Boot 集成 机器人指令中枢ROS2工业机械臂控制网关
  • Linux系统之K8S基本命令概述
  • PyTorch基础(Numpy与Tensor)
  • 集成 OceanBase 并打印 SQL 日志
  • 老生常谈智能指针:《More Effective C++》的条款28
  • PCIe Base Specification解析(十一)
  • nginx高性能web服务器实验
  • 【114页PPT】基于SAPSRM数字化采购解决方案(附下载方式)
  • Java面试宝典:G1垃圾收集器下
  • hadoop 前端yarn查看
  • 完整源码+技术文档!基于Hadoop+Spark的鲍鱼生理特征大数据分析系统免费分享
  • 以太坊的下一个十年:Vitalik Buterin的愿景与挑战