title: C Win32: save .bmp image from HBITMAP
body: <p>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 :</p>
  
  <pre><code>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 &lt; 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&lt;&lt;8);       
          zWinGHeader.bmiHeader.biClrImportant= 0;
          zWinGHeader.bmiHeader.biHeight      = -lYSize;
          zWinGHeader.bmiHeader.biWidth       = lXSize;
          //zWinGHeader.bmiHeader.biSizeImage = ((zWinGHeader.bmiHeader.biWidth * 8 +31) &amp; ~31) /8
              //                                  * zWinGHeader.bmiHeader.biHeight; 
  
          //  create colortable fot bitmap (grayvalues).
          for (i = 0; i &lt; 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 *)&amp;zWinGHeader,     //  address of structure containing
                                          //  bitmap size, format and color data
          DIB_RGB_COLORS,                 //  color data type indicator: RGB values
                                          //  or palette indices
          &amp;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 
  }
  </code></pre>
  
  <p>and here is the function for saving into .bmp :</p>
  
  <pre><code>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 &lt;= 1)
      wBitCount = 1;
    else if (iBits &lt;= 4)
      wBitCount = 4;
    else if (iBits &lt;= 8)
      wBitCount = 8;
    else
      wBitCount = 24; 
    GetObject(hBitmap3, sizeof(Bitmap0), (LPSTR)&amp;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) &amp; ~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)&amp;bmfHdr, sizeof(BITMAPFILEHEADER), &amp;dwWritten, NULL);
  
    WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &amp;dwWritten, NULL);
    GlobalUnlock(hDib);
    GlobalFree(hDib);
    CloseHandle(fh);
    counter=1;
    return TRUE;
  } 
  </code></pre>
  
  <p>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 :</p>
  
  <pre><code>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 &lt; lYSize; lY++ )
      {
          for ( lX = 0; lX &lt; lXSize; lX++ )
          {
              gadwHistogram[ *pTmpDest ]++;
              pTmpDest++;
          }
      }
  
      GetClientRect ( gahIniDlg[ NdxHistogramDlg ].hWnd, &amp;rect) ;
  
      hdc = GetDC ( gahIniDlg[ NdxHistogramDlg ].hWnd );
  
      dwMax = 0;
      for ( lX = 0 ; lX &lt;= 0xff; lX++ )
          dwMax = ( gadwHistogram[ lX ] &gt; 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 &lt;= 0xff; lX+=8 )
      {
          MoveToEx( hdc, lX * fXFactor, rect.bottom, &amp;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 &lt;= 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 );
  
  }
  </code></pre>