24位位图转8位位图时的文件头问题我的一个程序中需要将一个24位位图转为8位位图后保存,我的思路是在读取原
24位位图转8位位图时的文件头问题
我的一个程序中需要将一个24位位图转为8位位图后保存,我的思路是在读取原图后得到原图的图像数据,然后重新申请内存空间,构造新的BITMAPFILEHEADER和BITMAPINFOR结构,里边包括BITMAPINFOHEADER和颜色表,之后是紧跟新的位图信息,然后再保存。我的思路对不对?有没有更好的方法?在生成新的位图数据时,新图每行所占的字节数变了,图像大小变了,那么在构造BITMAPFILEHEADER结构时它的那个bfSize和bfOffBits怎么确定?
[解决办法]
你这其实就是转换成灰度图象,就按你的思路弄就行,只不过把各个象素值重新计算一下,用(R+G+B)/3代替即可。
[解决办法]
bfsize不就是 width*height 么?
bfOffBits灰度数据起始地址应该没什么变化吧
真彩的255*255*255 size = 3 * width * height,灰度占一个byte,0~255
[解决办法]
[解决办法]
LZ我想你说的8位位图应该是 8位彩色(256色)而不是256灰度吧?
没理解错吧?
[解决办法]
图像大小没变,bfSize是文件的大小,也就是文件头加上颜色表加上位图数据的大小;bfOffBits是位图数据的开始位置,也就是文件头加上颜色表的大小。
[解决办法]
- C/C++ code
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 );
