Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Zooming a Window Using StretchBlt

355 views
Skip to first unread message

Peter David Lauren

unread,
Aug 25, 1998, 3:00:00 AM8/25/98
to
I am using MSVC++ 5.0 on Windows 95.

I am trying to develop a program which zooms the image in the window
in and out when I click on the appropriate dialog box
button. I have been trying to do this using StretchBlt in the
following way.

StretchBlt(hdcDest, 0, 0, gnZoom * gcxZoomed, gnZoom * gcyZoomed,
hdcSource, 0, 0, gcxZoomed, gcyZoomed, SRCCOPY);

When I make hdcSource the same as hdcDest (effectively copying a
window to itself in a zoomed form) it works but I keep seeing the unzoomed
image flicker in the window every time the window is repainted. If I
make them different, it would seem that I would need two windows: one
to hold the original image and the other to display the zoomed image. However,
when I do this, I see the scratch image on the screen and zooming will also
display whatever is in front of the scratch image when I zoom to the
display image. I have tried putting the scratch image off the visible
screen area but then it never seems to get painted with the image.

Am I going about things the right way? Apparanetly not, since I
don't get the desired results. What would be the best way to zoom a
bitmap image in a window?

Many thanks for any help,

--
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Peter D. Lauren, %%
%% pd...@virginia.edu %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Roger

unread,
Aug 25, 1998, 3:00:00 AM8/25/98
to

Peter David Lauren <pd...@pasteur.micr.Virginia.EDU> wrote in message
6rvbui$a9a$1...@murdoch.acc.Virginia.EDU...

>I am using MSVC++ 5.0 on Windows 95.
>
>I am trying to develop a program which zooms the image in the window
>in and out when I click on the appropriate dialog box
>button. I have been trying to do this using StretchBlt in the
>following way.
>
>StretchBlt(hdcDest, 0, 0, gnZoom * gcxZoomed, gnZoom * gcyZoomed,
> hdcSource, 0, 0, gcxZoomed, gcyZoomed, SRCCOPY);
>
>When I make hdcSource the same as hdcDest (effectively copying a
>window to itself in a zoomed form) it works but I keep seeing the unzoomed
>image flicker in the window every time the window is repainted.
I assume you are painting the DC with the unzoomed image first? (probably in
your WM_PAINT handler). You don't really want to do that. And you won't want
to erase the background either, or you will get an annoying white flash.

> If I make them different, it would seem that I would need two windows:
one
>to hold the original image and the other to display the zoomed image.

Close to right. What you want is 2 device contexts, not 2 windows. One you
already have, it maps to your destination window. The other needs to be a
memory DC. Look at the function CreateCompatibleDC. You need to select your
bitmap into this compatible DC, and make it the hdcSource.

Roger


Peter David Lauren

unread,
Aug 26, 1998, 3:00:00 AM8/26/98
to
In article <#NT3e7H0...@ntdwwaaw.compuserve.com>,

Greetings Roger,

Thank you for responding to my query.

I am trying to do as you suggest but am having trouble with the
``compatible'' device context. Specifically,
the following code leaves the window totally black.

//Create memory device context compatible with display device
hdcMem=CreateCompatibleDC(DeviceContext);

//Select Bitmap into memory device context
SelectObject(hdcMem, hBitmap);

ErrorNumber=SetMapMode(hdcMem, GetMapMode(DeviceContext));

scanLinesSet = SetDIBitsToDevice(hdcMem, 0, 0, ptSize.x, ptSize.y, ptOrg.x,
ptOrg.y, 0, ptSize.y, (void *)ppvBits, pbmi, DIB_RGB_COLORS);

BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);

The same occurs with StretchBlt. However, if the last two calls are
replaced by

scanLinesSet = SetDIBitsToDevice(DeviceContext, 0, 0, ptSize.x, ptSize.y,
ptOrg.x, ptOrg.y, 0, ptSize.y, (void *)ppvBits, pbmi, DIB_RGB_COLORS);

I get the image in the window.

DeviceContext is created by BeginPaint(), while hBitmap is returned by
CreateDIBSection().

I would be most grateful if you could tell me what I am still doing wrong.

Roger

unread,
Aug 26, 1998, 3:00:00 AM8/26/98
to

>Thank you for responding to my query.
>
>I am trying to do as you suggest but am having trouble with the
>``compatible'' device context. Specifically,
>the following code leaves the window totally black.
>
>//Create memory device context compatible with display device
>hdcMem=CreateCompatibleDC(DeviceContext);
>
>//Select Bitmap into memory device context
>SelectObject(hdcMem, hBitmap);
>
>ErrorNumber=SetMapMode(hdcMem, GetMapMode(DeviceContext));
>
>scanLinesSet = SetDIBitsToDevice(hdcMem, 0, 0, ptSize.x, ptSize.y, ptOrg.x,
>ptOrg.y, 0, ptSize.y, (void *)ppvBits, pbmi, DIB_RGB_COLORS);
>
>BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
>
>The same occurs with StretchBlt. However, if the last two calls are
>replaced by
>
>scanLinesSet = SetDIBitsToDevice(DeviceContext, 0, 0, ptSize.x, ptSize.y,
>ptOrg.x, ptOrg.y, 0, ptSize.y, (void *)ppvBits, pbmi, DIB_RGB_COLORS);
>
>I get the image in the window.
>
>DeviceContext is created by BeginPaint(), while hBitmap is returned by
>CreateDIBSection().
>
>I would be most grateful if you could tell me what I am still doing wrong.

I believe the problem is with the SetDIBitsToDevice call. This cannot (or at
least could not in the past) be used with a memory device context.


A search of the MSDN turned up this article that might help. It was written
for 3.1, but I believe it still applies to 9x and NT
~~~~~~~~~~~
(Ref. Q66595 )
The SetDIBitsToDevice() function will set the device-independent bitmap
(DIB) only to a physical device context, not to a memory device context. To
set the DIB to a memory device context, use SetDIBits(), or call
StretchDIBits() and specify the same height and width for both the source
and the destination.

It is important to keep in mind that, on a palette device, the palette must
be set appropriately before transferring the image. The SetDIBitsToDevice()
and StretchDIBits() functions do not set the palette automatically. To do
this, perform the following steps:

Get the palette from the DIB.
Create a logical palette with the palette colors from the DIB.
Select the palette into the device context.
Realize the palette.

Call SetDIBitsToDevice() or StretchDIBits() to transfer the image to the
device context.
~~~~~~~~~~
And you thought this was gonna be easy ;)

Roger


Peter David Lauren

unread,
Aug 27, 1998, 3:00:00 AM8/27/98
to
In article <#1UVXLV0...@nih2naaa.prod2.compuserve.com>,


Thanks again for your help. I don't know why but even this, apparently
simple, operation doesn't work.

//Create memory device context compatible with display device
hdcMem=CreateCompatibleDC(DeviceContext);

//Select Bitmap into memory device context
SelectObject(hdcMem, hBitmap);

SelectPalette(hdcMem, greyPalette, FALSE);
RealizePalette(hdcMem);

SetDIBits(DeviceContext, hBitmap, 0, ptSize.y, (void *)ppvBits,
pbmi, DIB_PAL_COLORS);

BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, DeviceContext, 0, 0, SRCCOPY);


BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);

greyPalette is a handle to a logical palette which is used successfully with
DeviceContext. If I leave the BitBlt's out, I get the image in the
window. With the BitBlt's, the window goes black.

Roger Lathrop

unread,
Aug 27, 1998, 3:00:00 AM8/27/98
to

Peter David Lauren wrote in message
<6s3vo7$40e$1...@murdoch.acc.Virginia.EDU>...
<SNIP>

>//Create memory device context compatible with display device
>hdcMem=CreateCompatibleDC(DeviceContext);
>
>//Select Bitmap into memory device context
>SelectObject(hdcMem, hBitmap);
>
>SelectPalette(hdcMem, greyPalette, FALSE);
>RealizePalette(hdcMem);
>
>SetDIBits(DeviceContext, hBitmap, 0, ptSize.y, (void *)ppvBits,
>pbmi, DIB_PAL_COLORS);
>
>BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, DeviceContext, 0, 0, SRCCOPY);
>BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
>
>greyPalette is a handle to a logical palette which is used successfully
with
>DeviceContext. If I leave the BitBlt's out, I get the image in the
>window. With the BitBlt's, the window goes black.


The remarks section of the SetDIBits function contains this caveat:
"The bitmap identified by the hbmp parameter must not be selected into a
device context when the application calls this function."

In the code above, hBitmap is selected into hdcMem already. I think you've
got all the pieces, just need to re-arrange the order a bit.

Roger


Roger

unread,
Aug 28, 1998, 3:00:00 AM8/28/98
to

Peter David Lauren <pd...@pasteur.micr.Virginia.EDU> wrote in message
6s7i5h$jrh$1...@murdoch.acc.Virginia.EDU...
>In article <6s4418$n...@partech.partech.com>,
>Thanks again for your help. Now I have tried the following

>
>//Create memory device context compatible with display device
>hdcMem=CreateCompatibleDC(DeviceContext);
>
>//Select Bitmap into memory device context
>SelectObject(hdcMem, hBitmap);
>
>SelectPalette(hdcMem, greyPalette, FALSE);
>RealizePalette(hdcMem);
>
> SetDIBits(hdcMem, ::CreateCompatibleBitmap (DeviceContext, ptSize.x,
> ptSize.y), 0, ptSize.y, (void *)ppvBits, pbmi, DIB_PAL_COLORS);

>
>BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
>
>Unfortunately, the result is the same. The window goes black. When I
>replace hdcMem with DeviceContext in the last two calls, I get the
>(unzoomed) image in the window as expected. PtSize contains the image
>dimensions.
>

Peter,
I think you're confusing devices with device contexts. Easy mistake to make.
A device context is a thing (handle, but it's really a structure internally)
that contains all the 'stuff' needed to be able to draw on a device (mapping
mode, background color, etc). A device is a thing to be drawn on (the
screen, a printer, a memory bitmap). It is just one of the many attributes
that are stored in a device context. For the screen, you don't have to
manually select the device into the device context, windows does that for
you when you call functions like GetDC. For a memory bitmap, you must
manually select the bitmap into the device context, as you did with
SelectObject.
The SetDIBits function is a bit of an odd beast. The docs aren't too clear
about what the first param is...just says 'handle to a device context'. But
then it goes on to say that the bitmap must not be selected into a device
context. Weird stuff. But you have to look at which way data flows in this
call...from lpvbits(param 5) to hbmp(param 2). hbmp is the thing (device)
that the image is drawn on. hdc(param 1) only plays a bit part in color
translation. The docs say "The device context identified by the hdc
parameter is used only if the DIB_PAL_COLORS ".

What you did was create a bitmap (param 2), copy the bits to it, but...you
didn't keep the bitmap handle!
What you really want to do is copy the data to hBitmap, but BEFORE you
select it into any other device context.
Something along the lines of:

//Create memory device context compatible with display device
hdcMem=CreateCompatibleDC(DeviceContext);

SelectPalette(hdcMem, greyPalette, FALSE);
RealizePalette(hdcMem);

SetDIBits(DeviceContext, hBitmap, 0, ptSize.y, (void *)ppvBits, pbmi,
DIB_PAL_COLORS);

//Select Bitmap into memory device context
SelectObject(hdcMem, hBitmap);

BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);

Roger


Peter David Lauren

unread,
Aug 29, 1998, 3:00:00 AM8/29/98
to

SelectPalette(hdcMem, greyPalette, FALSE);
RealizePalette(hdcMem);

--

Peter David Lauren

unread,
Aug 31, 1998, 3:00:00 AM8/31/98
to
In article <eyvl1Yv...@ntdwwaaw.compuserve.com>,
Roger <ratc...@sprynet.com> wrote:
>
(snip)

>>
>>
>>Thanks again for your help. Now I have tried the following
>>
>>//Create memory device context compatible with display device
>>hdcMem=CreateCompatibleDC(DeviceContext);
>>
>>//Select Bitmap into memory device context
>>SelectObject(hdcMem, hBitmap);
>>
>>SelectPalette(hdcMem, greyPalette, FALSE);
>>RealizePalette(hdcMem);
>>
>> SetDIBits(hdcMem, ::CreateCompatibleBitmap (DeviceContext, ptSize.x,
>> ptSize.y), 0, ptSize.y, (void *)ppvBits, pbmi, DIB_PAL_COLORS);
>>
>>BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
>>
>>Unfortunately, the result is the same. The window goes black. When I
>>replace hdcMem with DeviceContext in the last two calls, I get the
>>(unzoomed) image in the window as expected. PtSize contains the image
>>dimensions.
>>
>
>Peter,
>I think you're confusing devices with device contexts. Easy mistake to make.
>A device context is a thing (handle, but it's really a structure internally)
>that contains all the 'stuff' needed to be able to draw on a device (mapping
>mode, background color, etc). A device is a thing to be drawn on (the
>screen, a printer, a memory bitmap). It is just one of the many attributes
>that are stored in a device context. For the screen, you don't have to
>manually select the device into the device context, windows does that for
>you when you call functions like GetDC. For a memory bitmap, you must
>manually select the bitmap into the device context, as you did with
>SelectObject.
>The SetDIBits function is a bit of an odd beast. The docs aren't too clear
>about what the first param is...just says 'handle to a device context'. But
>then it goes on to say that the bitmap must not be selected into a device
>context. Weird stuff. But you have to look at which way data flows in this
>call...from lpvbits(param 5) to hbmp(param 2). hbmp is the thing (device)
>that the image is drawn on. hdc(param 1) only plays a bit part in color
>translation. The docs say "The device context identified by the hdc
>parameter is used only if the DIB_PAL_COLORS ".
>
>What you did was create a bitmap (param 2), copy the bits to it, but...you
>didn't keep the bitmap handle!
>What you really want to do is copy the data to hBitmap, but BEFORE you
>select it into any other device context.
>Something along the lines of:
>
>//Create memory device context compatible with display device
>hdcMem=CreateCompatibleDC(DeviceContext);
>
>SelectPalette(hdcMem, greyPalette, FALSE);
>RealizePalette(hdcMem);
>
>SetDIBits(DeviceContext, hBitmap, 0, ptSize.y, (void *)ppvBits, pbmi,
>DIB_PAL_COLORS);
>
>//Select Bitmap into memory device context
>SelectObject(hdcMem, hBitmap);
>BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
>
>Roger
>
>
>


Thanks again for your help.

This still gives a black window. However, when I use the following code,


//Create memory device context compatible with display device
hdcMem=CreateCompatibleDC(DeviceContext);

SelectPalette(hdcMem, greyPalette, FALSE);
RealizePalette(hdcMem);

CompatBitmap=::CreateCompatibleBitmap (DeviceContext, ptSize.x, ptSize.y);
SetDIBits(hdcMem, hCompatBitmap, 0, ptSize.y, (void *)ppvBits, pbmi,
DIB_PAL_COLORS);

//Select Bitmap into memory device context
SelectObject(hdcMem, hCompatBitmap);


BitBlt(DeviceContext, 0, 0, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);

I can actually see the image data in the window but there is a problem
with the color mapping. When the screen is set to a bit depth of >= 16,
the image is mainly black except in very dark parts of the image where
it is multicolored. There is enough color for me to see that
the image data is being written to the window although the color mapping
is wrong. When the screen has a bit depth of >=16, greyPalette==NULL
and the color mapping for DeviceContext is derived from the values in
pbmi->bmiColors.

When the screen bitdepth is set to eight, the above code again shows
the image which is roughly a gray-scale image but a lot of values which
should be mid-gray are black. The appearance changes as I adjust the
values in pbmi->bmiColors but the image still looks like someone poured
acid over it with all of the gray levels which are erroneously set to
black.

If I replace the above code with

scanLinesSet = SetDIBitsToDevice(DeviceContext, 0, 0, ptSize.x, ptSize.y,

ptOrg.x, ptOrg.y, 0, ptSize.y, (void *)ppvBits, pbmi, DIB_RGB_COLORS);

everything looks fine at any screen setting but, of course, that doesn't
get me anywhere with zooming.

0 new messages