意,Windows规定一个扫描行所占的字节数必须是 ??
? ? //4的倍数(即以long为单位),不足的以0填充,所以如果当前biWidth如果不是 ??
? ? //4的倍数时,要在后面补0直到为4的倍数 ??
? ? for(i = 0; i < bmpInfoHeader.biHeight; i++ ) ?
? ? { ?
? ? ? ? //位图数据(pBmpData)中存储的实际像素数为biWidth个,而一个扫描行要lineByte个字节, ??
? ? ? ? //多余出来的是上面补的0,所以要转换的要是实际的像素数, ??
? ? ? ? //因为转换前后biWidth是相同的,而lineByte是不同的,也就是后面补的0不同 ??
? ? ? ? //如果还有疑惑,请留言提问,我会即时回复 ??
? ? ? ? for(int j = 0; j < bmpInfoHeader.biWidth; j++ ) ?
? ? ? ? { ?
? ? ? ? ? ? red = *(pBmpData + i*oldLineBytes + 3*j ); ?
? ? ? ? ? ? green = *(pBmpData + i*oldLineBytes + 3*j + 1); ?
? ? ? ? ? ? blue = *(pBmpData + i*oldLineBytes + 3*j + 2); ?
? ? ? ? ? ? gray = (BYTE)((77 * red + 151 * green + 28 * blue) >> 8); ?
? ? ? ? ? ? *(pGrayData + i*lineBytes + j) = gray; ?
? ? ? ? } ?
? ? } ?
??
} ?
/**?
* 函数名: writeBmp?
* 参 ?数: fileName -- 转换之后的文件名?
* 功 ?能: 将转换后的图像信息写入到fileName文件中?
*/ ?
bool writeBmp(char *fileName) ?
{ ?
? ? FILE *fp = fopen(fileName,"wb"); ? //以二进制写方式打开 ??
? ? if(NULL == fp) ?
? ? { ?
? ? ? ? cout<<"File is opened failure!"<
? ? ? ? return FALSE; ?
? ? } ?
? ? //写入数据 ??
? ? fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp); ?
? ? fwrite(&bmpInfoHeader,sizeof(BITMAPINFOHEADER),1,fp); ?
? ? fwrite(pColorTable,sizeof(RGBQUAD),256,fp); ?
? ? fwrite(pGrayData,sizeof(unsigned char),bmpInfoHeader.biSizeImage,fp); ?
? ? fclose(fp); ?
? ? //释放内存空间 ??
? ? delete []pColorTable; ?
? ? delete []pBmpData; ?
? ? delete []pGrayData; ?
? ? return TRUE; ?
} ?
/**?
* 函数名: work?
* 功 ?能: 主要处理步骤?
*/ ?
void work() ?
{ ?
? ? char readFileName[] = "test1.bmp"; ?
? ? if(!readBmp(readFileName)) ?
? ? ? ? cout<<"The function of readBmp error!"<
? ? convert(); ?
? ? char writeFileName[] = "gray.bmp"; ?
? ? if(!writeBmp(writeFileName)) ?
? ? ? ? cout<<"The function of writebmp error!"<
? ? cout<<"convert success!"<
??
} ?
int main() ?
{ ?
? ? work(); ?
? ? return 0; ?
} ?
?
/**
* 程序名: Convert.cpp
* 功 ?能: 将24位真彩色图转换为8位灰度图片
*
?测试图片test1.bmp放到工程目录下
*/
#include
#include
#include
#include
using namespace std;
BITMAPFILEHEADER bmpFileHeader; //位图文件头
BITMAPINFOHEADER bmpInfoHeader; //位图信息头
RGBQUAD *pColorTable;
//颜色表,注:24位真彩色图无颜色表
unsigned char *pBmpData;
//位图数据
unsigned char *pGrayData;
//灰度图像数据
/**
* 函数名: readBmp
* 参 ?数: fileName -- 要转换的图片名
* 功 ?能: 读取fileName文件信息,读取成功返回TRUE,反之,返回FALSE
*/
bool readBmp(char *fileName)
{
FILE *fp = fopen(fileName,"rb");
//以二进制读方式打开
if(NULL == fp)
{
cout<<"File is opened failure!"<
return FALSE;
}
//读取数据
fread(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
fread(&bmpInfoHeader,sizeof(BITMAPINFOHEADER),1,fp);
pBmpData = new unsigned char[bmpInfoHeader.biSizeImage]; ? //申请空间,大小为位图数据大小
fread(pBmpData,sizeof(unsigned char),bmpInfoHeader.biSizeImage,fp);
fclose(fp);
//不要忘了关闭文件
return TRUE;
}
/**
* 函数名: convert
* 功 ?能: 实现24位真彩色图到灰度图的转换
*/
void convert()
{
//因为转换后多了个颜色表,所以要改变,对bmp文件结构不清楚的看笔记1
bmpFileHeader.bfOffBits += (sizeof(RGBQUAD) * 256);?
//biSizeImg存储的为位图数据占用的字节数,转换为灰度图像后值发生改变,
//因为24为真彩色位图数据的一个像素用3各字节表示,灰度图像为1个字节
bmpInfoHeader.biBitCount = 8;
int lineBytes = (bmpInfoHeader.biWidth * 8 + 31) / 32 * 4;
int oldLineBytes = (bmpInfoHeader.biWidth * 24 + 31) / 32 * 4;
int oldSize = bmpInfoHeader.biSizeImage;
//原图数据大小
bmpInfoHeader.biSizeImage = lineBytes * bmpInfoHeader.biHeight;
//定义灰度图像的颜色表
pColorTable = new RGBQUAD[256];
for(int i = 0; i < 256; i++ )
{
(*(pColorTable + i)).rgbBlue = i;
(*(pColorTable + i)).rgbGreen = i;
(*(