Solved

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

Posted on 2004-08-13
8
1,300 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
ID: 11791838
pWnd->GetWindowRect(&rect);    //NOTE THE &
0
 
LVL 4

Author Comment

by:smpoojary
ID: 11792185
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
ID: 11792282
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
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 44

Expert Comment

by:AndyAinscow
ID: 11793112
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
 
LVL 44

Expert Comment

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

Expert Comment

by:AlexFM
ID: 11795502
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
ID: 11807454
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
ID: 12670237
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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Folder Comparison 12 54
fizzArray2 challenge 1 91
modThree challenge 4 97
MaxSpan challenge 9 105
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
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.

861 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