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

Started by
4 comments, last by gretty 13 years, 6 months ago
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 );      }
Advertisement
What does GetLastError() return when StretchBlt fails?
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)
What's wrong with CopyImage?
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]
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

This topic is closed to new replies.

Advertisement