使用C++读取8位BMP位图
2015-05-26 10:58
435 查看
使用C++读取8位BMP位图
一、 基础知识
微软的图像库关于位图的数据结构BITMAPFILEHEADER、BITMAPINFOHEADER位图存储时候的四字节对齐。
调色板的理解
二、八位图片的读取
细节见代码和注释。需要注意的是我们实际读的时候忽略了填充的字节(没必要)。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<windows.h> #include<stdio.h> int main() { int width,height,rwidth; BYTE *pFile; pFile=RmwRead8BitBmpFile2Img("D:\\test.bmp",&width,&height); RmwWriteByteImg2BmpFile(pFile,width,height,"D:\\test1.bmp"); }
Fig.1
Fig.2
五、说明
需要注意的地方是字节对齐而不是宽度对齐图像一个像素宽度在位深不同的情况下是不一样的。在8位图处理的时候宽度被4整除和字节被4整除等价(一个像素宽度对应一个字节),但是在24位的时候一个像素宽度由3个字节表示。所以这个时候不能以宽度为基准了。比如此时宽度为2,正确填充方式是一行有2*3=6个字节,再填充2个字节能被4整除。如果以宽度为基准,像素宽度扩为4,则填充了4*3-2*3=6个字节。可见结果是不同的。前一种是正确的处理方式。24位写的时候不需要写入调色板了。
相关文章推荐
- 毕业设计——使用vb访问BMP位图,如何读取位图分辨率
- 毕业设计——使用vb访问BMP位图,如何读取位图分辨率
- bmp位图文件:读取、写入、24位真彩转8位灰度、灰度图的二值化
- C++读取bmp位图入门
- 使用Excel的VBA来读取和修改bmp位图像素数据
- C++读取BMP位图数据的方法
- 图像识别 - C++读取bmp位图入门
- C++ BMP位图读取
- 图像识别-C++读取bmp位图入门
- C++读取bmp位图入门
- 图像识别 - C++读取bmp位图入门
- 图像识别 - C++读取bmp位图入门
- 图像识别 - C++读取bmp位图入门
- 【数字图像处理】<纯C++>读取、裁剪、缩放、旋转和存储8位bmp灰度图像
- 【数字图像处理】<纯C++>读取、裁剪、缩放、旋转和存储8位bmp灰度图像
- 【数字图像】C++8位和24位BMP位图的平滑、锐化、二值化处理,以及24位真彩图的灰度化
- C++读取BMP位图数据的方法
- C++ C语言 读取32位BMP图片转为8位灰度图
- C++8位和24位bmp位图平滑、锐化和二值处理,24位真彩图的灰度化
- C++ bmp位图读取