Solved

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

Posted on 2004-08-13
8
1,304 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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
Technology Partners: 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!

 
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

Secure Your Active Directory - April 20, 2017

Active Directory plays a critical role in your company’s IT infrastructure and keeping it secure in today’s hacker-infested world is a must.
Microsoft published 300+ pages of guidance, but who has the time, money, and resources to implement? Register now to find an easier way.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
set up trigger (or something) to rename files (starting with ATL) in a linux directory 6 56
sumNumber challenge 16 140
modThree challenge 4 112
pre4 challenge 19 111
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
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.

726 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