代码改变世界

我的第一个MFC小项目(4)之 位图转换(续)

2011-12-20 20:22  捣乱小子  阅读(2352)  评论(2编辑  收藏  举报

非常感谢Imageshop的指正,代码有修改,主要是:

  1. 计算8位位图像素位使用了更高效的整点运算;
  2. 去除多余的变量检测。

求网友们支招:在32位位图中有Alpha值,在转换成8位灰阶位图的时候可以直接省略吗?                                                                                            

我的第一个MFC小项目(3)之 位图转换中,有关于将24位的彩色位图转换为8位的灰阶位图,发散一下就很容易可以得到32位位图彩图转换为8位的灰阶位图,看图:

image 

 

 32位位图多出一个Alpha字节,用来描述图片的透明度,根据这一特性,可以将Alpha特意忽略,然后将紧跟其后的RGB按照我的第一个MFC小项目(3)之 位图转换中24位位图转8位灰阶位图的方法就可以很轻易地达到我们的目的。这一次的位图转换接口我优化了一下,下面给出代码

void Convertto8Bit(LPWSTR lpSrcFileName,LPWSTR lpDestFileName)
{
	HANDLE hFile;					//文件句柄
	DWORD dwWritten;			//记录以写入的字节数
	hFile   =   CreateFile(lpSrcFileName,GENERIC_READ,
	FILE_SHARE_READ,
	NULL,
	OPEN_EXISTING,
	FILE_FLAG_SEQUENTIAL_SCAN,
	NULL);

	BITMAPFILEHEADER  bmfh;					//文件头
	ReadFile(hFile,&bmfh,sizeof(BITMAPFILEHEADER),&dwWritten,NULL);

	BITMAPINFOHEADER   bmif;					//信息头
	ReadFile(hFile,&bmif,40,&dwWritten,NULL);  

	DWORD   dwSizeImage;						//源文件像素位大小
	dwSizeImage   =									//获取 像素位 的大小,分配空间
		bmif.biSizeImage;

	BYTE * pBits   =   new BYTE[dwSizeImage];   
	ReadFile(hFile,pBits,dwSizeImage,&dwWritten,NULL);

	::CloseHandle(hFile);

	long  lSrcWidth = bmif.biWidth;					//原图长与宽
	long lSrcHeight = bmif.biHeight;

	long lLineBytes;							//原图每行总字节数
	long lScanWidth;						//转换为8位图之后的宽度,必须是大于原图且为4的倍数

	lLineBytes = (lSrcWidth*4);			
	/*
	if(lLineBytes<lSrcWidth*4)					//在这里转换需要比原图每行总字节数大
		lLineBytes += 4;
	*/

	lScanWidth = (lSrcWidth/4)*4;			//8位位图的宽度必须为4的倍数,在这里转换需要比原图宽度大
	if(lScanWidth<lSrcWidth)
		lSrcWidth += 4;

	DWORD dwSizeNewImage = lSrcWidth * lSrcHeight + 2;			//为什么要预留两位呢
	BYTE * bits = new BYTE[dwSizeNewImage];

	for(int i=0; i<lSrcHeight; i++)
	{
		for(int j=0; j<lSrcWidth; j++)
		{
			BYTE color[3];						//对应RGB的红绿蓝值
			DWORD dwColorTemp;			//Y值,RGB转换为Y之后的值Y=0.299*R+0.587*G+0.114*B
			for(int s=0;s<3; s++)			//一个RGB对应一个Y值
				color[s]=pBits[i*lLineBytes+j*4+s+1];

			/*
			dwColorTemp=unsigned int(color[2]*0.299+color[1]*0.587+color[0]*0.114);     
			*/
			//换成更高效的计算,确实快很多
			dwColorTemp=unsigned int(color[2]*30+color[1]*59+color[0]*11+50)/100;     

			//多余的变量检测
			/*
			if(dwColorTemp>255)
				dwColorTemp = 255;
			if(dwColorTemp<0)
				dwColorTemp = 0;
			*/

			bits[i*lScanWidth+j]=(unsigned char)dwColorTemp;
		}
	}
	bits[dwSizeNewImage-1] = 0;
	bits[dwSizeNewImage-2] = 0;

	RGBQUAD   *rgbQuad   =   new   RGBQUAD[256];   //颜色表
	for(int i=0;i<256;i++)   
	{   
		rgbQuad[i].rgbBlue   =   i;     
		rgbQuad[i].rgbGreen   =   i;     
		rgbQuad[i].rgbRed   =   i;     
		rgbQuad[i].rgbReserved   =   0;     
	}   

	//完善8位位图的文件头和信息头字段

	bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) +
		sizeof(BITMAPINFOHEADER) + 
		256*sizeof(RGBQUAD);				//颜色表有256个

	bmfh.bfReserved1 = 0;
	bmfh.bfReserved2 = 0;
	
	bmfh.bfSize = bmfh.bfOffBits + dwSizeNewImage;			//size in byte of the file

	bmif.biBitCount = 8;															//信息头中bitcounts改为8
	bmif.biSizeImage =  dwSizeNewImage;

	//写入转换后得到的8位位图
	hFile=CreateFile(lpDestFileName,GENERIC_WRITE,
		FILE_SHARE_WRITE,NULL,
		CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
	::WriteFile(hFile,&bmfh,sizeof(BITMAPFILEHEADER),&dwWritten,NULL);
	::WriteFile(hFile,&bmif,sizeof(BITMAPINFOHEADER),&dwWritten,NULL);
	::WriteFile(hFile,rgbQuad,256*sizeof(RGBQUAD),&dwWritten,NULL);
	::WriteFile(hFile,bits,dwSizeNewImage,&dwWritten,NULL);
	::CloseHandle(hFile);
}

换汤不换药的。另外在这里问问大牛们,用MFC做图像处理的工程,是不是最好用单文档或者单文档之类的框架?

传送门:

我的第一个MFC小项目(3)之 位图转换


 捣乱小子 2011-12-20

ps:欢迎讨论