• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1311
  • Last Modified:

Convert drawing from OnDraw(CDC *pDC) to BMP file

Dear Friends,

    I got following code from expert-exchange.com for convert displayed drawing from OnDraw(CDC *pDC) to BMP file

void CCheckView::OnFileSave()
{
      // TODO: Add your command handler code here
     CDC * pdcMemory = new CDC;
     CWnd *pWnd=new CWnd;
     CRect          rect;
     pWnd->GetWindowRect(rect);
     CBitmap * pBitmap = new CBitmap;
     if (pdcMemory->GetSafeHdc() == NULL) {
          CClientDC dc(this);
          OnPrepareDC(&dc);
          pBitmap->CreateCompatibleBitmap(&dc, 300, 300);
          pdcMemory->CreateCompatibleDC(&dc);
          pdcMemory->SelectObject(pBitmap);
          pdcMemory->FillSolidRect(0, 0, 300,300,RGB(255, 255, 255)); // manully paint it white
          OnDraw(pdcMemory);
          WriteWindowToDIB(".\\test.bmp", pWnd);
     }
     delete pdcMemory;
     delete pBitmap;
}

    In the above code, while running pWnd->GetWindowRect(rect); giving run-time error.
 
    Please help me to clear my doubts.
    With warm regards
    -Mahesh
0
smpoojary
Asked:
smpoojary
1 Solution
 
AndyAinscowCommented:
pWnd->GetWindowRect(&rect);    //NOTE THE &
0
 
smpoojaryAuthor Commented:
hi AndyAinScow,

         Now I have modified code like
     pWnd->GetWindowRect(&rect);

        But same Run-Time error is coming

     Please help me to clear my doubts.

     With regards.
     -Mahesh
0
 
jimbucciCommented:
pWnd->GetWindowRect(&rect) fails because pWnd does not point to any valid window.    If you just want the rect of the view just call GetWindowRect(&rect).  It will use the window handle of the view window.

Jim

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
AndyAinscowCommented:
Good point from jimbucci - this also means the following line should fail
WriteWindowToDIB(".\\test.bmp", pWnd);
Do you have the link to the original question you got this code from?
0
 
AndyAinscowCommented:
The code snippet is also missing a
delete pWnd;
to stop memory leaks.
0
 
AlexFMCommented:
CWnd *pWnd=new CWnd;
pWnd->GetWindowRect(rect);

This is wrong. CWnd object exists, but window itself is not created. To create window you need to call CWnd::Create function, only after this you can call GetWindowRect. However, I don't beleive you need new CWnd object here. Try this:

void CCheckView::OnFileSave()
{
     // TODO: Add your command handler code here
     CDC * pdcMemory = new CDC;
     CRect          rect;
     GetWindowRect(rect);
     CBitmap * pBitmap = new CBitmap;
     if (pdcMemory->GetSafeHdc() == NULL) {
          CClientDC dc(this);
          OnPrepareDC(&dc);
          pBitmap->CreateCompatibleBitmap(&dc, 300, 300);
          pdcMemory->CreateCompatibleDC(&dc);
          pdcMemory->SelectObject(pBitmap);
          pdcMemory->FillSolidRect(0, 0, 300,300,RGB(255, 255, 255)); // manully paint it white
          OnDraw(pdcMemory);
          WriteWindowToDIB(".\\test.bmp", this);
     }
     delete pdcMemory;
     delete pBitmap;
}
0
 
smpoojaryAuthor Commented:
hi all,

   Thanks for everybody. Now it is working fine.

   -Mahesh

I have pasted my code below. It may helps to others in future.
void XYchartView::OnFileSave()
{
      // TODO: Add your command handler code here
      UpdateData();

      char strFilter[] = { "BMP Files (*.bmp)|*.bmp||" };

      CFileDialog FileDlg(FALSE, ".bmp", NULL, 0, strFilter);

      if( FileDlg.DoModal() == IDOK )
      {
              char fileName[100];
              strcpy(fileName,FileDlg.GetPathName());

              int i=0;
              while(fileName[i] != '\0')
              {
                    if(fileName[i] == '\\')
                          fileName[i] = '/';
                    ++i;
              }

          WriteWindowToDIB(fileName, this);
      }
      else
            return;


      UpdateData(FALSE);
}


BOOL XYchartView::WriteWindowToDIB( LPTSTR szFile, CWnd *pWnd )
{
      CBitmap       bitmap;
      CWindowDC      dc(pWnd);
      CDC             memDC;
      CRect            rect;

      memDC.CreateCompatibleDC(&dc);

      pWnd->GetWindowRect(rect);

      bitmap.CreateCompatibleBitmap(&dc, rect.Width(),rect.Height() );
      
      CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
      memDC.BitBlt(0, 0, rect.Width(),rect.Height(), &dc, 0, 0, SRCCOPY);

      // Create logical palette if device support a palette
      CPalette pal;
      if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE )
      {
            UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256);
            LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
            pLP->palVersion = 0x300;

            pLP->palNumEntries =
                  GetSystemPaletteEntries( dc, 0, 255, pLP->palPalEntry );

            // Create the palette
            pal.CreatePalette( pLP );

            delete[] pLP;
      }

      memDC.SelectObject(pOldBitmap);

      // Convert the bitmap to a DIB
      
      HANDLE hDIB = DDBToDIB( bitmap, BI_RGB, &pal );

      if( hDIB == NULL )
            return FALSE;

      // Write it to file
      WriteDIB( szFile, hDIB );

      // Free the memory allocated by DDBToDIB for the DIB
      GlobalFree( hDIB );
      return TRUE;
}



// WriteDIB            - Writes a DIB to file
// Returns            - TRUE on success
// szFile            - Name of file to write to
// hDIB                  - Handle of the DIB
BOOL XYchartView::WriteDIB( LPTSTR szFile, HANDLE hDIB)
{
      BITMAPFILEHEADER      hdr;
      LPBITMAPINFOHEADER      lpbi;

      if (!hDIB)
            return FALSE;

      CFile file;
      if( !file.Open( szFile, CFile::modeWrite|CFile::modeCreate) )
            return FALSE;

      lpbi = (LPBITMAPINFOHEADER)hDIB;

      int nColors = 1 << lpbi->biBitCount;

      // Fill in the fields of the file header
      hdr.bfType            = ((WORD) ('M' << 8) | 'B');      // is always "BM"
      hdr.bfSize            = GlobalSize (hDIB) + sizeof( hdr );
      hdr.bfReserved1       = 0;
      hdr.bfReserved2       = 0;
      hdr.bfOffBits            = (DWORD) (sizeof( hdr ) + lpbi->biSize +
                                    nColors * sizeof(RGBQUAD));

      // Write the file header
      file.Write( &hdr, sizeof(hdr) );

      // Write the DIB header and the bits
      file.Write( lpbi, GlobalSize(hDIB) );

      return TRUE;
}

/*/////////////////////////////////////////////////////////////////
Function Name :HANDLE DDBToDIB(CBitmap &bitmap,
                               DWORD dwCompression,
                               CPalette *pPal)
Parameters:
  CBitmap &bitmap : Compatible Device Dependent Bitmap
  DWORD dwCompression : Compression format for Bitmap must not be
  BI_BITFIELDS in this case.
  CPalette *pPal : Pointer to Palette. If this is NULL, the
  default system palette will be used.

/////////////////////////////////////////////////////////////////*/
HANDLE XYchartView::DDBToDIB(CBitmap &bitmap, DWORD dwCompression, CPalette *pPal)
{

  BITMAP              bm;
  BITMAPINFOHEADER    bi;
  LPBITMAPINFOHEADER  lpbi;
  DWORD               dwLen;
  HANDLE              hDIB;
  HANDLE              handle;
  HDC                 hDC;
  HPALETTE            hPal;


  ASSERT( bitmap.GetSafeHandle() );

  // The function has no arg for bitfields
  if( dwCompression == BI_BITFIELDS )
    return NULL;

  // If a palette has not been supplied, use default palette
  hPal = (HPALETTE) pPal->GetSafeHandle();
  if (hPal==NULL)
    hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);

  // Get bitmap information
  bitmap.GetObject(sizeof(bm),(LPSTR)&bm);

  // Initialize the bitmap infoheader
  bi.biSize          = sizeof(BITMAPINFOHEADER);
  bi.biWidth         = bm.bmWidth;
  bi.biHeight        = bm.bmHeight;
  bi.biPlanes        = 1;
  bi.biBitCount      = bm.bmPlanes * bm.bmBitsPixel;
    //bm.bmPlanes    * bm.bmBitsPixel;
  bi.biCompression   = dwCompression;
  bi.biSizeImage     = 0;
  bi.biXPelsPerMeter = 0;
  bi.biYPelsPerMeter = 0;
  bi.biClrUsed       = 0;
  bi.biClrImportant  = 0;

  // Compute the size of the infoheader and the color table
  int nColors = (1 << bi.biBitCount);
  if( nColors > 256 )
    nColors = 0;
  dwLen  = bi.biSize + nColors * sizeof(RGBQUAD);

  // We need a device context to get the DIB from
  hDC = ::GetDC(NULL);
  hPal = SelectPalette(hDC,hPal,FALSE);
  RealizePalette(hDC);

  // Allocate enough memory to hold bitmap infoheader and
  // color table
  hDIB = GlobalAlloc(GMEM_FIXED,dwLen);

  if (!hDIB){
    SelectPalette(hDC,hPal,FALSE);
    ::ReleaseDC(NULL,hDC);
    return NULL;
  }

  lpbi = (LPBITMAPINFOHEADER)hDIB;

  *lpbi = bi;

  // Call GetDIBits with a NULL lpBits param, so the device
  // driver will calculate the biSizeImage field
  GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L,
                 (DWORD)bi.biHeight,
                 (LPBYTE)NULL, (LPBITMAPINFO)lpbi,
                 (DWORD)DIB_RGB_COLORS);

  bi = *lpbi;

  // If the driver did not fill in the biSizeImage field, then
  // compute it
  // Each scan line of the image is aligned on a DWORD (32bit)
  // boundary
  if (bi.biSizeImage == 0){
    bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31)
                        & ~31) / 8) * bi.biHeight;

    // If a compression scheme is used, the result may in fact
    // be larger
    // Increase the size to account for this.
    if (dwCompression != BI_RGB)
      bi.biSizeImage = (bi.biSizeImage * 3) / 2;
  }

  // Realloc the buffer so that it can hold all the bits
  dwLen += bi.biSizeImage;
  if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
    hDIB = handle;
  else{
    GlobalFree(hDIB);

    // Reselect the original palette
    SelectPalette(hDC,hPal,FALSE);
    ::ReleaseDC(NULL,hDC);
    return NULL;
  }

  // Get the bitmap bits
  lpbi = (LPBITMAPINFOHEADER)hDIB;

  // FINALLY get the DIB
  BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(),
        0L,                        // Start scan line
        (DWORD)bi.biHeight,        // # of scan lines
        (LPBYTE)lpbi               // address for bitmap bits
        + (bi.biSize + nColors * sizeof(RGBQUAD)),
        (LPBITMAPINFO)lpbi,        // address of bitmapinfo
        (DWORD)DIB_RGB_COLORS);    // Use RGB for color table

  if( !bGotBits )
  {
    GlobalFree(hDIB);

    SelectPalette(hDC,hPal,FALSE);
    ::ReleaseDC(NULL,hDC);
    return NULL;
  }

  SelectPalette(hDC,hPal,FALSE);
  ::ReleaseDC(NULL,hDC);

  return hDIB;

//End of the function
}

0
 
tullheadCommented:
I tried your code (exactly as posted) and the file is created, and
the bitmap has the proper dimensions, but it is blank (all pixels white).
Do you have an idea what I did wrong?

Tullhead
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now