做图像处理时的源文件一般要用无损的图像文件格式,位图(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;
- 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;
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;
用c++写的位图文件的读取与存储方法:
类结构(BitMap.h):
- #include <windows.h>
- 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);
- };
- #include "BitMap.h"
- #include <stdio.h>
- #include <iostream>
- #include <fstream>
- 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;
- }