Hi Folks,
I'm not sure where this post belongs since I'm using managed vc.net, but the
issue is around GDI BitBlt.
Here is a summary of the problem:
- I am trying to copy a bitmap of my main form into a picture box.
- To do this, I bitblt using the device contexts of the form and a bitmap
object.
- After blitting, the bitmap image is always blank. I don't understand what
I'm doing wrong here.
Here is my relevant code:
MainMenuForm_Shown(...)
{
Graphics ^formGraphics = this->CreateGraphics();
Bitmap ^bitmap = gcnew Bitmap(this->Width, this->Height, formGraphics);
Graphics ^bitmapGraphics = Graphics::FromImage(bitmap);
IntPtr formDC = formGraphics->GetHdc();
IntPtr bitmapDC = bitmapGraphics->GetHdc();
BitBlt(bitmapDC, 0, 0, this->Width, this->Height, formDC, 0, 0, 0xCC0020);
formGraphics->ReleaseHdc(formDC);
bitmapGraphics->ReleaseHdc(bitmapDC);
bitmap->Save(CCarthageDefs::DIR_IMAGES + "test.jpg");
}
After running the above code, the file test.jpg is tiny and basically blank
(maybe all solid grayish white). I expected it to be a copy of the form.
Any comments on why this is happening would be most appreciated.
I thought maybe the problem was with the form, so I tried an even simpler
test: copying one image to another. Here is the code:
Bitmap ^srcImage = gcnew Bitmap("input.jpg");
Graphics ^srcG = Graphics::FromImage(srcImage);
Bitmap ^toImage = gcnew Bitmap(srcImage->Width, srcImage->Height,
srcG);
Graphics ^toG = Graphics::FromImage(toImage);
IntPtr srcDc = srcG->GetHdc();
IntPtr toDc = toG->GetHdc();
BitBlt(toDc, 0, 0, srcImage->Width, srcImage->Height, srcDc, 0, 0,
0xCC0020);
srcG->ReleaseHdc(srcDc);
toG->ReleaseHdc(toDc);
srcImage->Save(CCarthageDefs::DIR_IMAGES + "test1.jpg");
toImage->Save(CCarthageDefs::DIR_IMAGES + "test2.jpg");
---
After running the above code, test1.jpg (an output of the source image) is a
correct copy of the source image. test2.jpg is *blank*?? Again, something
with the BitBlt seems to have failed ...
Also, to make sure I was actually hitting the genuine BitBlt code, I tried
using the options BLACKNESS and WHITENESS. Both worked ... the destination
turned the appropriate color.
Finally, in case anyone is interested in why I'm doing this ... I am having
some ugly flicker at the load-up of my form. I'm trying to take a copy of
the form's look, put it in a screen-sized picture box, and display that to
the user before they see the real form.
Thanks
cranke_boy - 26 Mar 2008 16:36 GMT
I thought the following might also be helpful:
- I tried to use control->DrawToBitmap(). but it doesn't draw all the
sub-controls that I need it to.
- I am using VC++ under Visual Studio Express 2008.
- Here is my prototype for BitBlt:
[System::Runtime::InteropServices::DllImportAttribute("gdi32.dll")]
extern bool BitBlt(IntPtr hDestDC,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hSrcDC,
int xSrc,
int ySrc,
int dwRop);
Norman Diamond - 27 Mar 2008 02:59 GMT
> IntPtr formDC = formGraphics->GetHdc();
In my experience, that creates a write-only Hdc. You can BitBlt to it in
order to draw, but BitBlt from it will do nothing and pretend to succeed.
> IntPtr bitmapDC = bitmapGraphics->GetHdc();
Sometimes that has the same problem.
http://support.microsoft.com/default.aspx?scid=kb;en-us;311221
At least one time I worked around it by getting the bits and calling
something like SetDIBitsToDevice.
> Hi Folks,
>
[quoted text clipped - 73 lines]
>
> Thanks
cranke_boy - 27 Mar 2008 04:59 GMT
I think you're bang on. Thanks.
When I changed the source DC to be something like GetWindowDC(this->Handle),
I was able to read from the source DC successfully. As you suggested, it
looks like doing Graphics->GetHdc() results in a write-only DC.
Does anyone know how to get a **readable** DC for a Bitmap object (since it
doesn't look like I can use GetWindowDC(handle) for such an object)? Is
there some standard way to do this?
I poked around at SetDIBitsToDevice, but I don't think I fully understand
how to apply it to this situation ...
> > IntPtr formDC = formGraphics->GetHdc();
>
[quoted text clipped - 9 lines]
> At least one time I worked around it by getting the bits and calling
> something like SetDIBitsToDevice.
Ben Voigt [C++ MVP] - 27 Mar 2008 14:52 GMT
> I think you're bang on. Thanks.
>
[quoted text clipped - 6 lines]
> (since it doesn't look like I can use GetWindowDC(handle) for such an
> object)? Is there some standard way to do this?
The pure GDI way to do that is CreateCompatibleDC followed by SelectObject.
But since source is a .NET Bitmap object and destination is a .NET Graphics,
why not just use DrawImage or DrawImageUnscaled instead of BitBlt?
> I poked around at SetDIBitsToDevice, but I don't think I fully
> understand how to apply it to this situation ...
[quoted text clipped - 13 lines]
>> At least one time I worked around it by getting the bits and calling
>> something like SetDIBitsToDevice.
Norman Diamond - 28 Mar 2008 02:38 GMT
> But since source is a .NET Bitmap object and destination is a .NET
> Graphics, why not just use DrawImage or DrawImageUnscaled instead of
> BitBlt?
I'm not the original poster but I'm cranky enough to know the answer.
DrawImage is about 50 times slower than StretchBlt, burdens a CPU core at
100% while it's running, and causes the user to give up and look for other
programs.
>> I think you're bang on. Thanks.
>>
[quoted text clipped - 31 lines]
>>> At least one time I worked around it by getting the bits and calling
>>> something like SetDIBitsToDevice.