Solved

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

Posted on 2004-08-13
8
1,297 Views
Last Modified: 2013-11-20
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
Comment
Question by:smpoojary
8 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
pWnd->GetWindowRect(&rect);    //NOTE THE &
0
 
LVL 4

Author Comment

by:smpoojary
Comment Utility
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
 
LVL 3

Accepted Solution

by:
jimbucci earned 125 total points
Comment Utility
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
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
The code snippet is also missing a
delete pWnd;
to stop memory leaks.
0
 
LVL 48

Expert Comment

by:AlexFM
Comment Utility
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
 
LVL 4

Author Comment

by:smpoojary
Comment Utility
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
 

Expert Comment

by:tullhead
Comment Utility
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

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

This is to be the first in a series of articles demonstrating the development of a complete windows based application using the MFC classes.  I’ll try to keep each article focused on one (or a couple) of the tasks that one may meet.   Introductio…
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now