C Win32:从HBITMAP保存.bmp图像

我正在使用framegrabber,需要从计算机内存中获取图像并将其保存在图像文件中。 在尝试了几天后,我最终得到了以下2个函数,它们创建了一个文件,Windows操作系统能够运行.bmp文件,但位图文件是黑色的(图像大小为900KB,640 * 480)。 有没有人知道为什么,图片是黑色的? 这里有两个function:

LPSTR CreateBMP( HWND hAppWnd, int nImageType ) { void * pWinGBits = NULL; int i; Z_BITMAPINFO zWinGHeader; // bitmapinfo for cerating the DIB // create DC for bitmap. hDCBits = CreateCompatibleDC( ghDCMain ); switch ( nImageType ) { case bayer_filter: zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); zWinGHeader.bmiHeader.biPlanes = 1; zWinGHeader.bmiHeader.biClrImportant = 0; zWinGHeader.bmiHeader.biHeight = -lYSize; zWinGHeader.bmiHeader.biWidth = lXSize; zWinGHeader.bmiHeader.biBitCount = 32; zWinGHeader.bmiHeader.biClrUsed = 0;//3; zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS; zWinGHeader.bmiHeader.biSizeImage = 0; zWinGHeader.bmiColors[0].rgbBlue = 0x00; zWinGHeader.bmiColors[0].rgbGreen = 0x00; zWinGHeader.bmiColors[0].rgbRed = 0xFF; zWinGHeader.bmiColors[0].rgbReserved = 0x00; zWinGHeader.bmiColors[1].rgbBlue = 0x00; zWinGHeader.bmiColors[1].rgbGreen = 0xFF; zWinGHeader.bmiColors[1].rgbRed = 0x00; zWinGHeader.bmiColors[1].rgbReserved = 0x00; zWinGHeader.bmiColors[2].rgbBlue = 0xFF; zWinGHeader.bmiColors[2].rgbGreen = 0x00; zWinGHeader.bmiColors[2].rgbRed = 0x00; zWinGHeader.bmiColors[2].rgbReserved = 0x00; break; case color32: zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); zWinGHeader.bmiHeader.biPlanes = 1; zWinGHeader.bmiHeader.biClrImportant = 0; zWinGHeader.bmiHeader.biHeight = -lYSize; zWinGHeader.bmiHeader.biWidth = lXSize/4; zWinGHeader.bmiHeader.biBitCount = 32; zWinGHeader.bmiHeader.biClrUsed = 0; zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS; zWinGHeader.bmiHeader.biSizeImage = 0; zWinGHeader.bmiColors[0].rgbBlue = 0x00; zWinGHeader.bmiColors[0].rgbGreen = 0x00; zWinGHeader.bmiColors[0].rgbRed = 0xFF; zWinGHeader.bmiColors[0].rgbReserved = 0x00; zWinGHeader.bmiColors[1].rgbBlue = 0x00; zWinGHeader.bmiColors[1].rgbGreen = 0xFF; zWinGHeader.bmiColors[1].rgbRed = 0x00; zWinGHeader.bmiColors[1].rgbReserved = 0x00; zWinGHeader.bmiColors[2].rgbBlue = 0xFF; zWinGHeader.bmiColors[2].rgbGreen = 0x00; zWinGHeader.bmiColors[2].rgbRed = 0x00; zWinGHeader.bmiColors[2].rgbReserved = 0x00; break; case color24: zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); zWinGHeader.bmiHeader.biPlanes = 1; zWinGHeader.bmiHeader.biClrImportant = 0; zWinGHeader.bmiHeader.biHeight = -lYSize; zWinGHeader.bmiHeader.biWidth = lXSize/3; zWinGHeader.bmiHeader.biBitCount = 24; zWinGHeader.bmiHeader.biClrUsed = 0; zWinGHeader.bmiHeader.biCompression = BI_RGB; zWinGHeader.bmiHeader.biSizeImage = 0; break; case color3x16: zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); zWinGHeader.bmiHeader.biPlanes = 1; zWinGHeader.bmiHeader.biClrImportant = 0; zWinGHeader.bmiHeader.biHeight = -lYSize; zWinGHeader.bmiHeader.biWidth = lXSize/6; zWinGHeader.bmiHeader.biBitCount = 32; zWinGHeader.bmiHeader.biClrUsed = 0; zWinGHeader.bmiHeader.biCompression = BI_BITFIELDS; zWinGHeader.bmiHeader.biSizeImage = 0; zWinGHeader.bmiColors[0].rgbBlue = 0x00; zWinGHeader.bmiColors[0].rgbGreen = 0x00; zWinGHeader.bmiColors[0].rgbRed = 0xFF; zWinGHeader.bmiColors[0].rgbReserved = 0x00; zWinGHeader.bmiColors[1].rgbBlue = 0x00; zWinGHeader.bmiColors[1].rgbGreen = 0xFF; zWinGHeader.bmiColors[1].rgbRed = 0x00; zWinGHeader.bmiColors[1].rgbReserved = 0x00; zWinGHeader.bmiColors[2].rgbBlue = 0xFF; zWinGHeader.bmiColors[2].rgbGreen = 0x00; zWinGHeader.bmiColors[2].rgbRed = 0x00; zWinGHeader.bmiColors[2].rgbReserved = 0x00; break; case bw1x10: // create bitmap-infoheader. zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); zWinGHeader.bmiHeader.biPlanes = 1; zWinGHeader.bmiHeader.biBitCount = 8; zWinGHeader.bmiHeader.biCompression = BI_RGB; zWinGHeader.bmiHeader.biSizeImage = 0; zWinGHeader.bmiHeader.biClrUsed = 256; zWinGHeader.bmiHeader.biClrImportant= 0; zWinGHeader.bmiHeader.biHeight = -lYSize; zWinGHeader.bmiHeader.biWidth = lXSize/2; // create colortable fot bitmap (grayvalues). for (i = 0; i < 256; i++) { zWinGHeader.bmiColors[i].rgbGreen = i; zWinGHeader.bmiColors[i].rgbBlue = i; zWinGHeader.bmiColors[i].rgbRed = i; zWinGHeader.bmiColors[i].rgbReserved = 0; } break; default: case bw8: // create bitmap-infoheader. zWinGHeader.bmiHeader.biSize = sizeof( BITMAPINFOHEADER ); zWinGHeader.bmiHeader.biPlanes = 1; zWinGHeader.bmiHeader.biBitCount = 8; zWinGHeader.bmiHeader.biCompression = BI_RGB; zWinGHeader.bmiHeader.biSizeImage = 0; zWinGHeader.bmiHeader.biClrUsed = (1<<8); zWinGHeader.bmiHeader.biClrImportant= 0; zWinGHeader.bmiHeader.biHeight = -lYSize; zWinGHeader.bmiHeader.biWidth = lXSize; //zWinGHeader.bmiHeader.biSizeImage = ((zWinGHeader.bmiHeader.biWidth * 8 +31) & ~31) /8 // * zWinGHeader.bmiHeader.biHeight; // create colortable fot bitmap (grayvalues). for (i = 0; i < 256; i++) { zWinGHeader.bmiColors[i].rgbGreen = i; zWinGHeader.bmiColors[i].rgbBlue = i; zWinGHeader.bmiColors[i].rgbRed = i; zWinGHeader.bmiColors[i].rgbReserved = 0; } break; } // cerate identity palette hPal = CreateIdentityPalette( zWinGHeader.bmiColors ); // get new palette into DC and map into physical palette register. hOldPal = SelectPalette( ghDCMain, hPal, FALSE); RealizePalette( ghDCMain ); // cerate DIB-Section f黵 direct access of image-data. hBitmap = CreateDIBSection( hDCBits, // handle of device context (BITMAPINFO *)&zWinGHeader, // address of structure containing // bitmap size, format and color data DIB_RGB_COLORS, // color data type indicator: RGB values // or palette indices &pWinGBits, // pointer to variable to receive a pointer // to the bitmap's bit values NULL, // optional handle to a file mapping object 0 // offset to the bitmap bit values within // the file mapping object ); // get bitmap into DC . hOldBitmap = (HBITMAP)SelectObject( hDCBits, hBitmap ); return pWinGBits; // return pointer to DIB } 

这是保存到.bmp的function:

 BOOL SaveToFile(HBITMAP hBitmap3, LPCTSTR lpszFileName) { HDC hDC; int iBits; WORD wBitCount; DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0; BITMAP Bitmap0; BITMAPFILEHEADER bmfHdr; BITMAPINFOHEADER bi; LPBITMAPINFOHEADER lpbi; HANDLE fh, hDib, hPal,hOldPal2=NULL; hDC = CreateDC("DISPLAY", NULL, NULL, NULL); iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); DeleteDC(hDC); if (iBits <= 1) wBitCount = 1; else if (iBits <= 4) wBitCount = 4; else if (iBits <= 8) wBitCount = 8; else wBitCount = 24; GetObject(hBitmap3, sizeof(Bitmap0), (LPSTR)&Bitmap0); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = Bitmap0.bmWidth; bi.biHeight =-Bitmap0.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBitCount; bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrImportant = 0; bi.biClrUsed = 256; dwBmBitsSize = ((Bitmap0.bmWidth * wBitCount +31) & ~31) /8 * Bitmap0.bmHeight; hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); *lpbi = bi; hPal = GetStockObject(DEFAULT_PALETTE); if (hPal) { hDC = GetDC(NULL); hOldPal2 = SelectPalette(hDC, (HPALETTE)hPal, FALSE); RealizePalette(hDC); } GetDIBits(hDC, hBitmap3, 0, (UINT) Bitmap0.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) +dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS); if (hOldPal2) { SelectPalette(hDC, (HPALETTE)hOldPal2, TRUE); RealizePalette(hDC); ReleaseDC(NULL, hDC); } fh = CreateFile(lpszFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (fh == INVALID_HANDLE_VALUE) return FALSE; bmfHdr.bfType = 0x4D42; // "BM" dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; bmfHdr.bfSize = dwDIBSize; bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL); GlobalUnlock(hDib); GlobalFree(hDib); CloseHandle(fh); counter=1; return TRUE; } 

我可以通过以下function完美地从内存中绘制图像,所以我确定读取图像数据没有任何问题:

 void DrawPicture( HDC hDC, PBYTE pDest, PBYTE pSrc, LONG lXSize, LONG lYSize ) { LONG lXSizeDiv, lYSizeDiv; LONG lX, lY; DWORD dwMax; RECT rect; HDC hdc; PBYTE pTmpDest; double fXFactor, fYFactor; // HBRUSH hBrush; // POINT Point; switch( gzMvfgKamDef.iImageType ) { case bayer_filter: lXSizeDiv = 1; lYSizeDiv = 1; BayerToRGB( (PDWORD) pDest, pSrc, lXSize, lYSize, gzMvfgKamDef.iBayerQuadrant, gzMvfgKamDef.iBayerQuality ); break; case color24: lXSizeDiv = 3; lYSizeDiv = 1; memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) ); break; case color32: lXSizeDiv = 4; lYSizeDiv = 1; memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) ); break; case color3x16: lXSizeDiv = 6; lYSizeDiv = 1; Conv3x16To3x8( pDest, pSrc, 4, lXSize, lYSize ); break; case bw1x10: lXSizeDiv = 2; lYSizeDiv = 1; Conv1x10To1x8( pDest, pSrc, 2, lXSize, lYSize ); break; case bw6Tap: lXSizeDiv = 1; lYSizeDiv = 1; Conv6TapTo1x8( pDest, pSrc, 1, lXSize, lYSize ); break; default: case bw8: lXSizeDiv = 1; lYSizeDiv = 1; memcpy( pDest, pSrc, (size_t)( lXSize * lYSize ) ); break; } if( gahIniDlg[ NdxHistogramDlg ].hWnd ) { memset( gadwHistogram, 0, sizeof( gadwHistogram) ); pTmpDest = pDest; for ( lY = 0; lY < lYSize; lY++ ) { for ( lX = 0; lX < lXSize; lX++ ) { gadwHistogram[ *pTmpDest ]++; pTmpDest++; } } GetClientRect ( gahIniDlg[ NdxHistogramDlg ].hWnd, &rect) ; hdc = GetDC ( gahIniDlg[ NdxHistogramDlg ].hWnd ); dwMax = 0; for ( lX = 0 ; lX  dwMax ) ? gadwHistogram[ lX ] : dwMax; fYFactor = (double) dwMax / (double) rect.bottom; fXFactor = (double) ( rect.right - 100 ) / (double) 0x100; /* SelectObject (hdc, GetStockObject (BLACK_PEN)) ; for( lX = 0; lX <= 0xff; lX+=8 ) { MoveToEx( hdc, lX * fXFactor, rect.bottom, &Point ); LineTo( hdc, lX * fXFactor, rect.bottom-10 ); } */ SelectObject (hdc, GetStockObject (WHITE_PEN)) ; // hBrush = CreateSolidBrush( GetSysColor( COLOR_WINDOW )); // hBrush = CreateSolidBrush( 0xffffff ); // SelectObject (hdc, hBrush); Polyline( hdc, gaHistogram, 0x100 ); // DeleteObject( hBrush ); for ( lX = 0 ; lX <= 0xff; lX++ ) { gaHistogram[ lX ].x = (DWORD)( fXFactor * (double)lX ); gaHistogram[ lX ].y = rect.bottom - (DWORD)( (double) gadwHistogram[ lX ] / fYFactor ); } SelectObject (hdc, GetStockObject (BLACK_PEN)) ; Polyline( hdc, gaHistogram, 0x100 ); ReleaseDC ( gahIniDlg[ NdxHistogramDlg ].hWnd , hdc ) ; } // display the bitmap StretchBlt( hDC, rcWin.left, rcWin.top, lXSize / lXSizeDiv, lYSize / lYSizeDiv, hDCBits, 0, 0, lXSize / lXSizeDiv, lYSize / lYSizeDiv, SRCCOPY ); //BitBlt( hDC, rcWin.left, rcWin.top, lXSize / lXSizeDiv, lYSize / lYSizeDiv, //hDCBits, 0, 0, SRCCOPY ); } 

我发现在我使用的代码的另一部分中有一个愚蠢的错误:

 // Convert Image to bitmap and display it DrawPicture( ghDCMain, pWinGBitmap, gpbImageData, lXSize, lYSize ); if(counter!=1) { hBitmap2 = CreateCompatibleBitmap (hDCBits, lXSize, lYSize); SaveToFile(hBitmap2, "c:\\t.bmp"); OutputDebugString("tested !!!!"); } 

删除hBitmap2 = CreateCompatibleBitmap (hDCBits, lXSize, lYSize); 线,并将hBitmap2更改为hBitmap CreateDIBSection()的结果,它保存了漂亮的图像。 感谢大家的帮助。

 FORMAT_INFO sFormat; mvfg_getparam( MVFGPAR_DATAFORMAT, &sFormat, giCurrentGrabberID); long lFrameSize = sFormat.lFrameSize; BYTE *pBitmap = (BYTE*)malloc(FrameSize); memcpy( pBitmap, CamGetPicture(), FrameSize ); writeBitmapToFile(pBitmap, FrameSize, "tmp.bmp"); /* * write our raw data into a bitmap file * adding the correct header and put it all * together in a single file */ int writeBitmapToFile(void *data, unsigned long size, const char *filename) { bmpFileHeader_t header; bmpInfoHeader_t info; bmpRGBQuad_t rgb = { 0, 0, 0, 0}; FILE *out; size_t len; int i; header.type = 0x4d42; // magic sequence 'BM' header.size = 0; header.res0 = 0; header.res1 = 0; /* 256 different colors, each is defined by an bmpRBQuad type */ header.offset = 256 * sizeof(bmpRGBQuad_t) + sizeof(bmpInfoHeader_t) + sizeof(bmpFileHeader_t); info.size = sizeof(bmpInfoHeader_t); info.width = WIDTH; info.height = HEIGHT; info.planes = 1; info.cDepth = 8; /* 8 Bit */ info.compression = 0; info.rawSize = size; info.hRes = 0; info.vRes = 0; info.nrColors = 0x100; info.impColors = 0; out = fopen(filename, "wb"); if (out == NULL) { printf("error cannot open %s for writing\n", filename); return -1; } len = fwrite(&header, 1, sizeof(header), out); if (len != sizeof(header)) { printf("error while writing header\n"); return -1; } len = fwrite(&info, 1, sizeof(info), out); if (len != sizeof(info)) { printf("error while writing info header\n"); return -1; } /* stupid try and error programming leads to this */ for (i = 0; i < 256; i++) { rgb.red = i; rgb.green = i; rgb.blue = i; len = fwrite(&rgb, 1, sizeof(rgb), out); if (len != sizeof(rgb)) { printf("error while writing rgb header\n"); return -1; } } len = fwrite(data, 1, size, out); if (len != size ) { printf("error while writing bitmap data\n"); return -1; } return 0; } 

参考 - mikrotron

参考 - 写位图

你确定那里有适当的数据吗?

我会尝试提取RGB数据并以“手动”的一些非常简单的格式保存,只是为了看看那里有什么。 如果您正在寻找一种简单但仍然标准的图像格式,请查看PPM图像 。

从CreateCompatibleDC的文档:

当创建存储器DC时,其显示表面恰好是一个单色像素宽和一个单色像素高。 在应用程序可以使用内存DC进行绘制操作之前,它必须在DC中选择正确宽度和高度的位图。

由于您正在使用具有该DC的CreateDIBSection ,因此生成的DIB部分也将是1位单色。