C Win32: save .bmp image from HBITMAP

匿名 (未验证) 提交于 2019-12-03 03:05:02

问题:

I am working with a framegrabber and need to get the images from computer memory and save them on an image file. after trying for couple of days I end up with the following 2 functions, which creates a file and windows OS is able to run the .bmp file, but the bitmap file is black (the image size is 900KB , 640*480). does any body has any idea why, the picture is in black? here are the two functions :

and here is the function for saving into .bmp :

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; }  

I CAN Draw the images from memory perfectly with the following function, so for sure I dont have any problem for reading the image data :

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 <= 0xff; lX++ )         dwMax = ( gadwHistogram[ 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 );  } 

回答1:

I just find out I had a silly mistake in another part of my code I was using :

// 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 !!!!"); } 

by deleting the hBitmap2 = CreateCompatibleBitmap (hDCBits, lXSize, lYSize); line, and changing the hBitmap2 to hBitmap the result of CreateDIBSection(), it saved the image beautifully. THANK YOU EVERYONE FOR YOUR HELP.



回答2:

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; } 

Reference - mikrotron

Reference - write bitmap



回答3:

Are you sure there is proper data in there?

I would try extract the RGB data and save it in some very simple format "manually", just to see what is in there. If you are looking for a dead simple but still standard image format, look at PPM images.



回答4:

From the documentation for CreateCompatibleDC:

When the memory DC is created, its display surface is exactly one monochrome pixel wide and one monochrome pixel high. Before an application can use a memory DC for drawing operations, it must select a bitmap of the correct width and height into the DC.

Since you're using CreateDIBSection with that DC, the resulting DIB section will be 1-bit monochrome as well.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!