我的一个程序中需要将一个24位位图转为8位位图后保存,我的思路是在读取原图后得到原图的图像数据,然后重新申请内存空间,构造新的BITMAPFILEHEADER和BITMAPINFOR结构,里边包括BITMAPINFOHEADER和颜色表,之后是紧跟新的位图信息,然后再保存。我的思路对不对?有没有更好的方法?在生成新的位图数据时,新图每行所占的字节数变了,图像大小变了,那么在构造BITMAPFILEHEADER结构时它的那个bfSize和bfOffBits怎么确定?
调试欢乐多
bfOffBits灰度数据起始地址应该没什么变化吧真彩的255*255*255 size = 3 * width * height,灰度占一个byte,0~255
你说改成8位位图(256色)那么这个偏移量就是:
BITMAPFILEHEADER 14Byte
BITMAPINFOHEADER 40Byte
Palette 256*4=1024Byte
所以这个bfOffBits=14+40+1024=1078至于bfSize 是整个文件的大小 单位也是字节
就是 bfOffBits+biSizeImage(实际的位图数据占用的字节数)
你的文件是8位的 一个像素一个字节。biSizeImage=biWidth’*biHeight*1需要注意biWidth’是大于biWidth的最小4的整数倍。例如:如你的图像时799*600的 那么biWidth’=800
biSizeImage=800*600*1=48000
bfOffBits=1078
bfSize=1078+48000=49078
HANDLE hFile = ::CreateFile("E:\\bitmap.bmp",GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == 0)
{
MessageBox("不能打开文件,请重新选择!");
}
DWORD dwWriteNum;
BITMAPFILEHEADER Bmp_file_head; //文件头
ReadFile(hFile,&Bmp_file_head,14,&dwWriteNum,NULL);//读取文件头,共14个字节
if((Bmp_file_head.bfType != 'MB')||(dwWriteNum != sizeof(BITMAPFILEHEADER)))
{
MessageBox("不是BMP位图文件或数据有误!");
}
BITMAPINFOHEADER Bmp_info_head; //信息头
ReadFile(hFile,&Bmp_info_head,40,&dwWriteNum,NULL);
if(dwWriteNum != sizeof(BITMAPINFOHEADER))
{
MessageBox("读取信息头错误!");
}
//读取24位图像素数据
DWORD Bitmap_bit_len;
Bitmap_bit_len = Bmp_file_head.bfSize-sizeof(BITMAPFILEHEADER)-sizeof(BITMAPINFOHEADER);
BYTE *lpOldBmpData = new BYTE[Bitmap_bit_len];
ReadFile(hFile,lpOldBmpData,Bitmap_bit_len,&dwWriteNum,NULL);
if(dwWriteNum != Bitmap_bit_len)
{
MessageBox("位图像素数据读取错误!");
}
int nScanWidth; //转换后其每行扫描宽度
int nLineWidth; //将其转换成8位位图后每行宽度(即每行字节数)
int nSrcWidth,nSrcHeight;
nSrcHeight = Bmp_info_head.biHeight; //原24位位图高度(像素数)
nSrcWidth = Bmp_info_head.biWidth; //原24位位图宽度(像素数)
nLineWidth = ((nSrcWidth*3)/4)*4;
if(nLineWidth<nSrcWidth*3)
nLineWidth=nLineWidth+4; //保证以DWORD对齐(为4的整数倍)(原图象每行字节数)
nScanWidth=(nSrcWidth/4)*4;
if(nScanWidth<nSrcWidth)
nScanWidth=nScanWidth+4; //保证以DWORD对齐(为4的整数倍)(转换图象每行像素数)
//申请8位图的空间
int intnDataLen = nScanWidth*nSrcHeight;//+2; //原图像素数
BYTE * lpNewBmpData = new BYTE[intnDataLen];
//为8位位图像素赋值
for(int i=0;i<nSrcHeight;i++) //像素
{
for(int j=0;j<nSrcWidth;j++) //像素
{
BYTE color[3];
unsigned int dwColorTemp;
for(int s=0; s<3; s++)
color[s]=lpOldBmpData[i*nLineWidth+j*3+s];
dwColorTemp=unsigned int(color[2]*0.299+color[1]*0.587+color[0]*0.114);
if(dwColorTemp>255)
dwColorTemp=255;
if( dwColorTemp< 0 )
dwColorTemp = 0;
//***************the problem is here****************************//
lpNewBmpData[i*nScanWidth+j]=(unsigned char)dwColorTemp;
}
}
//设置8位位图调色板
RGBQUAD *rgbQuad = new RGBQUAD[256];
for(i=0;i<256;i++)
{
rgbQuad[i].rgbBlue = i;
rgbQuad[i].rgbGreen = i;
rgbQuad[i].rgbRed = i;
rgbQuad[i].rgbReserved = 0;
}
//设置8位位图文件头
BITMAPFILEHEADER Bmp_new_file_head;
Bmp_new_file_head.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
Bmp_new_file_head.bfReserved1 = Bmp_file_head.bfReserved1;
Bmp_new_file_head.bfReserved2 = Bmp_file_head.bfReserved2;
Bmp_new_file_head.bfType = Bmp_file_head.bfType;
Bmp_new_file_head.bfSize = Bmp_new_file_head.bfOffBits+intnDataLen;
//设置8位位图信息头
Bmp_info_head.biBitCount=8;
//关闭24位位图文件
if( !CloseHandle( hFile ) )
MessageBox("关闭文件时失败");
HANDLE hSaveFile = CreateFile("E:\\bitmap_8.bmp", GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if( !hSaveFile )
{
MessageBox( "创建文件出错");
}
//写位图文件头
WriteFile( hSaveFile, &Bmp_new_file_head, sizeof(BITMAPFILEHEADER), &dwWriteNum, NULL);
//写位图信息头
WriteFile( hSaveFile, &Bmp_info_head, sizeof(BITMAPINFOHEADER), &dwWriteNum, NULL);
//写位图调色板
WriteFile( hSaveFile, rgbQuad, 256*sizeof(RGBQUAD), &dwWriteNum, NULL);
//写位图像素数据
WriteFile( hSaveFile, lpNewBmpData, intnDataLen, &dwWriteNum, NULL);
//关闭8位位图
CloseHandle( hSaveFile );