Bitmap 格式

Bitmap是Windows操作系統中的標準圖像文件格式,可以分成兩類:設備相關位圖(DDB)和設備無關位圖(DIB),DDB已經基本停用。

Bitmap格式有4部分組成: 文件頭、圖像描述、顏色表(在真彩色(24或32位)模式無顏色表)和圖像數據區

1. 文件頭  14B

2B    0000-0001:文件標識,爲字母ASCII碼“BM”,即0x4d42
4B    0002-0005:文件大小,字節數,最大爲4G
4B    0006-0009:保留,每字節以“00”填寫。
4B    000A-000D:記錄圖像數據區的起始位置。各字節的信息依次含義爲:文件頭信息塊大小,圖像描述信息塊的大小,圖像顏色表的大小,保留(爲01)。


數據類型定義:(32位系統下的定義;64位系統下在編譯時需要加入-m32)

typedef unsigned char BYTE;               // 1B
typedef unsigned short WORD;           // 2B
typedef unsigned long DWORD;          // 4B
typedef long LONG;                            // 4B

文件頭結構定義

typedef struct tagBITMAPFILEHEADER {

    WORD magic; // "BM",即0x4d42
    DWORD bfSize; //文件大小 
    WORD bfReserved1; //保留字,不考慮 
    WORD bfReserved2; //保留字,同上 
    DWORD bfOffBits; //實際位圖數據的偏移字節數,即前三個部分長度之和
} BITMAPFILEHEADER;

2. 圖像描述      40B

4B    000E-0011:圖像描述信息塊的大小,常爲40。 

4B    0012-0015:圖像寬度。

4B    0016-0019:圖像高度。

2B    001A-001B:圖像的plane(平面?)總數(恆爲1)。

2B    001C-001D:記錄像素的位數,很重要的數值,圖像的顏色數由該值決定。

4B    001E-0021:數據壓縮方式(數值位0:不壓縮;1:8位壓縮;2:4位壓縮)。

4B    0022-0025:圖像區數據的大小。 

4B    0026-0029:水平每米有多少像素,在設備無關位圖(.DIB)中,每字節以00H填寫。 

4B    002A-002D:垂直每米有多少像素,在設備無關位圖(.DIB)中,每字節以00H填寫。

4B    002E-0031:此圖像所用的顏色數,如值爲0,表示所有顏色一樣重要。

4B    0032-0035:重要的顏色數

圖像信息描述結構

typedef struct tagBITMAPINFOHEADER{
    DWORD biSize; //指定此結構體的長度,爲40
    LONG biWidth; //位圖寬
    LONG biHeight; //位圖高
    WORD biPlanes; //平面數,爲1
    WORD biBitCount; //採用顏色位數,可以是1,2,4,8,16,24,新的可以是32
    DWORD biCompression; //壓縮方式,可以是0,1,2,其中0表示不壓縮
    DWORD biSizeImage; //實際位圖數據佔用的字節數
    LONG biXPelsPerMeter; //X方向分辨率
    LONG biYPelsPerMeter; //Y方向分辨率
    DWORD biClrUsed; //使用的顏色數,如果爲0,則表示默認值(2^顏色位數)
    DWORD biClrImportant; //重要顏色數,如果爲0,則表示所有顏色都是重要的
} BITMAPINFOHEADER;


不包含顏色表的數據頭大小爲54B


3. 顏色表

    在真彩色(24或32位)模式無顏色表

    其他色彩圖像的顏色表的大小根據所使用的顏色模式而定:

              2色圖像的顏色表大小是8字節;16色圖像的顏色表大小是64字節;256色圖像顏色表大小是1024字節。

             其中,每4字節表示一種顏色,並以B(藍色)、G(綠色)、R(紅色)、alpha(像素的透明度值,一般不需要)。即首先4字節表示顏色號0的顏色,接下來表示顏色號1的顏色,依此類推。

             以16色圖像爲例:每一種顏色是4B,所以顏色表大小就是16*4=64B。

4 圖像數據區

    注意情況: 每種顏色模式的行字節數要用數據“00”補齊爲4的整數倍

    16色圖像,圖像寬爲19,存儲時每行則要補充4-(19/2+1)%4=2個字節(加1是因爲裏面有一個像素點要獨佔了一字節)。

    256色圖像,圖像寬爲19,每行也要補充4-19%4=1個字節。

    24位色彩圖,圖像寬爲19,每行也要補充4-(19*3)%4=3個字節。

    32位色彩圖,圖像寬爲19,每行也要補充4-(19*4)%4=0個字節,即無需補字節,本身已經是4B對齊了


參考程序

#include <stdio.h>
#include <stdlib.h>

#define WIDTHBYTES(bits) (((bits)+31)/32*4)

typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;


//位圖文件頭信息結構定義
//其中不包含文件類型信息(由於結構體的內存結構決定,要是加了的話將不能正確讀取文件信息)
typedef struct tagBITMAPFILEHEADER {
    DWORD bfSize; //文件大小
    WORD bfReserved1; //保留字,不考慮
    WORD bfReserved2; //保留字,同上
    DWORD bfOffBits; //實際位圖數據的偏移字節數,即前三個部分長度之和
} BITMAPFILEHEADER;


//信息頭BITMAPINFOHEADER,也是一個結構,其定義如下:
typedef struct tagBITMAPINFOHEADER{
    //public:
    DWORD biSize; //指定此結構體的長度,爲40
    LONG biWidth; //位圖寬
    LONG biHeight; //位圖高
    WORD biPlanes; //平面數,爲1
    WORD biBitCount; //採用顏色位數,可以是1,2,4,8,16,24,新的可以是32
    DWORD biCompression; //壓縮方式,可以是0,1,2,其中0表示不壓縮
    DWORD biSizeImage; //實際位圖數據佔用的字節數
    LONG biXPelsPerMeter; //X方向分辨率
    LONG biYPelsPerMeter; //Y方向分辨率
    DWORD biClrUsed; //使用的顏色數,如果爲0,則表示默認值(2^顏色位數)
    DWORD biClrImportant; //重要顏色數,如果爲0,則表示所有顏色都是重要的
} BITMAPINFOHEADER;


//調色板Palette,當然,這裏是對那些需要調色板的位圖文件而言的。24位和32位是不需要調色板的。
//(似乎是調色板結構體個數等於使用的顏色數。)
typedef struct tagRGBQUAD {
    //public:
    BYTE rgbBlue; //該顏色的藍色分量
    BYTE rgbGreen; //該顏色的綠色分量
    BYTE rgbRed; //該顏色的紅色分量
    BYTE rgbReserved; //保留值
} RGBQUAD;

void showBmpHead(BITMAPFILEHEADER* pBmpHead)
{
    printf("位圖文件頭:\n");
    printf("文件大小:%d\n",pBmpHead->bfSize);
    printf("保留字:%d\n",pBmpHead->bfReserved1);
    printf("保留字:%d\n",pBmpHead->bfReserved2);
    printf("實際位圖數據的偏移字節數:%d\n",pBmpHead->bfOffBits);
}

void showBmpInforHead(BITMAPINFOHEADER* pBmpInforHead)
{
    printf("位圖信息頭:\n");
    printf("結構體的長度:%d\n",pBmpInforHead->biSize);
    printf("位圖寬:%d\n",pBmpInforHead->biWidth);
    printf("位圖高:%d\n",pBmpInforHead->biHeight);
    printf("biPlanes平面數:%d\n",pBmpInforHead->biPlanes);
    printf("biBitCount採用顏色位數:%d\n",pBmpInforHead->biBitCount);
    printf("壓縮方式:%d\n",pBmpInforHead->biCompression);
    printf("biSizeImage實際位圖數據佔用的字節數:%d\n",pBmpInforHead->biSizeImage);
    printf("X方向分辨率:%d\n",pBmpInforHead->biXPelsPerMeter);
    printf("Y方向分辨率:%d\n",pBmpInforHead->biYPelsPerMeter);
    printf("使用的顏色數:%d\n",pBmpInforHead->biClrUsed);
    printf("重要顏色數:%d\n",pBmpInforHead->biClrImportant);
}

void showRgbQuan(RGBQUAD* pRGB)
{
    printf("(%-3d,%-3d,%-3d) ",pRGB->rgbRed,pRGB->rgbGreen,pRGB->rgbBlue);
}

void main()
{
#ifdef __x86_64__
    printf("__x86_64__\n");
#elif __i386__
    printf("__i386__\n");
#endif

    BITMAPFILEHEADER bitHead;
    BITMAPINFOHEADER bitInfoHead;
    FILE* pfile;

    char strFile[50];
    printf("please input the .bmp file name:\n");
    scanf("%s",strFile);

    pfile = fopen(strFile,"rb");//打開文件

    if(pfile!=NULL) {
        printf("file bkwood.bmp open success.\n");
        //讀取位圖文件頭信息
        WORD fileType;
        fread(&fileType,1,sizeof(WORD),pfile);
        if(fileType != 0x4d42) {<span style="color:#ff0000;">   // 將magic單獨出來,沒有放到頭信息裏處理,來判斷該文件是否時bitmap文件</span>
            printf("file is not .bmp file!");
            return;
        }
        fread(&bitHead,1,sizeof(BITMAPFILEHEADER),pfile);

        showBmpHead(&bitHead);
        printf("\n\n");

        //讀取位圖信息頭信息
        fread(&bitInfoHead,1,sizeof(BITMAPINFOHEADER),pfile);
        showBmpInforHead(&bitInfoHead);
        printf("\n");
    } else {
        printf("file open fail!\n");
        return;
    }

    RGBQUAD *pRgb ;

    int width = bitInfoHead.biWidth;
    int height = bitInfoHead.biHeight;
    //分配內存空間把源圖存入內存
    int l_width = WIDTHBYTES(width* bitInfoHead.biBitCount);//計算位圖的實際寬度並確保它爲32的倍數
    BYTE *pColorData=(BYTE *)malloc(height*l_width);
    memset(pColorData,0,height*l_width);
    long nData = height*l_width;

    //把位圖數據信息讀到數組裏
    fread(pColorData,1,nData,pfile);

    //將位圖數據轉化爲RGB數據
    RGBQUAD* dataOfBmp;
    dataOfBmp = (RGBQUAD *)malloc(width*height*sizeof(RGBQUAD));//用於保存各像素對應的RGB數據
    memset(dataOfBmp,0,width*height*sizeof(RGBQUAD));

    int k = 0;
    int i = 0, j = 0, index = 0;
    for(;i<height;i++) {
        for(j=0;j<width;j++) {
            k = i*l_width + j*3;
            dataOfBmp[index].rgbRed = pColorData[k+2];
            dataOfBmp[index].rgbGreen = pColorData[k+1];
            dataOfBmp[index].rgbBlue = pColorData[k];
            index++;
        }
    }


    printf("像素數據信息:\n");
    for (i=0; i<width*height; i++) {
        if (i%5==0) {
            printf("\n");
        }
        showRgbQuan(&dataOfBmp[i]);
    }

    fclose(pfile);
    if (bitInfoHead.biBitCount<24) {
        free(pRgb);
    }
    free(dataOfBmp);
    free(pColorData);
    printf("\n");
}

編譯時需要注意:

         如果是64位,需要使用-m32參數。例如gcc main.c -m32

         這是因爲某些數據類型如long,在32和64是不同的



參考文章: http://blog.sina.com.cn/s/blog_523491650100fk1z.html

這裏有詳細的帶有顏色表的bitmap的處理






發佈了66 篇原創文章 · 獲贊 16 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章