细节见代码和注释。需要注意的是我们实际读的时候忽略了填充的字节(没必要)。
BYTE *RmwRead8BitBmpFile2Img(const char * filename,int *width,int *height){
FILE *binFile;
BYTE *pImg=NULL;
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER bmpHeader;
BOOL isRead=TRUE;
int linenum,ex; //linenum:一行像素的字节总数,包括填充字节
//open file
if((binFile=fopen(filename,"rb"))==NULL) return NULL;
//read struts
if(fread((void *)&fileHeader,1,sizeof(fileHeader),binFile)!=sizeof(fileHeader)) isRead=FALSE;
if(fread((void *)&bmpHeader,1,sizeof(bmpHeader),binFile)!=sizeof(bmpHeader)) isRead=FALSE;
//问,这里的判断是为了避免什么样问题
if(isRead==FALSE||fileHeader.bfOffBits<sizeof(fileHeader)+sizeof(bmpHeader)){
fclose(binFile);
return NULL;
}
//read image info
*width=bmpHeader.biWidth;
*height=bmpHeader.biHeight;
linenum=(*width*1+3)/4*4;
ex=linenum-*width*1; //每一行的填充字节
fseek(binFile,fileHeader.bfOffBits,SEEK_SET);
pImg=new BYTE[(*width)*(*height)];
if(pImg!=NULL){
for(int i=0;i<*height;i++){
int r=fread(pImg+(*height-i-1)*(*width),sizeof(BYTE),*width,binFile);
if(r!=*width){
delete pImg;
fclose(binFile);
return NULL;
}
fseek(binFile,ex,SEEK_CUR);
}
}
fclose(binFile);
return pImg;
}
下面给出的代码用调色板把原图Fig.1变成Fig.2的样子。这么做是为了强调调色板的作用。如果需要正常的存8位图稍微修改调色板那一部分(下代码中注释了)就行了。
bool RmwWriteByteImg2BmpFile(BYTE *pImg,int width,int height,const char * filename)
{ FILE * BinFile;
BITMAPFILEHEADER FileHeader;
BITMAPINFOHEADER BmpHeader;
int i,extend;
bool Suc=true;
BYTE p[4],*pCur;
BYTE* ex;
extend=(width+3)/4*4-width;
// Open File
if((BinFile=fopen(filename,"w+b"))==NULL) { return false; }
//参数填法见结构链接
FileHeader.bfType= ((WORD) ('M' << 8) | 'B');
FileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*4L;//2个头结构后加调色板
FileHeader.bfSize=FileHeader.bfOffBits+(width+extend)*height;
FileHeader.bfReserved1=0;
FileHeader.bfReserved2=0;
if (fwrite((void *)&FileHeader,1,sizeof(FileHeader),BinFile)!=sizeof(FileHeader)) Suc=false;
// Fill the ImgHeader
BmpHeader.biSize = 40;
BmpHeader.biWidth = width;
BmpHeader.biHeight = height;
BmpHeader.biPlanes = 1 ;
BmpHeader.biBitCount = 8 ;
BmpHeader.biCompression = 0 ;
BmpHeader.biSizeImage = 0 ;
BmpHeader.biXPelsPerMeter = 0;
BmpHeader.biYPelsPerMeter = 0;
BmpHeader.biClrUsed = 0;
BmpHeader.biClrImportant = 0;
if (fwrite((void *)&BmpHeader,1,sizeof(BmpHeader),BinFile)!=sizeof(BmpHeader)) Suc=false;
// 写入调色板
for (i=0,p[3]=0;i<256;i++)
{
p[0]=p[1]=p[2]=255-i; // blue,green,red;
if (fwrite((void *)p,1,4,BinFile)!=4) { Suc=false; break; }
}
if(extend)
{
ex=new BYTE[extend]; //填充数组大小为 0~3
memset(ex,0,extend);
}
//write data
for(pCur=pImg+(height-1)*width;pCur>=pImg;pCur-=width)
{
if (fwrite((void *)pCur,1,width,BinFile)!=(unsigned int)width) Suc=false; // 真实的数据
if(extend) // 扩充的数据 这里填充0
if (fwrite((void *)ex,1,extend,BinFile)!=1) Suc=false;
}
// return;
fclose(BinFile);
if(extend)
delete[] ex;
return Suc;
}
主调函数:
#include
#include
int main()
{
int width,height,rwidth;
BYTE *pFile;
pFile=RmwRead8BitBmpFile2Img("D:\\test.bmp",&width,&height);
RmwWriteByteImg2BmpFile(pFile,width,height,"D:\\test1.bmp");
}