一、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倍寬度的字符圖形。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ?