Solved

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

Posted on 2004-08-13
8
1,299 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
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

 
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

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Windows Drag & Drop Location 2 100
Adapt this command to show who installed 29 108
Hibernate methods 2 71
Work with App store 7 51
Introduction: Displaying information on the statusbar.   Continuing from the third article about sudoku.   Open the project in visual studio. Status bar – let’s display the timestamp there.  We need to get the timestamp from the document s…
Introduction: The undo support, implementing a stack. Continuing from the eigth article about sudoku.   We need a mechanism to keep track of the digits entered so as to implement an undo mechanism.  This should be a ‘Last In First Out’ collec…
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.
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

786 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