int iPixel = 24;
HANDLE hp; BITMAP bmpScreen; // Get the BITMAP from the HBITMAP
GetObject(hBitmap,sizeof(BITMAP),&bmpScreen); //图形格式参数
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi; bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = iPixel;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0; DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight; // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize+sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
*lpbi = bi;
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbi
GetDIBits(hMemDC,hBitmap,0,
(UINT)bmpScreen.bmHeight,
lpbi,
(BITMAPINFO *)lpbi, DIB_RGB_COLORS);
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); //Size of the file
bmfHeader.bfSize = dwSizeofDIB; //bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM if(file.Open(szBMPFileName,CFile::modeWrite | CFile::modeCreate))
{
file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER));
file.Write(&bi,sizeof(BITMAPINFOHEADER));
file.Write(lpbi,dwBmpSize);
file.Close();
}以上代码能正确保存为BMP文件!红色处不明白,还请教!
lpbi中已包含有信息头,位图信息头为什么要写两次到BMP文件中呢?
HANDLE hp; BITMAP bmpScreen; // Get the BITMAP from the HBITMAP
GetObject(hBitmap,sizeof(BITMAP),&bmpScreen); //图形格式参数
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bi; bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmpScreen.bmWidth;
bi.biHeight = bmpScreen.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = iPixel;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0; DWORD dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen.bmHeight; // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc
// have greater overhead than HeapAlloc.
HANDLE hDIB = GlobalAlloc(GHND,dwBmpSize+sizeof(BITMAPINFOHEADER));
LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
*lpbi = bi;
// Gets the "bits" from the bitmap and copies them into a buffer
// which is pointed to by lpbi
GetDIBits(hMemDC,hBitmap,0,
(UINT)bmpScreen.bmHeight,
lpbi,
(BITMAPINFO *)lpbi, DIB_RGB_COLORS);
// Add the size of the headers to the size of the bitmap to get the total file size
DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //Offset to where the actual bitmap bits start.
bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); //Size of the file
bmfHeader.bfSize = dwSizeofDIB; //bfType must always be BM for Bitmaps
bmfHeader.bfType = 0x4D42; //BM if(file.Open(szBMPFileName,CFile::modeWrite | CFile::modeCreate))
{
file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER));
file.Write(&bi,sizeof(BITMAPINFOHEADER));
file.Write(lpbi,dwBmpSize);
file.Close();
}以上代码能正确保存为BMP文件!红色处不明白,还请教!
lpbi中已包含有信息头,位图信息头为什么要写两次到BMP文件中呢?
file.Write(&bi,sizeof(BITMAPINFOHEADER)); //将bmp写到文件,这是写bmp的文件头部!
file.Write(lpbi,dwBmpSize); //具体的内容!
lpbi指的内存中,不是已经包含有位图信息头了吗?就是包含过BITMAPINFOHEADER,为什么写两次呢?
这个没有写内容,写的是BMP头部,sizeof(BITMAPINFOHEADER)只有40字节!
file.Write(lpbi,dwBmpSize); //具体的内容!是写具体内容,
现在问题是我发现,lpbi具体内容存储空间的前40字节,已经是BMP头部的,这两行代码等于把头总信息写了两次到BMP文件中!
这个问题是不是和 GetDIBits(hMemDC,hBitmap,0,(UINT)bmpScreen.bmHeight, lpbi,
(BITMAPINFO *)lpbi, DIB_RGB_COLORS); 有关?
HDC hdc, // handle to device context
HBITMAP hbmp, // handle to bitmap
UINT uStartScan, // first scan line to set in destination bitmap
UINT cScanLines, // number of scan lines to copy
LPVOID lpvBits, // address of array for bitmap bits
LPBITMAPINFO lpbi, // address of structure with bitmap data
UINT uUsage // RGB or palette index
);
看楼主对这个函数的用法,那习惯不是一种好的习惯,其结果之一就像现有楼主的疑惑一样就产生了。倒数第二个参数lpbi是一个信息结构体指针,它指明了要获取到的BMP数据格式,而倒数第三个则是保存获取到的DIB数据。楼主把这两个参数用同一变量,虽然在调用该函数之前,对lpbi进行了附值,但在函数返回之后,里面的内容即被破坏掉,因为它被DIB数据覆盖掉了。所以楼主可以跟踪一下,在调用返回之后,你的lpbi里的内容,还是不是你在调用之前附值之后的那些东西,肯定不是!a
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;
BITMAPINFO内含有头部信息!所以,在GetDIBits中,(BITMAPINFO *)lpbi算输入与输出参数吧,输入的是BITMAPINFOHEADER ,然后,输出的是RGBQUAD!应该是这样的!
建议楼主调试跟踪一下看看!还有,建议楼主把前面的几个文件头部去掉看看是否可以!我也觉的多写了!
楼上的,我也试过, file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER));
file.Write(&bi,sizeof(BITMAPINFOHEADER));
file.Write(lpbi,dwBmpSize);
第二行是不能去的,去掉,就保存失败了!去掉换成下面的,能保存成功,不过图片打开后,颜色发生变化了!
file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER));
//file.Write(&bi,sizeof(BITMAPINFOHEADER));
file.Write(lpbi,dwBmpSize + sizeof(BITMAPINFOHEADER) );
HDC hdc, // handle to device context
HBITMAP hbmp, // handle to bitmap
UINT uStartScan, // first scan line to set in destination bitmap
UINT cScanLines, // number of scan lines to copy
LPVOID lpvBits, // address of array for bitmap bits
LPBITMAPINFO lpbi, // address of structure with bitmap data
UINT uUsage // RGB or palette index
);
看楼主对这个函数的用法,那习惯不是一种好的习惯,其结果之一就像现有楼主的疑惑一样就产生了。倒数第二个参数lpbi是一个信息结构体指针,它指明了要获取到的BMP数据格式,而倒数第三个则是保存获取到的DIB数据。楼主把这两个参数用同一变量,虽然在调用该函数之前,对lpbi进行了附值,但在函数返回之后,里面的内容即被破坏掉,因为它被DIB数据覆盖掉了。所以楼主可以跟踪一下,在调用返回之后,你的lpbi里的内容,还是不是你在调用之前附值之后的那些东西,肯定不是!a是这样的!
(UINT)bmpScreen.bmHeight,
lpbi,
(BITMAPINFO *)lpbi, DIB_RGB_COLORS); 这里笔误吧,导致写成红色字那样.应该是:
GetDIBits(hMemDC,hBitmap,0,
(UINT)bmpScreen.bmHeight,
lpbi+sizeof(BITMAPINFOHEADER),
(BITMAPINFO *)lpbi, DIB_RGB_COLORS); 那么就直接可以:
if(file.Open(szBMPFileName,CFile::modeWrite | CFile::modeCreate))
{
file.Write(&bmfHeader,sizeof(BITMAPFILEHEADER));
//file.Write(&bi,sizeof(BITMAPINFOHEADER));
file.Write(lpbi,dwBmpSize+sizeof(BITMAPINFOHEADER));
file.Close();
}