Saving View as Bitmap

I want to save my current document view as a .BMP file. The view is a Excel like grid created with 3rd party softare (Dundas). Somehow I want to grab the entire view (including the portion that is scrolled off screen and save that to a file in BMP format.

I've been looking at CDC, GDI, etc but am new new Windows and MFC so am a bit mind boggled.

Certainly this can be done with just a few lines of code, no?

Who is Participating?
RONSLOWConnect With a Mentor Commented:

1) you are misunderstanding me.

In the OnSize you simply create a bitmap of the required size.  no bitblt or anything else.  Just make it.

Then in your OnDraw, you draw directly into the bitmap and not onto the screen.  Then blt from the bitmap to the screen.

2) I missed reading your comment about getting the offsecreen parts as well.

In that case, create the bitmap in (say) the oninitialupdate to be the size of your whole document (including offscree bits).  In your OnDraw, draw the whole document into the whole bitmap, then just bit the appropriate part into your view (the part that is visible).
Tommy HuiEngineerCommented:
Go here for a library that saves images to .BMP files.

This what I think I would try... This is off-the-top-of-my-head so there may be bugs in my thought processes ;-)
 a)   I would temporarily resize the view so that it doesn't need scrolling

 b) copy the client area to a bitmap

  c) resize the window to normal and

to resize:

   you can use GetWindowPlacement() to get orginal position

perhaps you can compute the total size
by expoiting the scroll range of the scroll bar and current size of view?
you will probably also need use GetSystemMetrics() for the non-client values you will need when you resize the frame (in order to resize the view) with MoveWindow()

lastly turn off the scroll bar
with ShowScrollBar(FALSE)

Create a bitmap....

CreateCompabileDC.. CreateCompatibleBitmap..
BitBlt (ya know, the usual stuff

finally restore with SetWindowPlacement and redraw....



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.

Use off-screen drawing (ie draw into a bitmap) anyway and the output the bitmap to a file.

To do offscreen drawing, declare a bitmap member in your view.

Create / Recreate the bitmap in your OnSize call (so that it is always the same size as the view).

Make rename your OnDraw .. call it say OnDrawHelper.

Modify the OnDraw for your to create a DC for that bitmap, and call the OnDrawHelper passing it the DC you just created).  Then, use bitblt to copy it to the real dc.

You now have a bitmap with the view contents, which you can write to a file whenever you want.  With 24bit DIBs, the code to write to a file is not too tricky

NOTE: In your OnDraw, don't use the bitmap member and bitblt business if the DC if printing - just directly call OnDrawHelper passing through the original DC.

I (or other experts) can help with each of these steps.

nchenkinAuthor Commented:
Hello all experts,

Thanks for the comments and proposed answer.

I was away from my desk yesterday afternoon and will be gone most of this morning. It looks like RONSLOW's answer will work out but I want to step through it when I have some time later today and then will be back to accept it (hopefully!)

Thanks again,
    to include the portion of the view that is scrolled off the screen wouldn't he need to resize the frame to the length of the "total" view?  or was I steering him wrong ;-) ?
nchenkinAuthor Commented:

Not quite! There are two problems:

1) Goes back to bertp's comment, how do I get the stuff off screen? The cx and cy in OnSize() are only the visible portons of the view.

Here is what I am doing in OnSize()

      if( m_Bitmap.m_hObject != NULL )
         m_Bitmap.DeleteObject();        // get rid of old bitmap

      CClientDC dc(this);
      CDC dcMem;

      m_Bitmap.CreateCompatibleBitmap( &dc, cx, cy );
      CBitmap* pbmOld = dcMem.SelectObject( &m_Bitmap );
      dcMem.BitBlt( 0, 0, cx, cy, &dc, 0, 0, SRCCOPY );
      dcMem.SelectObject( pbmOld );

At this point I can successfully write the file and look at the resulting bitmap in Paint. But it is only the visible portion.

2) The other problem is that what I get is actually just what is onscreen at the time the above code is executed, it really has nothing to do with my view. So, for example, if I put a breakpoint in the above code, the resulting bit map is a lovely image if my development environment.

What am I doing wrong?

nchenkinAuthor Commented:
1) Yes, I misunderstood you. Now I get it (I think). And I see that maybe there is not a "simple" way to do this. I was hoping that Windows had stored an image of the entire view somewhere after it was drawn normally via OnDraw(). Then I could just blt that int a bitmap.

The 3rd party software I'm using makes it tough to just switch DC contexts without changing their source code, or so it seems at first glance.

Oh well...
Does you code still have an OnDraw function (that calls Dundas code)?

If so, then an on-screen bitmap may well work ok. It should be similar to what happens when you do a print-preview.

If not, and it does all the drawing itself, then you are not in luck.

The only thing you can do is bitblt from the view window to a bitmap (ie. a screen capture).  This just gives you what you can see on the view, and is not really a 'nice' solution .. especially if you want
nchenkinAuthor Commented:

Thanks much for your further comment.

> Does you code still have an OnDraw function (that calls Dundas code)?

Well, it does but indirectly. Their documentation recommended using a call to MoveWindow() in the OnSize() handler to update the screen. My app is getting data from remote embedded controllers and I am painting the screen periodically via a timer and the using pDoc->UpdateAllViews().

Dundas has a bunch of OnPaint() functions for each part of the screen grid (headins, margins, cells, etc) that get the resulting WM_PAINT messages. Inside these OnPaint() they always do:

     CPaintDC dc(this);

and pass this to all the functions that do the drawing, which is my problem, methinks.

Hmm... I've been going back and forth between the code as I write this and now I see they have a double buffer mode that is doing something with a m_bitmap. The bitmap is protected in the base class so my derived class should be able to get at it. Wonder if this is the entire grid or just the onscreen part. I'll dig deeper...

Thanks for now. I'll let you know what I find.

nchenkinAuthor Commented:

Nope, out of luck. The Dundas bitmap is just the visible portion of the screen, GetClientRect.

I'm trying to avoid creating another function which duplicates redrawing the entire grid into a bitmap, a function that will need maintenance anytime the screen design changes.

So far no luck.

Don't understand what you mean by "The Dundas bitmap is just the visible portion of the screen, GetClientRect."

What is 'the dundas bitmap' ???

Do you think you could post the OnDraw code for your view here?  And the OnPrepareDc?

These may be in the Dundas code somewhere, or just in your view class.  Either way, that might give me a clue as to what to suggest.
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.