Linux framebuffer顯示bmp圖片

整理了幾位大牛們的圖片相關的資料

 

framebuffer簡介 


    幀緩衝(framebuffer)是Linux爲顯示設備提供的一個接口,把顯存抽象後的一種設備,他允許上層應用程序在圖形模式下直接對顯示緩衝區進行讀寫操作。framebuffer是LCD對應的一中HAL(硬件抽象層),提供抽象的,統一的接口操作,用戶不必關心硬件層是怎麼實施的。這些都是由Framebuffer設備驅動來完成的。 
    幀緩衝設備對應的設備文件爲/dev/fb*,如果系統有多個顯示卡,Linux下還可支持多個幀緩衝設備,最多可達32個,分別爲/dev/fb0到 /dev/fb31,而/dev/fb則爲當前缺省的幀緩衝設備,通常指向/dev/fb0,在嵌入式系統中支持一個顯示設備就夠了。幀緩衝設備爲標準字符設備,主設備號爲29,次設備號則從0到31。分別對應/dev/fb0-/dev/fb31。


通過/dev/fb,應用程序的操作主要有這幾種: 
1. 讀/寫(read/write)/dev/fb:相當於讀/寫屏幕緩衝區。 
2. 映射(map)操作:由於Linux工作在保護模式,每個應用程序都有自己的虛擬地址空間,在應用程序中是不能直接訪問物理緩衝區地址的。而幀緩衝設備可以通過mmap()映射操作將屏幕緩衝區的物理地址映射到用戶空間的一段虛擬地址上,然後用戶就可以通過讀寫這段虛擬地址訪問屏幕緩衝區,在屏幕上繪圖了。 
3. I/O控制:對於幀緩衝設備,對設備文件的ioctl操作可讀取/設置顯示設備及屏幕的參數,如分辨率,屏幕大小等相關參數。ioctl的操作是由底層的驅動程序來完成的。


在應用程序中,操作/dev/fb的一般步驟如下: 
1. 打開/dev/fb設備文件。 
2. 用ioctl操作取得當前顯示屏幕的參數,根據屏幕參數可計算屏幕緩衝區的大小。 
3. 將屏幕緩衝區映射到用戶空間。 
4. 映射後即可直接讀寫屏幕緩衝區,進行繪圖和圖片顯示。


framebuffer相關數據結構介紹 
1. fb_info結構體:幀緩衝設備中最重要的數據結構體,包括了幀緩衝設備屬性和操作的完整性屬性。
2. fb_ops結構體:fb_info結構體的成員變量,fb_ops爲指向底層操作的函數的指針。
3.fb_var_screen和fb_fix_screen結構體:fb_var_screen記錄用戶可以修改的顯示控制器參數,fb_fix_screen記錄用戶不能修改的顯示控制器參數。

*.bmp文件和大多數圖形文件一樣,分爲文件描述區(頭文件信息)和圖象存儲區(象素數據)兩部分。而頭文件信息中又包含了信息區和調色板區兩部分,信息區又可以細分爲文件信息區和圖象信息區兩部分。

24位bmp格式,一位大牛用oD分析出來的


1.BMP文件的標識符,開頭都是42 4D,mspaint也是靠這個判斷一個文件是不是BMP文件的。
2.兩個DWORD數據用來保存bmp文件的大小,一般高DWORD數據爲0,因爲大小超過4GB的BMP文件還是比較少見的。
3.一個DWORD數據,它指出了顏色數據開始的地址,上圖中的DWORD數據是00000036,我們看下00000036地址處的數據是什麼, B4 A8 90 這就是顏色數據了,由於是文件是24位的BMP圖片,所以圖片中的每一個像素的顏色值都用3個字節來描述,即24個二進制位。每個字節對應一種基礎顏色的豔麗程度,最後三種顏色混合起來纔是最終的顏色。對,你肯定想到了,RGB三基**4 A8 90 那個是紅色 哪個是藍色呢? 經過驗證,90是紅色,A8是綠**4是藍色, 這三個數據告訴顯卡程序要在顯示器的某個點顯示一種顏色,什麼樣的顏色呢?90個單位的紅色加上A8個單位的綠色再加上B4個單位的藍色最後得到的那種顏色,恩,我就要那種顏色。
4.一個DWORD數據,具體意義不明,大多數情況下這個值是00 00 00 28,但是也有其它的值,LZ前幾天記得至少有三個值是可以用的,LZ記得畫在一張圖上了,可是現在找不到了。其它的值都是不行的,程序會顯示無效的圖片。
5.寬度以pixel爲單位
6.高度以pixel爲單位
7.幀數,一般bmp文件爲一幀,在動畫中它是一個基礎單位。

 

以下代碼使用framebuffer顯示一張bmp圖片:

點擊(此處)摺疊或打開

  1. #include <unistd.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <fcntl.h>
  5. #include <string.h>
  6. #include <linux/fb.h>
  7. #include <sys/mman.h>
  8. #include <sys/ioctl.h>
  9. #include <arpa/inet.h>
  10. #include <utils/Log.h>
  11. #include <errno.h>

  12. //14byte文件頭
  13. typedef struct
  14. {
  15.     char cfType[2];//文件類型,"BM"(0x4D42)
  16.     long cfSize;//文件大小(字節)
  17.     long cfReserved;//保留,值爲0
  18.     long cfoffBits;//數據區相對於文件頭的偏移量(字節)
  19. }__attribute__((packed)) BITMAPFILEHEADER;
  20. //__attribute__((packed))的作用是告訴編譯器取消結構在編譯過程中的優化對齊

  21. //40byte信息頭
  22. typedef struct
  23. {
  24.     char ciSize[4];//BITMAPFILEHEADER所佔的字節數
  25.     long ciWidth;//寬度
  26.     long ciHeight;//高度
  27.     char ciPlanes[2];//目標設備的位平面數,值爲1
  28.     int ciBitCount;//每個像素的位數
  29.     char ciCompress[4];//壓縮說明
  30.     char ciSizeImage[4];//用字節表示的圖像大小,該數據必須是4的倍數
  31.     char ciXPelsPerMeter[4];//目標設備的水平像素數/
  32.     char ciYPelsPerMeter[4];//目標設備的垂直像素數/
  33.     char ciClrUsed[4]; //位圖使用調色板的顏色數
  34.     char ciClrImportant[4]; //指定重要的顏色數,當該域的值等於顏色數時(或者等於0時),表示所有顏色都一樣重要
  35. }__attribute__((packed)) BITMAPINFOHEADER;

  36. typedef struct
  37. {
  38.     unsigned short blue;
  39.     unsigned short green;
  40.     unsigned short red;
  41.     unsigned short reserved;
  42. }__attribute__((packed)) PIXEL;//顏色模式RGB

  43. BITMAPFILEHEADER FileHead;
  44. BITMAPINFOHEADER InfoHead;

  45. static char *fbp = 0;
  46. static int xres = 0;
  47. static int yres = 0;
  48. static int bits_per_pixel = 0;

  49. int show_bmp();
  50. int show_bmp2();
  51. int fbfd = 0;
  52. static void fb_update(struct fb_var_screeninfo *vi) //將要渲染的圖形緩衝區的內容繪製到設備顯示屏來
  53. { 
  54.     vi->yoffset = 1; 
  55.     ioctl(fbfd, FBIOPUT_VSCREENINFO, vi); 
  56.     vi->yoffset = 0; 
  57.     ioctl(fbfd, FBIOPUT_VSCREENINFO, vi); 
  58. } 

  59. int width, height;

  60. static int cursor_bitmpa_format_convert(char *dst,char *src){
  61.     int i ,;
  62.     char *psrc = src ;
  63.     char *pdst = dst;
  64.     char *= psrc;
  65.     int value = 0x00;
  66.     
  67.     /* 由於bmp存儲是從後面往前面,所以需要倒序進行轉換 */
  68.     pdst += (width * height * 4);
  69.     for(i=0;i<height;i++){
  70.         p = psrc + (i+1) * width * 3;
  71.         for(j=0;j<width;j++){
  72.             pdst -= 4;
  73.             p -= 3;
  74.             pdst[0] = p[0];
  75.             pdst[1] = p[1];
  76.             pdst[2] = p[2];
  77.             //pdst[3] = 0x00;

  78.             value = *((int*)pdst);
  79.             value = pdst[0];
  80.             if(value == 0x00){
  81.                 pdst[3] = 0x00;
  82.             }else{
  83.                 pdst[3] = 0xff;
  84.             }
  85.         }
  86.     }

  87.     return 0;
  88. }

  89. int show_bmp(char *path)
  90. {
  91.     FILE *fp;
  92.     int rc;
  93.     int line_x, line_y;
  94.     long int location = 0, BytesPerLine = 0;
  95.     char *bmp_buf = NULL;
  96.     char *bmp_buf_dst = NULL;
  97.     char * buf = NULL;
  98.     int flen = 0;
  99.     int ret = -1;
  100.     int total_length = 0;
  101.     
  102.     LOGI("into show_bmp function_____________________________________________________________________________________\n");
  103.     if(path == NULL)
  104.         {
  105.             LOGE("path Error,return");
  106.             return -1;
  107.         }
  108.     LOGI("path = %s", path);
  109.     fp = fopen( path, "rb" );
  110.     if(fp == NULL){
  111.         LOGE("load > cursor file open failed");
  112.         return -1;
  113.     }
  114.     /* 求解文件長度 */
  115.     fseek(fp,0,SEEK_SET);
  116.     fseek(fp,0,SEEK_END);
  117.     flen = ftell(fp);

  118.     bmp_buf = (char*)calloc(1,flen - 54);
  119.     if(bmp_buf == NULL){
  120.         LOGE("load > malloc bmp out of memory!");
  121.         return -1;
  122.     }

  123.     /* 再移位到文件頭部 */
  124.     fseek(fp,0,SEEK_SET);
  125.     
  126.     rc = fread(&FileHead, sizeof(BITMAPFILEHEADER),1, fp);
  127.     if ( rc != 1)
  128.     {
  129.         LOGI("read header error!\n");
  130.         fclose( fp );
  131.         return( -);
  132.     }
  133.     
  134.     //檢測是否是bmp圖像
  135.     if (memcmp(FileHead.cfType, "BM", 2) != 0)
  136.     {
  137.         LOGI("it's not a BMP file\n");
  138.         fclose( fp );
  139.         return( -);
  140.     }
  141.     rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );
  142.     if ( rc != 1)
  143.     {
  144.         LOGI("read infoheader error!\n");
  145.         fclose( fp );
  146.         return( -);
  147.     }
  148.     width = InfoHead.ciWidth;
  149.     height = InfoHead.ciHeight;
  150.     LOGI("FileHead.cfSize =%d byte\n",FileHead.cfSize);
  151.     LOGI("flen = %d", flen);    
  152.     LOGI("width = %d, height = %d", width, height);
  153.     total_length = width * height *3;
  154.     
  155.     LOGI("total_length = %d", total_length);
  156.     //跳轉的數據區
  157.     fseek(fp, FileHead.cfoffBits, SEEK_SET);
  158.     LOGI(" FileHead.cfoffBits = %d\n", FileHead.cfoffBits);
  159.     LOGI(" InfoHead.ciBitCount = %d\n", InfoHead.ciBitCount);    
  160.     //每行字節數
  161.     buf = bmp_buf;
  162.     while ((ret = fread(buf,1,total_length,fp)) >= 0) {
  163.         if (ret == 0) {
  164.             usleep(100);
  165.             continue;
  166.         }
  167.         LOGI("ret = %d", ret);
  168.         buf = ((char*) buf) + ret;
  169.         total_length = total_length - ret;
  170.         if(total_length == 0)break;
  171.     }
  172.     
  173.     total_length = width * height * 4;
  174.     LOGI("total_length = %d", total_length);
  175.     bmp_buf_dst = (char*)calloc(1,total_length);
  176.     if(bmp_buf_dst == NULL){
  177.         LOGE("load > malloc bmp out of memory!");
  178.         return -1;
  179.     }
  180.     
  181.     cursor_bitmpa_format_convert(bmp_buf_dst, bmp_buf);
  182.     memcpy(fbp,bmp_buf_dst,total_length);
  183.     
  184.     LOGI("show logo return 0");
  185.     return 0;
  186. }
  187. int show_picture(int fd, char *path)
  188. {
  189.     
  190.     struct fb_var_screeninfo vinfo;
  191.     struct fb_fix_screeninfo finfo;
  192.     long int screensize = 0;
  193.     struct fb_bitfield red;
  194.     struct fb_bitfield green;
  195.     struct fb_bitfield blue;
  196.     LOGI("Enter show_logo");
  197.     //打開顯示設備
  198.     retry1:
  199.     fbfd = fd;//open("/dev/graphics/fb0", O_RDWR);
  200.     LOGI("fbfd = %d", fbfd);
  201.     if (fbfd == -1)
  202.     {
  203.         LOGE("Error opening frame buffer errno=%d (%s)",
  204.              errno, strerror(errno));
  205.         goto retry1;
  206.     }

  207.     if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
  208.     {
  209.         LOGI("Error:reading fixed information.\n");
  210.         return -1;
  211.     }

  212.     if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
  213.     {
  214.         LOGI("Error: reading variable information.\n");
  215.         return -1;
  216.     }

  217.     LOGI("R:%d,G:%d,B:%d \n", vinfo.red, vinfo.green, vinfo.blue );

  218.     LOGI("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
  219.     xres = vinfo.xres;
  220.     yres = vinfo.yres;
  221.     bits_per_pixel = vinfo.bits_per_pixel;

  222.     //計算屏幕的總大小(字節)
  223.     screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
  224.     LOGI("screensize=%d byte\n",screensize);

  225.     //對象映射
  226.     fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
  227.     if ((int)fbp == -1)
  228.     {
  229.         printf("Error: failed to map framebuffer device to memory.\n");
  230.         return -1;
  231.     }

  232.     LOGI("sizeof file header=%d\n", sizeof(BITMAPFILEHEADER));

  233.     
  234.     //顯示圖像
  235. //    while(1){
  236.     show_bmp(path);
  237.     fb_update(&vinfo);
  238. //}

  239.     //刪除對象映射
  240.     munmap(fbp, screensize);
  241.     //close(fbfd);
  242.     LOGI("Exit show_logo");
  243.     return 0;
  244. }

由於bmp圖象是從下至上存儲的,所以我們不能進行直接順序讀取。詳細的說,bmp圖象存儲區數據是從1078偏移字節開始。文件內第一個圖象點實際上是對應圖象(320*200)第200行的最左邊的第一個點,而從1078開始的320個點則是圖象最下面一行對應的點,之後的321個點是圖象倒數第二行最左邊的第一個點。這樣,bmp文件最後一個字節對應的點是第一行最後邊的點了。

上面程序顯示的圖片原來是24位深度的,代碼裏面將其轉爲32位

 

有幾個需要注意,第一必須爲bmp圖片,第二,圖片不能過大

 

注意:上面的程序只在framebuffer上顯示圖片,卻沒有刪除刷新屏幕,可以使用下面的命令恢復屏幕


保存屏幕信息:dd if=/dev/fb0 of=fbfile  或: cp /dev/fb0 fbfile
恢復屏幕信息:dd if=fbfile of=/dev/fb0  或: cat fbfile > /dev/fb0


轉載自:http://blog.csdn.net/new_abc/article/details/8185217
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章