linux應用編程--顯示bmp圖片


平台:tiny4412SDK 1161 + HD700

kernel:linux 3.5

bmp:24位深

前言:

  前邊設置好了HD700的驅動,能夠正常顯示像素,現在學習bmp圖片格式並顯示一張bmp圖片。

1、bmp圖片格式:

  BMP是英文Bitmap(位圖)的簡寫,它是Windows操作系統中的標准圖像文件格式,能夠被多種Windows應用程序所支持。隨着Windows操作系統的流行與豐富的Windows應用程序的開發,BMP位圖格式理所當然地被廣泛應用。

  常用的圖片格式有:JPEG、GIF、PSD、PNG、SWF、SVG……

2、bmp圖片的優缺點:

  優點:包含的圖像信息較豐富,幾乎不進行壓縮

  缺點:占用磁盤空間過大

3、bmp圖片的應用范圍:

  網絡上應用較少,目前BMP在單機上比較流行

4、bmp圖片數據結構:

  bmp圖片文件數據流中前54個字節是bmp格式包含的數據頭信息,其余為顏色數據。

  數據頭信息如下數據結構:

    //14byte文件頭  
    typedef struct    
    {  
        char cfType[2];  //文件類型,"BM"(0x4D42)  
        long cfSize;    //文件大小(字節)    
        long cfReserved;  //保留,值為0    
        long cfoffBits;    //數據區相對於文件頭的偏移量(字節)  
    }__attribute__((packed)) BITMAPFILEHEADER;    
    //__attribute__((packed))的作用是告訴編譯器取消結構在編譯過程中的優化對齊  
    //40byte信息頭  
    typedef struct    
    {  
        char ciSize[4];      //BITMAPFILEHEADER所占的字節數  
        long ciWidth;        //寬度  
        long ciHeight;       //高度    
        char ciPlanes[2];    //目標設備的位平面數,值為1  
        int ciBitCount;      //每個像素的位數    
        char ciCompress[4];  //壓縮說明  
        char ciSizeImage[4]; //用字節表示的圖像大小,該數據必須是4的倍數  
        char ciXPelsPerMeter[4];//目標設備的水平像素數/米  
        char ciYPelsPerMeter[4];//目標設備的垂直像素數/米  
        char ciClrUsed[4];      //位圖使用調色板的顏色數    
        char ciClrImportant[4]; //指定重要的顏色數,當該域的值等於顏色數時(或者等於0時),表示所有顏色都一樣重要  
    }__attribute__((packed)) BITMAPINFOHEADER;    

編程過程當中需要多加關注的成員是文件類型、數據區偏移量、寬度、高度、像素位深。

5、編程思路:

1)、打開linux系統下顯示設備。

2)、獲取設備的大小信息,得到屏幕寬高,並計算屏幕大小。

3)、根據屏幕大小映射顯存區域

4)、顯示圖片
  a、打開圖片文件

  b、獲取數據頭

  c、判斷文件類型

  d、循環讀取顏色數據

  e、把數據往顯存當中寫入

  f、關閉圖片文件

5)、解除映射

6)、關閉顯示設備

6、注意事項:

  1、從bmp圖片文件當中讀取像素信息時,需要根據位深度讀取不同大小的數據信息,例如例子當中使用的是24位深度,每次讀取一個像素數據是3個字節。

  2、bmp圖片的像素數據存儲的排版是從下到上、從左到右的。

7、待優化:

  1、圖片顯示需要根據位深度不同而讀取顏色數據時做適應性變化。

  2、添加顯示初始位置接口

  3、由於映射的顯存是一段連續的地址,需要對圖片行、列顯示做限定處理,確保超出屏幕大小不會顯示混亂。

8、代碼實現:

#include <unistd.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <fcntl.h>  
#include <string.h>  
#include <linux/fb.h>  
#include <sys/mman.h>  
#include <sys/ioctl.h>  
#include <arpa/inet.h>  
  
//14byte文件頭  
typedef struct	
{  
	char cfType[2];//文件類型,"BM"(0x4D42)  
	long cfSize;//文件大小(字節)	
	long cfReserved;//保留,值為0	
	long cfoffBits;//數據區相對於文件頭的偏移量(字節)  
}__attribute__((packed)) BITMAPFILEHEADER;	
//__attribute__((packed))的作用是告訴編譯器取消結構在編譯過程中的優化對齊  
  
//40byte信息頭  
typedef struct	
{  
	char ciSize[4];//BITMAPFILEHEADER所占的字節數  
	long ciWidth;//寬度  
	long ciHeight;//高度	
	char ciPlanes[2];//目標設備的位平面數,值為1  
	int ciBitCount;//每個像素的位數	
	char ciCompress[4];//壓縮說明  
	char ciSizeImage[4];//用字節表示的圖像大小,該數據必須是4的倍數  
	char ciXPelsPerMeter[4];//目標設備的水平像素數/米  
	char ciYPelsPerMeter[4];//目標設備的垂直像素數/米  
	char ciClrUsed[4]; //位圖使用調色板的顏色數	
	char ciClrImportant[4]; //指定重要的顏色數,當該域的值等於顏色數時(或者等於0時),表示所有顏色都一樣重要  
}__attribute__((packed)) BITMAPINFOHEADER;	
  
typedef struct	
{  
	unsigned char blue;  
	unsigned char green;  
	unsigned char red;  
//	unsigned char reserved;  
}__attribute__((packed)) PIXEL;//顏色模式RGB  
  
BITMAPFILEHEADER FileHead;	
BITMAPINFOHEADER InfoHead;	
  
static char *fbp = 0;  
static int xres = 0;  
static int yres = 0;  
static int bits_per_pixel = 0;	
  
int show_bmp();  
  
int main ( int argc, char *argv[] )  
{  
	int fbfd = 0;  
	struct fb_var_screeninfo vinfo;  
	struct fb_fix_screeninfo finfo;  
	long int screensize = 0;  
	struct fb_bitfield red;  
	struct fb_bitfield green;  
	struct fb_bitfield blue;  
  
	//打開顯示設備  
	fbfd = open("/dev/fb0", O_RDWR);  
	if (!fbfd)	
	{  
		printf("Error: cannot open framebuffer device.\n");  
		exit(1);  
	}  
  
	if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))  
	{  
		printf("Error:reading fixed information.\n");  
		exit(2);  
	}  
  
	if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))  
	{  
		printf("Error: reading variable information.\n");  
		exit(3);  
	}  
	printf("R:%d,G:%d,B:%d \n", vinfo.red.offset, vinfo.green.offset, vinfo.blue.offset ); 
	printf("R:%d,G:%d,B:%d \n", vinfo.red.length, vinfo.green.length, vinfo.blue.length );  
  
	printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );  
	xres = vinfo.xres;	
	yres = vinfo.yres;	
	bits_per_pixel = vinfo.bits_per_pixel;	
  
	//計算屏幕的總大小(字節)	
	screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;  
	printf("screensize=%d byte\n",screensize);	
  
	//對象映射	
	fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);  
	if ((int)fbp == -1)  
	{  
		printf("Error: failed to map framebuffer device to memory.\n");  
		exit(4);  
	}  
 
	//顯示圖像	
	show_bmp();  
  
	//刪除對象映射  
	munmap(fbp, screensize);  
	close(fbfd);  
	return 0;  
}  
  
int show_bmp()	
{  
	FILE *fp;  
	int rc;  
	int line_x, line_y;  
	long int location = 0, BytesPerLine = 0;  
  
	fp = fopen( "timg.bmp", "rb" );  
	if (fp == NULL)  
	{  
		return(-1);  
	}  
  
	rc = fread( &FileHead, sizeof(BITMAPFILEHEADER),1, fp );  
	if ( rc != 1)  
	{  
		printf("read header error!\n");  
		fclose(fp);  
		return(-2);  
	}  
  
	//檢測是否是bmp圖像	
	if (memcmp(FileHead.cfType, "BM", 2) != 0)	
	{  
		printf("it's not a BMP file\n");  
		fclose(fp);  
		return(-3);  
	}  
  
	rc = fread((char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp);  
	if (rc != 1)  
	{  
		printf("read infoheader error!\n");  
		fclose(fp);  
		return(-4);  
	}  
  
	//跳轉的數據區  
	fseek(fp, FileHead.cfoffBits, SEEK_SET);  
	//每行字節數  
	BytesPerLine = (InfoHead.ciWidth * InfoHead.ciBitCount + 31) / 32 * 4;	
	line_x = line_y = 0;  
	//向framebuffer中寫BMP圖片  
	while(!feof(fp))  
	{  
		PIXEL pix;	
		rc = fread( (char *)&pix, 1, sizeof(PIXEL), fp);  
		if (rc != sizeof(PIXEL))  
			break;	
		location = line_x * bits_per_pixel / 8 + (InfoHead.ciHeight - line_y - 1) * xres * bits_per_pixel / 8;	
  
		//顯示每一個像素  
		*(fbp + location + 0)=pix.blue;  
		*(fbp + location + 1)=pix.green;  
		*(fbp + location + 2)=pix.red;	
		*(fbp + location + 3)=0;  
		line_x++;  
		if (line_x == InfoHead.ciWidth)  
		{  
			line_x = 0;  
			line_y++;  
			if(line_y == InfoHead.ciHeight)  
				break;	
		}  
	}  
	fclose(fp);  
	return(0);  
} 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM