Jump to content
Mbee

Suggestions for resizing Pic Control in this circumstance?

Recommended Posts

Mbee

Hi!

Okay, I've been spending a ridiculous amount of time on redesigning some buttons for one of my GUIs.  The existing ones are English text-based, but I now want to use symbol buttons (universal pictures inside a Pic button) because they will never need translating.  And while I'm trying and testing different designs, I don't want to have to worry about getting all the jpeg/png/whatever images set to any fixed sizes or aspect ratios.

Instead of reading files or resources for the various Pic controls, I use UEZ's utility to convert the image files into base 64 strings saved in the source code, to be loaded into memory in real time.

I'm using ISN AutoIt Studio to prototype the various GUI layouts using dummy pic controls.  Once the GUI in question has been created with GUICreate() and the various Pic controls have been created based on the ISN Studio prototype (.isf file has been #included), but these dummy pic controls have not yet been filled with a binary image, I want to obtain the size and position of each dummy Pic control, one by one, and then resize the memory-resident images to fit the preordained locations in the GUI prototype.

Here's a simpler description using pseudo-code:

For $i = 0 to $NumberOfDummyPicControls                                         ; For each dummy Pic control set up in ISN Studio Prototype
    Local $ControlAra = ControlGetPos( "", "", $DummyPicControlID[$i] )         ; Obtain the size and position of that dummy Pic control
    $BinPic = Load_Pic_From_Base64( $i )                                        ; Load the corresponding base 64 text string into binary in RAM
    $ResizedBinPic = ResizePicInMemory( $BinPic, $ControlAra )                  ; Now resize that memory-resident binary image to fit into that area
    SetDummyPicFromMemory( $DummyPicControlID[$i], $ResizedBinPic )             ; Update the pic control (I already have a func to do this)
Next

My question is: What would you advise for the "ResizePicInMemory()" function? 

I've tried _GDIPlus_BitmapCreateFromMemory() -> _GDIPlus_BitmapCreateHBITMAPFromBitmap() -> _GDIPlus_ImageResize(), etc, but I get a lot of errors when I try it that way.

Please advise?  Thanks!

Share this post


Link to post
Share on other sites
UEZ
Posted (edited)

By default _GDIPlus_BitmapCreateFromMemory() creates a GDIPlus bitmap which is not compatible with GDI bitmap format. GDI bitmaps are needed to send them to pic controls etc. Of course you can convert the saved in memory image to GDI format directly setting the 2nd parameter to True but then you have to use GDI functions for resizing.

I personally somehow prefer GDIPlus :D

  1. load the image using _GDIPlus_BitmapCreateFromMemory() but as GDIPlus
  2. Resize it using _GDIPlus_ImageResize() or _GDIPlus_ImageScale()
  3. convert the resized image to GDI by using _GDIPlus_BitmapCreateHBITMAPFromBitmap()
  4. send the GDI image to your picture control
  5. dispose the GDI / GDIPlus resources

Give it a try.

Edited by UEZ
  • Like 2

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Mbee
Posted (edited)

Thanks, UEZ! Sorry I didn't get a chance to get back here earlier...

I want to take this opportunity once more to express my strong and genuine gratitude for all the excellent help you've provided to me over the years! :)  I'm already relying on your great tools/code for converting images to base 64 with compression/decompression and placing those images into pic controls (among other things).

I am already using GDI+ for everything, but as you can see from my OP, I needed to know which GDI+ functions and algorithm to use, which you've solved very well.

Thanks again!

Edited by Mbee
  • Like 1

Share this post


Link to post
Share on other sites
Mbee
Posted (edited)

Oh, wise @UEZI've been very busy with other matters until now, and I've run into a problem. Here's what I have...

_GDIPlus_Startup()

Local $Lf_BitmapHdl = _GDIPlus_BitmapCreateFromMemory( $arg_BinaryImage, True )
$Lf_SizeTag = _WinAPI_GetBitmapDimension( $Lf_BitmapHdl )
Local $Lf_CurPicWidth = DllStructGetData( $Lf_SizeTag, 'X' )
Local $Lf_CurPicHeight = DllStructGetData( $Lf_SizeTag, 'Y' )

Local $Lf_PosAra = ControlGetPos( "", "", $arg_ControlID )
Local $Lf_CtlPicWidth = $Lf_PosAra[2]
Local $Lf_CtlPicHeight = $Lf_PosAra[3]
If $Lf_CtlPicWidth <> $Lf_CurPicWidth Then $Lf_MustResize = True
If $Lf_CtlPicHeight <> $Lf_CurPicHeight Then $Lf_MustResize = True
If $Lf_MustResize Then
    Local $Lf_ResizedBitmapHdl = _GDIPlus_ImageResize( $Lf_BitmapHdl, $Lf_CtlPicWidth, $Lf_CtlPicHeight )
    $Lf_Error = @error
    $Lf_Extended = @extended
    _WinAPI_DeleteObject( GUICtrlSendMsg( $arg_ControlID, $STM_SETIMAGE, $IMAGE_BITMAP, $Lf_ResizedBitmapHdl ) )
EndIf
_WinAPI_DeleteObject( GUICtrlSendMsg( $arg_ControlID, $STM_SETIMAGE, $IMAGE_BITMAP, $Lf_BitmapHdl ) )

_GDIPlus_Shutdown()

The call to _GDIPlus_ImageResize() always crashes. I suspect that's because it requires a handle to an "image object" rather than a handle to a bitmap.  But I'll be damned if I can find a way -- other than by using files -- to convert the bitmap / handle to an image object / handle.  I've looked through the list of GDIPlus Bitmap functions, but I don't see anything there that converts a bitmap to an image or other intermediary. The only possibility I can see is _GDIPlus_BitmapGetPixel(), and I have no clue how to use that to create an image object.

Note that the function doesn't return an error; what happens is the application crashes.

There are slightly more possibilities in the GDIPlus Image Management functions, such as _GDIPlus_ImageLoadFromStream(), but I have no idea how to create a stream from a bitmap handle.

Would you mind sharing your mind with us again, please?

Edited by Mbee

Share this post


Link to post
Share on other sites
UEZ
Posted (edited)

Try this (not tested):

_GDIPlus_Startup()

Local $Lf_BitmapHdl = _GDIPlus_BitmapCreateFromMemory( $arg_BinaryImage, True ) ;2nd parameter converts the image to GDI
$Lf_SizeTag = _WinAPI_GetBitmapDimension( $Lf_BitmapHdl )
Local $Lf_CurPicWidth = DllStructGetData( $Lf_SizeTag, 'X' )
Local $Lf_CurPicHeight = DllStructGetData( $Lf_SizeTag, 'Y' )

Local $Lf_PosAra = ControlGetPos( "", "", $arg_ControlID )
Local $Lf_CtlPicWidth = $Lf_PosAra[2]
Local $Lf_CtlPicHeight = $Lf_PosAra[3]
If $Lf_CtlPicWidth <> $Lf_CurPicWidth Then $Lf_MustResize = True
If $Lf_CtlPicHeight <> $Lf_CurPicHeight Then $Lf_MustResize = True
If $Lf_MustResize Then
    Local $Lf_BitmapHdl2 = _GDIPlus_BitmapCreateFromMemory( $arg_BinaryImage ) ;load the binary image again but as GDIPlus
    Local $Lf_ResizedBitmapHdl = _GDIPlus_ImageResize( $Lf_BitmapHdl2, $Lf_CtlPicWidth, $Lf_CtlPicHeight ) ;needs GDIPlus bitmap handle
    Local $Lf_ResizedBitmapHdl2 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($Lf_ResizedBitmapHdl) ;convert image to GDI format
    _WinAPI_DeleteObject( GUICtrlSendMsg( $arg_ControlID, $STM_SETIMAGE, $IMAGE_BITMAP, $Lf_ResizedBitmapHdl2 ) ) ;here we need a GDI handle
    _GDIPlus_ImageDispose($Lf_ResizedBitmapHdl)
    _GDIPlus_ImageDispose($Lf_BitmapHdl2)
    _WinAPI_DeleteObject($Lf_ResizedBitmapHdl2)
EndIf
_WinAPI_DeleteObject( GUICtrlSendMsg( $arg_ControlID, $STM_SETIMAGE, $IMAGE_BITMAP, $Lf_BitmapHdl ) )
_WinAPI_DeleteObject($Lf_BitmapHdl)
_GDIPlus_Shutdown()

 

Afaik, _GDIPlus_ImageLoadFromStream() function is to stream an image to a different format such as JPG, PNG, etc. 

An example can be found here to stream image to JPG format:

 

Edited by UEZ
  • Like 1

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Mbee

You are a god, sir @UEZ !!  That worked perfectly! :)

NOW I understand your earlier post about preferring GDI+, since I had thought I'd been using it all along.  I've been working on this particular application for so long (periodically) that I simply used "True" as the second parameter in those calls out of blind habit.  It was not until I read your vital comment in the code you posted above about passing True to that call that I realized my dumb mistake.

Once again I am in your considerable debt.  Thanks tremendously!

Share this post


Link to post
Share on other sites
Mbee
Posted (edited)

Oops, there was a major bug in the code I submitted in post #4, which of course got brought along in @UEZ's code (not his fault).  As it was, the resized image was immediately replaced with the non-resized original!  I'd fixed it almost immediately, but I thought I should post the correct code.

Here's the working version:

_GDIPlus_Startup()

Local $Lf_BitmapHdl = _GDIPlus_BitmapCreateFromMemory( $arg_BinaryImage, True ) ;2nd parameter converts the image to GDI
$Lf_SizeTag = _WinAPI_GetBitmapDimension( $Lf_BitmapHdl )
Local $Lf_CurPicWidth = DllStructGetData( $Lf_SizeTag, 'X' )
Local $Lf_CurPicHeight = DllStructGetData( $Lf_SizeTag, 'Y' )

Local $Lf_PosAra = ControlGetPos( "", "", $arg_ControlID )
Local $Lf_CtlPicWidth = $Lf_PosAra[2]
Local $Lf_CtlPicHeight = $Lf_PosAra[3]
If $Lf_CtlPicWidth <> $Lf_CurPicWidth Then $Lf_MustResize = True
If $Lf_CtlPicHeight <> $Lf_CurPicHeight Then $Lf_MustResize = True
If $Lf_MustResize Then
    Local $Lf_BitmapHdl2 = _GDIPlus_BitmapCreateFromMemory( $arg_BinaryImage ) ;load the binary image again but as GDIPlus
    Local $Lf_ResizedBitmapHdl = _GDIPlus_ImageResize( $Lf_BitmapHdl2, $Lf_CtlPicWidth, $Lf_CtlPicHeight ) ;needs GDIPlus bitmap handle
    Local $Lf_ResizedBitmapHdl2 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($Lf_ResizedBitmapHdl) ;convert image to GDI format
    _WinAPI_DeleteObject( GUICtrlSendMsg( $arg_ControlID, $STM_SETIMAGE, $IMAGE_BITMAP, $Lf_ResizedBitmapHdl2 ) ) ;here we need a GDI handle
    _GDIPlus_ImageDispose($Lf_ResizedBitmapHdl)
    _GDIPlus_ImageDispose($Lf_BitmapHdl2)
    _WinAPI_DeleteObject($Lf_ResizedBitmapHdl2)
Else
    _WinAPI_DeleteObject( GUICtrlSendMsg( $arg_ControlID, $STM_SETIMAGE, $IMAGE_BITMAP, $Lf_BitmapHdl ) )
    _WinAPI_DeleteObject($Lf_BitmapHdl)
EndIf

_GDIPlus_Shutdown()

 

Edited by Mbee

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

×