非常感谢Imageshop的指正,代码有修改,主要是:
- 计算8位位图像素位使用了更高效的整点运算;
- 去除多余的变量检测。
求网友们支招:在32位位图中有Alpha值,在转换成8位灰阶位图的时候可以直接省略吗?
在《我的第一个MFC小项目(3)之 位图转换》中,有关于将24位的彩色位图转换为8位的灰阶位图,发散一下就很容易可以得到32位位图彩图转换为8位的灰阶位图,看图:
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做图像处理的工程,是不是最好用单文档或者单文档之类的框架?
传送门:
捣乱小子 2011-12-20
ps:欢迎讨论