非常感谢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:欢迎讨论