程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> DOS下顯示8位256色BMP位圖

DOS下顯示8位256色BMP位圖

編輯:關於C

 

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved