Mbee Posted April 9, 2018 Posted April 9, 2018 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!
UEZ Posted April 9, 2018 Posted April 9, 2018 (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 load the image using _GDIPlus_BitmapCreateFromMemory() but as GDIPlus Resize it using _GDIPlus_ImageResize() or _GDIPlus_ImageScale() convert the resized image to GDI by using _GDIPlus_BitmapCreateHBITMAPFromBitmap() send the GDI image to your picture control dispose the GDI / GDIPlus resources Give it a try. Edited April 9, 2018 by UEZ Xandy and Mbee 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Mbee Posted April 16, 2018 Author Posted April 16, 2018 (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 April 16, 2018 by Mbee Xandy 1
Mbee Posted April 25, 2018 Author Posted April 25, 2018 (edited) Oh, wise @UEZ, I'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 April 25, 2018 by Mbee
UEZ Posted April 25, 2018 Posted April 25, 2018 (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 April 25, 2018 by UEZ Mbee 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
Mbee Posted April 25, 2018 Author Posted April 25, 2018 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!
Mbee Posted April 26, 2018 Author Posted April 26, 2018 (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 April 26, 2018 by Mbee
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now