DOS下顯示8位256色BMP位圖

 

#include<stdio.h>
#include<stdlib.h>	//exit()
#include<dos.h>		//in86()
#include<bios.h>	//close()
#include<fcntl.h>	//open()
#include<io.h>		//lseek(),read()

#include<conio.h>	//outp(),getch()

#define VGA256 					0x13	//320*200 256色 顯示模式
#define TEXT_MODE 				0x03	//80×25   16 色 文本模式

#define SCREEN_HEIGHT			200		//圖象高度,像素單位
#define SCREEN_WIDTH 			320		//圖象寬度,像素單位

#define PALETTE_MASK 			0x3c6	//調色板屏蔽寄存器端口,放入0xff可以通過調色板索引寄存器0x3c7和0x3c8訪問你希望的寄存器
#define PALETTE_REGISTER_RD 	0x3c7	//讀顏色寄存器端口
#define PALETTE_REGISTER_WR 	0x3c8	//寫顏色寄存器端口
#define PALETTE_DATA 			0x3c9	//調色板數據寄存器端口

unsigned char far *video_buffer=(char far *)0xA0000000L;

typedef struct BMP_file
{
	unsigned int bfType;			//這裏恆定等於0x4D42,ASCII字符‘BM’
	unsigned long bfSize;			//文件大小,以字節爲單位
	unsigned int Reserved1;			//備用,必須爲0
	unsigned int reserved2;			//備用,必須爲0
	unsigned long bfOffset;			//數據區在文件中的位置偏移量,以字節爲單位
}bitmapfile;						//文件頭結構體,14 字節

typedef struct BMP_info
{
	unsigned long biSize;			//位圖信息頭大小,本結構所佔用字節數
	unsigned long biWidth;			//圖象寬度,像素單位
	unsigned long biHeight;			//圖象高度,像素單位
	unsigned int biPlanes;			//位平面樹,目標設備的級別,必須爲1
	unsigned int biBitCount;		//單位像素的位數,表示BMP圖片的顏色位數,必須是1(雙色 ),4(16色),8(256色),24位圖(真彩色),32位圖
	unsigned long biCompression;	//圖片壓縮屬性,必須爲:0(不壓縮),1(BI_RLE8壓縮類型)或2(BI_RLE4壓縮類型)之一
	unsigned long biSizeImage;		//表示圖片數據區的大小,當biBompression等於0時,這裏的值可以省略
	unsigned long biXpolsPerMeter;	//水平分辨率,每米像素數,可省略
	unsigned long biYpelsPerMeter;	//垂直分辨率,每米像素數,可省略
	unsigned long biClrUsed;		//表示使用了多少個顏色索引表,一般biBitCount屬性小於16纔會用到,等於0時表示有2^biBitCount個顏色索引表
	unsigned long biClrImportant;	//表示有多少個重要的顏色,等於0時表示所有顏色都很重要
}bitmapinfo;						//位圖信息頭,40 字節


typedef struct RGB_BMP_typ
{
	unsigned char blue;				//藍色的亮度(值範圍爲0-255)
	unsigned char green;			//綠色的亮度(值範圍爲0-255)
	unsigned char red;				//紅色的亮度(值範圍爲0-255)
	unsigned char reserved;			//保留,必須爲0
}RGB_BMP,*RGB_BMP_ptr;				//單個像素顏色結構體,4 字節

typedef struct bmp_picture_typ
{
	bitmapfile file;				//位圖文件頭
	bitmapinfo info;				//位圖信息頭
	RGB_BMP palette[256];			//位圖顏色表
} bmp_picture, *bmp_picture_ptr;	//位圖非數據區結構體

void Set_BMP_Palette_Register(int index,RGB_BMP_ptr color)		//設置調色板寄存器……
{
	outp(PALETTE_MASK,0xff);
	outp(PALETTE_REGISTER_WR,index);
	outp(PALETTE_DATA,color->red>>2);
	outp(PALETTE_DATA,color->green>>2);
	outp(PALETTE_DATA,color->blue>>2);
}

void Check_Bmp(bmp_picture_ptr bmp_ptr)		//檢測是否是BMP文件
{
	if(bmp_ptr->file.bfType!=0x4d42)
	{
		printf("Not a BMP file!\n");
		exit(1);
	}
	if(bmp_ptr->info.biCompression!=0)
	{
		printf("Can not display a compressed BMP file!\n");
		exit(1);
	}
	if(bmp_ptr->info.biBitCount!=8)
	{
		printf("Not a index 16 color BMP file!\n");
		exit(1);
	}
}


void BMP_Load_Screen(char *bmp)		//載入BMP文件並顯示……
{
	int i,j,fp,n_bytes;
	bmp_picture bmp256;	
	unsigned char line_buf[SCREEN_WIDTH];
	unsigned char far *line_ptr;
	
	if ((fp=open(bmp,O_RDONLY))==1)
	{
		printf("Can not open file:%s",bmp);
		exit(1);
	}

	read(fp,&bmp256.file,sizeof(bitmapfile));
	read(fp,&bmp256.info,sizeof(bitmapinfo));

	Check_Bmp((bmp_picture_ptr)&bmp256);
	/* lseek(fp,54,0); */
	for (i=0;i<256;i++)		//讀取文件顏色表數據
	{
		read(fp,&bmp256.palette[i].blue,1);
		read(fp,&bmp256.palette[i].green,1);
		read(fp,&bmp256.palette[i].red,1);
		read(fp,&bmp256.palette[i].reserved,1);
	}
	for (i=0;i<256;i++)
		Set_BMP_Palette_Register(i,(RGB_BMP_ptr)&bmp256.palette[i]);	//設置調色板寄存器……

	for(i=SCREEN_HEIGHT-1;i>=0;i--)		//顯示位圖
	{
		lseek(fp,-(long)(SCREEN_HEIGHT-i)*SCREEN_WIDTH,SEEK_END);		//定位讀取數據區
		n_bytes=read(fp,line_buf,SCREEN_WIDTH);							//讀取數據區數據
		line_ptr=video_buffer+(SCREEN_HEIGHT-i-1)*SCREEN_WIDTH;
		for(j=0;j<n_bytes;j++)			//將數據放入視頻圖形區
			line_ptr[j]=line_buf[j];
	}
	close(fp);
}

void Set_Video_Mode(int mode)		//設置顯示模式……
{
	union REGS inregs,outregs;
	inregs.h.ah=0;
	inregs.h.al=(unsigned char)mode;
	int86(0x10,&inregs,&outregs);
}

void main()
{
	Set_Video_Mode(VGA256);			//設置顯示模式爲320*200 256色
	BMP_Load_Screen("256.bmp");		//載入要顯示位圖並顯示
	getch();
	Set_Video_Mode(TEXT_MODE);		//設置迴文本模式
}


 

BMP格式詳解

位圖文件頭的格式:
typedef struct{
 int bfType;     //bfType(2字節),這裏恆定等於&H4D42,ASCII字符'BM'
 long bfSize;    //文件大小,以4字節爲單位
 int bfReserve1; //備用
 int bfReserve2; //備用
 long bfoffBits; //數據區在文件中的位置偏移量
}BITMAPFILEHEADER;  //文件頭結構體,14字節

typedef struct{
 long bitSize;        //位圖信息頭大小
 long biWidth;        //圖象寬度,像素單位
 long biHeight;       //圖象高度,像素單位
 int  biPlanes;       //位平面樹=1
 int  biBitCount;     //單位像素的位數,表示bmp圖片的顏色位數,即24位圖、32位圖
 long biCompression;  //圖片的壓縮屬性,bmp圖片是不壓縮的,等於0
 long biSizeImage;    //表示bmp圖片數據區的大小,當上一個屬性biCompression等於0時,這裏的值可以省略不填
 long biXPlosPerMeter;//水平分辨率,可省略
 long biYPlosPerMeter;//垂直分辨率,可省略
 long biClrUsed;      //表示使用了多少個顏色索引表,一般biBitCount屬性小於16纔會用到,等於0時表示有2^biBitCount個顏色索引表
 long biClrImportant; //表示有多少個重要的顏色,等於0時表示所有顏色都很重要
}BITMAPINFOHEADER;         //位圖信息頭,40字節

 

BMP文件詳解
1、BITMAPFILEHEADER結構體

一個bmp文件以BITMAPFILEHEADER結構體開始.

第1個屬性是bfType(2字節),這裏恆定等於&H4D42。由於內存中的數據排列高位在左,低位在右,所以內存中從左往右看就顯示成(42 4D),所以在UltraEdit中頭兩個 字節顯示爲(42 4D)就是這樣形成的,以後的數據都是這個特點,不再作重複說明。

第2個屬性是bfSize(4字節),表示整個bmp文件的大小,這裏等於&H000004F8=1272字節。

第3個、第4個屬性分別是bfReserved1、bfReserved2(各2字節),這裏是2個保留屬性,都爲0,這裏等於&H0000、&H0000。

第5個屬性是bfOffBits(4字節),表示DIB數據區在bmp文件中的位置偏移量,這裏等於&H00000076=118,表示數據區從文件開始往後數的118字節開始。

BITMAPFILEHEADER結構體這裏就講完了,大家會發現BITMAPFILEHEADER只佔了bmp文件開始的14字節長度,但需要 特別說明的是在vb中定義一個BITMAPFILEHEADER結構體變量,其長度佔了16個字節,原因就是第1個屬性本來應該只分配2個字節,但實際被 分配了4個字節,多出來2個字節,所以如果想保存一張bmp圖片,寫入BITMAPFILEHEADER結構體時一定要注意這一點。

 

2、BITMAPINFO結構體部分。

接下來是BITMAPINFO結構體部分.

BITMAPINFO段由兩部分組成:BITMAPINFOHEADER結構體和RGBQUAD結構體。
其中RGBQUAD結構體表示圖片的顏色信息,有些時候可以省略,一般的24位圖片和32位圖片都不帶RGBQUAD結構體,因爲DIB數據區直接表 示的RGB值,一般4位圖片和8位圖片才帶有RGBQUAD結構體。(多少位的圖片就是用多少位來表示一個顏色信息,例如4位圖片表示用4個bit來表示 一個顏色信息。)一個bmp文件中有沒有RGBQUAD結構體,可以根據前面BITMAPFILEHEADER結構體的第5個屬性bfOffBits來判 斷,因爲BITMAPINFOHEADER結構體長度爲40bit,如果BITMAPINFOHEADER結構體結束後還未到DIB數據區的偏移量,就說 明接下來的數據是RGBQUAD結構體部分。這裏講的C:\WINDOWS\Blue Lace 16.bmp是一個4bit圖片,所以它帶有 RGBQUAD結構體。

 

3、BITMAPINFOHEADER部分。

下面進入正題BITMAPINFOHEADER部分。

第1個屬性是biSize(4字節),表示BITMAPINFOHEADER結構體的長度,最常見的長度是40字節,UltraEdit中可以看到緊接着的4個字節等於&H00000028=40字節。

第2個屬性是biWidth(4字節),表示bmp圖片的寬度,這裏等於&H00000030=48像素。

第3個屬性是biHeight(4字節),表示bmp圖片的高度,這裏等於&H00000030=48像素。

第4個屬性是biPlanes(2字節),表示bmp圖片的平面屬,顯然顯示器只有一個平面,所以恆等於1,這裏等於&H0001。

第5個屬性是biBitCount(2字節),表示bmp圖片的顏色位數,即24位圖、32位圖等等。
這裏等於&H0004,表示該圖片爲4位圖。

第6個屬性是biCompression(4字節),表示圖片的壓縮屬性,bmp圖片是不壓縮的,等於0,所以這裏爲&H00000000。

第7個屬性是biSizeImage(4字節),表示bmp圖片數據區的大小,當上一個熟悉biCompression等於0時,這裏的值可以省略不填,所以這裏等於&H00000000。

第8個屬性是biXPelsPerMeter(4字節),表示圖片X軸每米多少像素,可省略,這裏等於&H00000EC3=3779像素/米。

第9個屬性是biYPelsPerMeter(4字節),表示圖片Y軸每米多少像素,可省略,這裏等於&H00000EC3=3779像素/米。

第10個屬性是biClrUsed(4字節),表示使用了多少個顏色索引表,一般biBitCount屬性小於16纔會用到,等於0時表示有2^biBitCount個顏色索引表,所以這裏仍等於&H00000000。

第11個屬性是biClrImportant(4字節),表示有多少個重要的顏色,等於0時表示所有顏色都很重要,所以這裏等於&H00000000。

至此BITMAPINFOHEADER結構體結束。

 

4、RGBQUAD結構體

由於這個圖片到這裏還未到達DIB數據區的偏移量,所以接下來的部分是RGBQUAD結構體。

RGBQUAD結構體由4個字節型數據組成,所以一 個RGBQUAD結構體只佔用4字節空間,從左到右每個字節依次表示(藍色,綠色,紅色,未使用)。舉例的這個圖片我數了數總共有16個RGBQUAD結 構體,由於該圖片是4位圖,2^4正好等於16,所以它把16種顏色全部都枚舉出來了,這些顏色就是一個顏色索引表。顏色索引表編號從0開始,總共16個 顏色,所以編號爲0-15。從UltraEdit中可以看到按照順序,這16個

RGBQUAD結構體依次爲:

編號:(藍,綠,紅,空)
0號:(00,00,00,00)
1號:(00,00,80,00)
2號:(00,80,00,00)
3號:(00,80,80,00)
4號:(80,00,00,00)
5號:(80,00,80,00)
6號:(80,80,00,00)
7號:(80,80,80,00)
8號:(C0,C0,C0,00)
9號:(00,00,FF,00)
10號:(00,FF,00,00)
11號:(00,FF,FF,00)
12號:(FF,00,00,00)
13號:(FF,00,FF,00)
14號:(FF,FF,00,00)
15號:(FF,FF,FF,00)

爲了更直觀的表示這些顏色,可以見後面的圖片。

到這裏,正好滿足DIB數據區的偏移量,所以後面的字節就是圖片內容了。這裏需要提醒的是所有的DIB數據掃描行是上下顛倒的,也就是說一幅圖片先繪製底部的像素,再繪製頂部的像素,所以這些DIB數據所表示的像素點就是從圖片的左下角開始,一直表示到圖片的右上角。

由於這裏的圖片是4位圖片,也就是說4bit就表示一個像素,一個字節有8個bit,所以一個字節能表示2個像素。

從UltraEdit中可以看到,DIB數據區第一個字節是&H44,16進制正好是將2進制數每4個一組書寫的,跟4bit圖片正好吻 合,所以&H44表示兩個像素,高位的4表示第一個像素,低位的4表示第二個像素。這裏的4不是表示RGB顏色,而是表示顏色索引號爲4,由於索 引號從0開始編號的,所以4表示索引表中第5個顏色,從附圖中可以看到索引號爲4的是藍色。這是第一字節,表示的是圖片左下角開始2個像素,如果有 PhotoShop打開這個圖片可以看到,左下角2個像素取出來的顏色RGB值正好等於索引表中第5個顏色的RGB值。後面的DIB數據以此類推。

至此一個bmp圖片就全部解析完了,根據這些信息就可以完整的繪製一張bmp圖片來。

============================================

如果你還不明白,還有:

1. BMP文件組成
BMP文件由文件頭、位圖信息頭、顏色信息和圖形數據四部分組成。
 
2. BMP文件頭
BMP文件頭數據結構含有BMP文件的類型、文件大小和位圖起始位置等信息。

其結構定義如下:

typedef struct tagBITMAPFILEHEADER
{
 WORDbfType;      // 位圖文件的類型,必須爲BM
 DWORD bfSize;    // 位圖文件的大小,以字節爲單位
 WORDbfReserved1; // 位圖文件保留字,必須爲0
 WORDbfReserved2; // 位圖文件保留字,必須爲0
 DWORD bfOffBits; // 位圖數據的起始位置,以相對於位圖文件頭的偏移量表示,以字節爲單位
} BITMAPFILEHEADER;

3. 位圖信息頭
BMP位圖信息頭數據用於說明位圖的尺寸等信息。

typedef struct tagBITMAPINFOHEADER{
 DWORD biSize;         // 本結構所佔用字節數
 LONGbiWidth;          // 位圖的寬度,以像素爲單位
 LONGbiHeight;         // 位圖的高度,以像素爲單位
 WORD biPlanes;        // 目標設備的級別,必須爲1
 WORD biBitCount       // 每個像素所需的位數,必須是1(雙色),4(16色),8(256色)或24(真彩色)之一
 DWORD biCompression;  // 位圖壓縮類型,必須是 0(不壓縮),1(BI_RLE8壓縮類型)或2(BI_RLE4壓縮類型)之一
 DWORD biSizeImage;    // 位圖的大小,以字節爲單位
 LONGbiXPelsPerMeter;  // 位圖水平分辨率,每米像素數
 LONGbiYPelsPerMeter;  // 位圖垂直分辨率,每米像素數
 DWORD biClrUsed;      // 位圖實際使用的顏色表中的顏色數
 DWORD biClrImportant; // 位圖顯示過程中重要的顏色數
} BITMAPINFOHEADER;

4. 顏色表
顏色表用於說明位圖中的顏色,它有若干個表項,每一個表項是一個RGBQUAD類型的結構,定義一種顏色。RGBQUAD結構的定義如下:

typedef struct tagRGBQUAD {
 BYTErgbBlue;     // 藍色的亮度(值範圍爲0-255)
 BYTErgbGreen;    // 綠色的亮度(值範圍爲0-255)
 BYTErgbRed;      // 紅色的亮度(值範圍爲0-255)
 BYTErgbReserved; // 保留,必須爲0
} RGBQUAD;

顏色表中RGBQUAD結構數據的個數有biBitCount來確定:
當biBitCount=1,4,8時,分別有2,16,256個表項;
當biBitCount=24時,沒有顏色表項。
位圖信息頭和顏色表組成位圖信息,
BITMAPINFO結構定義如下:

typedef struct tagBITMAPINFO {
 BITMAPINFOHEADER bmiHeader;  // 位圖信息頭
 RGBQUAD bmiColors[1];        // 顏色表
} BITMAPINFO;

5. 位圖數據
位圖數據記錄了位圖的每一個像素值,記錄順序是在掃描行內是從左到右,掃描行之間是從下到上。位圖的一個像素值所佔的字節數:

當biBitCount=1時,8個像素佔1個字節;
當biBitCount=4時,2個像素佔1個字節;
當biBitCount=8時,1個像素佔1個字節;
當biBitCount=24時,1個像素佔3個字節;
Windows規定一個掃描行所佔的字節數必須是4的倍數(即以long爲單位),不足的以0填充,
一個掃描行所佔的字節數計算方法:
DataSizePerLine= (biWidth* biBitCount+31)/8;   // 一個掃描行所佔的字節數
DataSizePerLine= DataSizePerLine/4*4;          // 字節數必須是4的倍數
位圖數據的大小(不壓縮情況下):
DataSize= DataSizePerLine* biHeight;
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章