Sign in to follow this  
gretty

[Win32] Load Bitmap, Resize, & Copy to Static Control

Recommended Posts

Hello

I am trying to load a Bitmap, resize the bitmap to a certain size(that size will be determined at run time) & then show the bitmap on a static control


Right now my problem is in the resizing part:

I use the function StretchBlt(); to resize the bitmap but the function is returning zero which means the function failed. Can you suggest what I am doing wrong & if my code after that will copy the picture to the static control?


Some extra information that may be needed, I call this code in the message WM_CREATE & NOT in the WM_PAINT message.



void PopUpDialog :: SetStaticPicture()
{
bkgdImage = (HBITMAP) LoadImage( NULL, "popupbk.bmp", IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );


// Resize Bitmap to classes private vars width & height
HDC hdc = GetDC( hwnd );
HDC hdcMem = CreateCompatibleDC( hdc );
HDC hdcTar = CreateCompatibleDC( hdc );
BITMAP bm;
BITMAP newBm = CreateCompatibleBitmap( hdcTar, width, height ); // I want to place the resized bitmap in this variable

GetObject( bkgdImage, sizeof(bm), &bm );
SelectObject( hdcMem, bkgdImage );


// Copy the bkgdImage from the hdcMem to the newBm in hdcTar & resize it
int success = StretchBlt( hdcTar, 0, 0, newBm.bmWidth, newBm.bmHeight, hdcMem,
0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );


// the above function always fails
if ( success == 0 )
{
return false;
}


DeleteObject( &bkgdImage );
SelectObject( hdcTar, &newBm );

// Copy the contents of hdcTar(the resized bitmap) to bkgdImage
bkgdImage = CreateCompatibleBitmap( hdcTar, newBm.bmWidth, newBm.bmHeight );


// Rubbish collection
ReleaseDC( hwnd, hdc );
DeleteDC( hdcMem );
DeleteDC( hdcTar );
DeleteObject( &bm );
DeleteObject( &newBm );


// Set Statics background to bitmap
SendMessage( hwnd, STM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) bkgdImage );


}



Share this post


Link to post
Share on other sites
Hi, thanks for your reply.

Something weird is happening, when I use GetLastError() the error is 0(DWORD) & just "Error" when I use FormatMessage();


I have read the MSDN docs & I know that my StretchBlt() is failing because it is returning zero(what the docs say is the failed return value) & I have this code...


int success = StretchBlt( hdcTar, 0, 0, width, height, hdcMem, //newBm.bmWidth, newBm.bmHeight, hdcMem,
0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );

// if fail
if ( success == 0 )
{
DWORD a = GetLastError();
std::cout << a << endl;
char *buf;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, a, 0, buf, 600, NULL);
MessageBox( hwnd, (char*)a, (char*)a, MB_OK );
// the output is "Error" (0)
}







Maybe my actions are wrong, is it correct that to resize a bitmap:

- I need to load the bitmap from a file into a HBITMAP
- I need to select the bitmap with a hdc, SelectObject( hdcMem, myBitmap );
- Then use StretchBlt() to copy the scaled bitmap onto another hdc(hdcTar) & bitmap(newBm)

OR do I...

- I need to load the bitmap from a file into a HBITMAP
- I need to BitBlt() the original bitmap to a hdc( hdcMem)
- Then use StretchBlt() to copy the scaled bitmap onto another hdc(hdcTar) & bitmap(newBm)

Share this post


Link to post
Share on other sites
I see 3 things wrong off the top of my head:

CreateCompatibleBitmap returns an HBITMAP not a BITMAP.

You don't SelectObject anything into the hdcTar DC, so by default you have a 1x1 mono bitmap selected. That's why the StretchBlt call succeeds. I think you want to select newBm into it before the StretchBlt.

newBm.bmWidth and newBm.bmHeight in the StretchBlt call should be width and height, respectively.

[Edit]
On further review, you have further bugs:

You need to keep track of the return HGDIOBJ from the first SelectObject, otherwise you'll cause a GDI leak. Every HDC created has by default a 1x1 mono bitmap created and selected into it.

Your 2nd CreateCompatibleBitmap call where you "Copy the contents of hdcTar(the resized bitmap) to bkgdImage" doesn't do that. It instead just creates another "empty" bitmap. All you really need to do at that point is to use the newBm HBITMAP (once you correct the problem of calling it a BITMAP as noted above) to the static window via your SendMessage call.

You don't DeleteObject BITMAPs. They are not GDI objects that are allocated by the GDI api and therefore need to be cleaned up by you. They're just structs.

Make sure to SelectObject returned HGDIOBJs back into their respective HDCs prior to deleting the DC, otherwise you cause a GDI memory leak.

I hope that's everything. I don't have any more time to look over the code. I'm sure if I have something wrong in there I'll be corrected. Hopefully I got you on the right track though.

[Edit]
Quick rewrite due to further problems found (not tested);


void PopUpDialog :: SetStaticPicture()
{
HBITMAP bmpFrom = (HBITMAP) LoadImage( NULL, "popupbk.bmp", IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );

if( !bmpFrom ) return;

BITMAP bm;
GetObject( bmpFrom, sizeof(bm), &bm );

HDC hdc = GetDC( hwnd );
HDC hdcFrom = CreateCompatibleDC( hdc );
HDC hdcTo = CreateCompatibleDC( hdc );
HBITMAP bmpTo = CreateCompatibleBitmap( hdcTo, width, height );
HGDIOBJ hobFrom = SelectObject( hdcFrom, bmpFrom );
HGDIOBJ hobTo = SelectObject( hdcTo, bmpTo );

StretchBlt( hdcTo, 0, 0, width, height,
hdcFrom, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );

SelectObject( hdcFrom, hobFrom );
SelectObject( hdcTo, hobTo );

DeleteObject( bmpFrom );

ReleaseDC( hwnd, hdc );
DeleteDC( hdcFrom );
DeleteDC( hdcTo );

bkgdImage = bmpTo; // <<<< assuming bkgdImage is a HBITMAP member var here

SendMessage( hwnd, STM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) bkgdImage );
}



[Edited by - redllar on October 1, 2010 1:18:07 PM]

Share this post


Link to post
Share on other sites
Thanks guys, specially to redllar :D

I see where I went wrong with the GDI. And I never knew of the functions CopyImage() :P

I have done it 3 ways if anyone is interested for whenever they do something similiar.

It seems that I really dont need to StretchBlt() the bitmap to resize it(theres easier ways) but I am going to do it that way to learn. The other 2 ways are with CopyImage() - it resizes it perfectly that way also. And finally theres just LoadImage(), I can just say LoadImage( bkgdImage, IMAGE_BITMAP, "a.bmp", widthINeed, heightINeed,....); & it resizes it for me which is cool.


Thanks again

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this