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 %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
> 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
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.
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
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.
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
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
SelectPalette(hdcMem, greyPalette, FALSE);
RealizePalette(hdcMem);
--
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.