1. 程式人生 > >C++語言基礎 例程 案例:bmp檔案格式剖析

C++語言基礎 例程 案例:bmp檔案格式剖析

用程式讀出BMP檔案資訊

//readbmp.h
#ifndef READBMP_H_INCLUDED
#define READBMP_H_INCLUDED

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

typedef struct tagBITMAPFILEHEADER
{
    UINT bfType; /*說明檔案的型別*/
    DWORD bfSize; /*說明檔案的大小*/
    UINT bfReserved1; /*保留,設定為0 */
    UINT bfReserved2; /*保留,設定為0*/
    DWORD bfOffBits; /*到影象資料的偏移量*/
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER
{
    DWORD biSize; /*BITMAPINFOHEADER結構所需要的位元組數*/
    LONG biWidth; /*影象的寬度,以畫素為單位*/
    LONG biHeight; /*影象的高度,以畫素為單位*/
    WORD biPlanes; /*為目標裝置說明位面數,其值設定為1*/
    WORD biBitCount; /*位數/畫素*/
    DWORD biCompression; /*影象資料壓縮的型別:不壓縮,或4/8位RLE */
    DWORD biSizeImage; /*影象的大小,以位元組為單位。*/
    LONG biXPelsPerMeter; /*水平解析度,用畫素/米表示*/
    LONG biYPelsPerMeter; /*垂直解析度,用畫素/米表示*/
    DWORD biClrUsed; /*點陣圖使用的彩色表中的顏色索引數:2/16/256/224*/
    DWORD biClrImportant; /*對影象顯示有重要影響的顏色索引的數目,如果是0,表示都重要*/
} BITMAPINFOHEADER;


typedef struct tagRGBQUAD   /* rgbq */
{
    BYTE rgbBlue; /*指定藍色強度*/
    BYTE rgbGreen; /*指定綠色強度*/
    BYTE rgbRed; /*指定紅色強度*/
    BYTE rgbReserved; /*保留,設定為0 */
} RGBQUAD;

typedef struct tagBITMAPINFO
{
    BITMAPINFOHEADER bmiHeader; // 點陣圖資訊頭
    RGBQUAD bmiColors[16]; // 顏色表
} BITMAPINFO;

//畫素資訊
typedef unsigned char IMAGEDATA;

#endif // READBMP_H_INCLUDED

//main.cpp
#include "readbmp.h"
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <fstream>
using namespace std;

//變數定義
BITMAPFILEHEADER bmpHeader;   //檔案頭
BITMAPINFOHEADER bmpInfoHeader;     //檔案資訊頭
RGBQUAD *colorTable; //彩色表
IMAGEDATA *bmpData;

int main() 
{
    char bmpFileName[80]="bmp16bit.bmp";//bmp檔名
    ifstream bmpFile(bmpFileName, ios::in|ios::binary);
    if(!bmpFile)
    {
        cerr<<"open error!"<<endl;
        exit(1);//退出程式
    }
    /* 讀出點陣圖頭 */
    //由於“記憶體對齊問題(這部分為14位元組),無法一次性讀入所有資訊,此處逐個取出成員
    bmpFile.read((char*)&bmpHeader.bfType, sizeof(bmpHeader.bfType));
    bmpFile.read((char*)&bmpHeader.bfSize, sizeof(bmpHeader.bfSize));
    bmpFile.read((char*)&bmpHeader.bfReserved1, sizeof(bmpHeader.bfReserved1));
    bmpFile.read((char*)&bmpHeader.bfReserved1, sizeof(bmpHeader.bfReserved2));
    bmpFile.read((char*)&bmpHeader.bfOffBits, sizeof(bmpHeader.bfOffBits));
    /* 顯示點陣圖頭 */
    if(0x4d42!=bmpHeader.bfType)  //前兩個字元BM,其ASCII碼合成0x4d42,應該是固定的
    {
        cerr<<"not a bmp file!"<<endl;
        exit(1);
    }
    cout<<"點陣圖檔案頭:"<<endl;
    cout<<"檔案型別: BM"<<endl;
    cout<<"檔案大小:"<<hex<<bmpHeader.bfSize<<endl;  //hex:用16進位制輸出
    cout<<"保留字_1:"<<bmpHeader.bfReserved1<<endl;
    cout<<"保留字_2:"<<bmpHeader.bfReserved2<<endl;
    cout<<"實際點陣圖資料的偏移位元組數:"<<hex<<bmpHeader.bfOffBits<<endl<<endl;

    /* 讀出點陣圖資訊 */
    bmpFile.read((char*)&bmpInfoHeader, sizeof(bmpInfoHeader));
    /* 顯示點陣圖資訊 */
    cout<<"點陣圖資訊頭:"<<endl;
    cout<<"結構體的長度:"<<bmpInfoHeader.biSize<<endl;
    cout<<"點陣圖寬:"<<bmpInfoHeader.biWidth<<endl;
    cout<<"點陣圖高:"<<bmpInfoHeader.biHeight<<endl;
    cout<<"biPlanes平面數:"<<bmpInfoHeader.biPlanes<<endl;
    cout<<"biBitCount採用顏色位數:"<<bmpInfoHeader.biBitCount<<endl;
    cout<<"壓縮方式:"<<bmpInfoHeader.biCompression<<endl;
    cout<<"biSizeImage實際點陣圖資料佔用的位元組數:"<<bmpInfoHeader.biSizeImage<<endl;
    cout<<"X方向解析度:"<<bmpInfoHeader.biXPelsPerMeter<<endl;
    cout<<"Y方向解析度:"<<bmpInfoHeader.biYPelsPerMeter<<endl;
    cout<<"使用的顏色數:"<<bmpInfoHeader.biClrUsed<<endl;
    cout<<"重要顏色數:"<<bmpInfoHeader.biClrImportant<<endl<<endl;

    /*biClrUsed指定本圖象實際用到的顏色數,如果該值為零,則用到的顏色數為2^biBitCount*/
    int colorNum = bmpInfoHeader.biClrUsed;
    if(0==colorNum)
    {
        colorNum = pow(2, bmpInfoHeader.biBitCount);
    }
    colorTable = new RGBQUAD[colorNum];

    /* 讀取彩色表並顯示  */
    cout<<"所用顏色(R:G:B)"<<endl;
    int i;
    for(i=0; i<colorNum; i++)
    {
        bmpFile.read((char*)&colorTable[i].rgbBlue, 1);
        bmpFile.read((char*)&colorTable[i].rgbGreen, 1);
        bmpFile.read((char*)&colorTable[i].rgbRed, 1);
        bmpFile.read((char*)&colorTable[i].rgbReserved, 1);
        cout<<dec<<"["<<i<<"]="<<hex<<int(colorTable[i].rgbRed);
        cout<<":"<<int(colorTable[i].rgbGreen);
        cout<<":"<<int(colorTable[i].rgbBlue)<<endl;
    }
    cout<<endl;

    /*讀取畫素資訊*/
    bmpData = new unsigned char[bmpInfoHeader.biSizeImage];
    bmpFile.read((char*)bmpData, bmpInfoHeader.biSizeImage);

    /顯示畫素資訊:下面的顯示只提取了資料。BMP中的畫素資訊是從右上到左上儲存,在顯示影象時還需要要做處理*/
    /*牽涉到每畫素幾位-bmpInfoHeader.biBitCount-的問題,下面的程式碼,有點小繞*/
    int w, h;
    cout<<"下面是畫素資訊:"<<endl;
    for(h=0; h<bmpInfoHeader.biHeight; ++h)
    {
        cout<<"["<<setw(2)<<h<<"]: ";
        for(w=0; w < bmpInfoHeader.biSizeImage / bmpInfoHeader.biHeight; ++w)
        {
            cout<<setw(2)<<int(*(bmpData+h*bmpInfoHeader.biHeight*bmpInfoHeader.biBitCount/8+w))<<" ";
        }
        cout<<endl;
    }
    /*本程式只讀出了點陣圖資訊,要顯示出來,需要呼叫輸出裝置的功能了,此處略過*/
    delete[] bmpData;
    delete[] colorTable;
    return 0;
}