位图BitMap图像的读取与存储

    做图像处理时的源文件一般要用无损的图像文件格式,位图(BitMap)是windows系统下可存储无压缩图像的文件格式。要实现位图文件的读取和存储,首先要明白位图文件的的存储数据结构。位图文件由四部分依序组成:BITMAPFILEHEADER,BITMAPINFOHEADER,调色板,Image Data。

1)BITMAPFILEHEADER结构的长度是固定的14个字节,描述文件的有关信息。其数据结构是:

typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;//must be 0x4D42.
        DWORD   bfSize;//the size of the whole bitmap file.
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;//the sum bits of BITMAPFILEHEADER,BITMAPINFOHEADER and RGBQUAD;the index byte of the image data.
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
2)BITMAPINFOHEADER结构的长度是固定的40个字节,描述图像的有关信息。其数据结构是:
typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;//the size of this struct.it is 40 bytes.
        LONG       biWidth;//the width of image data. the unit is pixel.
        LONG       biHeight;//the height of image data. the unit is pixel.
        WORD       biPlanes;//must be 1.
        WORD       biBitCount;//the bit count of each pixel.usually be 1,4,8,or 24.
        DWORD      biCompression;//is this image compressed.0 indicates no compression.
        DWORD      biSizeImage;//the size of image data.
        LONG       biXPelsPerMeter;
        LONG       biYPelsPerMeter;
        DWORD      biClrUsed;
        DWORD      biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
    值得注意的是,其中biSizeImage指的是实际图像数据的大小,以字节为单位。其计算公式是:宽*高。其中宽必须是4的整数倍。如果不是整数倍,则取大于宽的离4的整数倍最近的数值。这个要求可能是因为现在的计算机大都是32位4字节的,计算机每次读取4字节,这样每行的像素可以整数次读取完成。

3)调色板:现在的计算机大都是32位或是更高,于是图像数据可用真彩色24位表达的,即每个像素均由24bit表示,每8bit表示RGB三色中的一色。但以前的计算机处理能力较差,图像用1位、4位或8位,即BITMAPINFOHEADER中的biBitCount不是24,这时又想表达出RGB色彩就需要调色板,调色板即使将图像数据中使用的一种颜色对应到RGB颜色中,这样图像数据中的像素值就是一个索引值,真正的像素值是这个索引值对应的调色板中的值。调色板是一个数组,数组中每个元素就是一个rgb颜色,对于8位图像,最多可表达256种颜色,调色板的大小就是256。调色板数组中每个元素的数据结构:

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;
        BYTE    rgbGreen;
        BYTE    rgbRed;
        BYTE    rgbReserved;
} RGBQUAD;
typedef RGBQUAD FAR* LPRGBQUAD;
4)图像数据对于1位图像,1个像素用1bit存储,对于24位图像,1个像素用24bit存储。位图文件的数据是从下而上,从左而右存储的。所以说,读取的时候,最先读到的是图像左下方的像素,最后读取的是图像右上方的图像。

用c++写的位图文件的读取与存储方法:
类结构(BitMap.h):
#include 
class BitMap
{
public:
    BitMap();
    ~BitMap();
protected:
    BITMAPFILEHEADER fileHeader;
    BITMAPINFOHEADER infoHeader;
public:
    int width_p,height_p,bitCount;
    unsigned char *dataBuf;
    LPRGBQUAD colorTable;
    bool Read(char *fileName);
    bool Write(char *_fileName);   
};
方法(BitMap.cpp):
#include "BitMap.h"
#include 
#include 
#include 
using namespace std;
#define NULL 0

BitMap::BitMap(){};
BitMap::~BitMap(){};

//read bitmap info from a file
bool BitMap::Read(char* fileName)
{
    FILE *_f=fopen(fileName,"rb");//open file
    if(_f==NULL) return false;

    fread(&fileHeader,sizeof(BITMAPFILEHEADER),1,_f);//read BITMAPFILEHEADER

    fread(&infoHeader,sizeof(BITMAPINFOHEADER),1,_f);//read BITMAPINFOHEADER
    width_p=infoHeader.biWidth;
    height_p=infoHeader.biHeight;
    bitCount=infoHeader.biBitCount;

    if(bitCount==8)//if colorTable exist,read colorTable
    {
        colorTable=new RGBQUAD[256];
        fread(&colorTable,sizeof(RGBQUAD),256,_f);
    }

    dataBuf=new unsigned char[infoHeader.biSizeImage];//read image data
    fread(dataBuf,1,infoHeader.biSizeImage,_f);

    fclose(_f);//close file
    return true;
}

//write bitmap info to a file
bool BitMap::Write(char * _fileName)
{
    FILE* f=fopen(_fileName,"wb");//create or open file to be written
    if(f==NULL) return false;

    int colorTableSize=0;//if bitcount is 24, there is no color table.
    if(bitCount==8)//if bitcount is 8 ,the size of color table is 256*4,4B is the size of RGBQUAD.
        colorTableSize=sizeof(RGBQUAD)*256;

    int headerSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+ colorTableSize;//the size of the header of bmp file.
    int lineSize=(width_p*bitCount/8+3)/4*4;//the size of each line in bmp file.
    int dataSize=lineSize*height_p;//the size of the image data of bmp file.
   
    fileHeader.bfType=0x4D42;//set the attribute of BITMAPFILEHEADER
    fileHeader.bfSize=headerSize+dataSize;
    fileHeader.bfReserved1=0;
    fileHeader.bfReserved2=0;
    fileHeader.bfOffBits=headerSize;

    infoHeader.biSize=40;//set the attribute of BITMAPINFOHEADER
    infoHeader.biWidth=width_p;
    infoHeader.biHeight=height_p;
    infoHeader.biPlanes=1;
    infoHeader.biBitCount=bitCount;
    infoHeader.biCompression=0;
    infoHeader.biSizeImage=dataSize;
    infoHeader.biClrImportant=0;
    infoHeader.biXPelsPerMeter=0;
    infoHeader.biYPelsPerMeter=0;

    fwrite(&fileHeader,sizeof(BITMAPFILEHEADER),1,f);//write the data of BITFILEHEADER to bmp file
    fwrite(&infoHeader,sizeof(BITMAPINFOHEADER),1,f);//write the data of BITINFOHEADER to bmp file
    if(bitCount==8)//if color table exists,write the data of color table to bmp file
    {
        colorTable=new RGBQUAD[256];
        fwrite(&colorTable,sizeof(RGBQUAD),256,f);
    }
    fwrite(dataBuf,1,dataSize,f);//write the image data to bmp file

    fclose(f);//data writting is finished,close the bmp file.
    return true;
}
程序入口:
void main()
{
    BitMap* bm=new BitMap();
    bm->Read("nv.BMP");
    bm->Write("nvnew.bmp");
    delete bm;
}

你可能感兴趣的:(图像处理)