Jump to content

Updating an image control from memory?


Recommended Posts

I'm sorry but could you split it into two seperate functions, one that gets the data of a control, and another that sets the data of a control? I'm trying to send a stream over a network.

Thanks for the help

 

Really, all that hard work for nothinggg?  Haha.. I suppose I misunderstood the full measure of what you wanted, but I did answer this question:

 1)how do I get the binary data from the source image control, and how to I then inject that data directly into another image control?

 

 

Also, the binary data can be retrieved if you look at my post which shows off GetDIBits.  The data inserted into the struct is RGBA data that can certainly be sent across a network, but unless you know the receiver is using Windows (in which case you can use SetDIBits also), you'll probably need to convert it to another format somewhere along the line.  Firefox's method is more time-consuming and compresses the images, but at least those images are cross-O/S compatible.

Link to comment
Share on other sites

Local $hBitmap=_GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    _WinAPI_DeleteObject(_SendMessage($PicCtrl,0x0172,0,$hBitmap));$__STM_SETIMAGE
    _WinAPI_DeleteObject($hBitmap)

sets the image handle to the $PicCtrl

[color=rgb(255,0,0);][font="'comic sans ms', cursive;"]FukuLeaks[/color][/font]

Link to comment
Share on other sites

Local $hBitmap=_GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
    _WinAPI_DeleteObject(_SendMessage($PicCtrl,0x0172,0,$hBitmap));$__STM_SETIMAGE
    _WinAPI_DeleteObject($hBitmap)

sets the image handle to the $PicCtrl

#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <TabConstants.au3>
#include <GDIPlus.au3>
#include <SendMessage.au3>
#include <Memory.au3>
#Region ### START Koda GUI section ### Form=
Global Const $STM_SETIMAGE = 0x0172
$Form1 = GUICreate("Form1", 158, 159, 192, 124)
$Pic1 = GUICtrlCreatePic("", 8, 8, 140, 140,BitOR($GUI_SS_DEFAULT_PIC,$SS_CENTERIMAGE,$SS_BITMAP,$WS_BORDER))
$hPic1 = GUICtrlGetHandle($Pic1)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
   $hBitmap=_GDIPlus_BitmapCreateHBITMAPFromBitmap(binary(FileRead(FileOpenDialog("", @WorkingDir, "All(*.*)"))))
    _WinAPI_DeleteObject(_SendMessage($hPic1,0x0172,0,$hBitmap));$__STM_SETIMAGE
    _WinAPI_DeleteObject($hBitmap)

While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit

EndSwitch
WEnd

Does not seem to work, you'll notice the data of the image control does not change.

Link to comment
Share on other sites

but wait...

.

$x_File=FileOpenDialog("", @WorkingDir, "All(*.*)")
$hImage=_GDIPlus_ImageLoadFromFile($x_File); full path here    
$hBitmap=_GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_WinAPI_DeleteObject(_SendMessage($PicCtrl,0x0172,0,$hBitmap));$__STM_SETIMAGE
_WinAPI_DeleteObject($hBitmap)

.

this will work

Edited by Edano

[color=rgb(255,0,0);][font="'comic sans ms', cursive;"]FukuLeaks[/color][/font]

Link to comment
Share on other sites

but wait...

.

$x_File=FileOpenDialog("", @WorkingDir, "All(*.*)")
$hImage=_GDIPlus_ImageLoadFromFile($x_File); full path here    
$hBitmap=_GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_WinAPI_DeleteObject(_SendMessage($PicCtrl,0x0172,0,$hBitmap));$__STM_SETIMAGE
_WinAPI_DeleteObject($hBitmap)

.

this will work

Yes but is there a way to do it with a binary string? I am processing a bmp to jpg to send it over a network, and don't want to have to first write the jpg to a file.

Edit: I am using this function, which returns the binary of a jpeg file.

Func _GDIPlus_SaveImage2Binary($hBitmap, $iQuality = 60) ;Coded by Andreik, modified by UEZ
    Local $sImgCLSID = _GDIPlus_EncodersGetCLSID("jpg")
    Local $tGUID = _WinAPI_GUIDFromString($sImgCLSID)
    Local $pEncoder = DllStructGetPtr($tGUID)
    Local $tParams = _GDIPlus_ParamInit(1)
    Local $tData = DllStructCreate("int Quality")
    DllStructSetData($tData, "Quality", $iQuality) ;quality 0-100
    Local $pData = DllStructGetPtr($tData)
    _GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, $pData)
    Local $pParams = DllStructGetPtr($tParams)
    Local $hStream = DllCall("ole32.dll", "uint", "CreateStreamOnHGlobal", "ptr", 0, "bool", True, "ptr*", 0)
    $hStream = $hStream[3]
    DllCall($ghGDIPDll, "uint", "GdipSaveImageToStream", "ptr", $hBitmap, "ptr", $hStream, "ptr", $pEncoder, "ptr", $pParams)
;~  _GDIPlus_BitmapDispose($hBitmap)
    Local $hMemory = DllCall("ole32.dll", "uint", "GetHGlobalFromStream", "ptr", $hStream, "ptr*", 0)
    $hMemory = $hMemory[2]
    Local $iMemSize = _MemGlobalSize($hMemory)
    Local $pMem = _MemGlobalLock($hMemory)
    $tData = DllStructCreate("byte[" & $iMemSize & "]", $pMem)
    Local $bData = DllStructGetData($tData, 1)
    Local $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data;ptr")
    DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $hStream, "dword", 8 + 8 * @AutoItX64, "dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT))
    _MemGlobalFree($hMemory)
    Return $bData
EndFunc   ;==>__GDIPlus_SaveImage2Binary
Edited by nullschritt
Link to comment
Share on other sites

What's wrong with the Load_BMP_From_Mem function I linked?

#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include <Memory.au3>
 
Global Const $STM_SETIMAGE = 0x0172
 
$hGUI = GUICreate("MyGUI")
$iMyPic1 = GUICtrlCreatePic("", 0, 0, 400, 400)
GUISetState(@SW_SHOW, $hGUI)
 
Local $hFile = FileOpen("image.bmp", $FO_BINARY)
Local $bData = FileRead($hFile) ;this is your binary data
FileClose($hFile)
 
_GDIPlus_Startup()
Local $hHBmp = Load_BMP_From_Mem($bData, True)
_GDIPlus_Shutdown()
 
_WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($iMyPic1), $STM_SETIMAGE, 0, $hHBmp))
_WinAPI_DeleteObject($hHBmp)
 
 
While GUIGetMsg() <> $GUI_EVENT_CLOSE
    Sleep(10)
WEnd
 
Func Load_BMP_From_Mem($memBitmap, $hHBITMAP = False)
    Local $len = 0, $tMem = 0, $hImage = 0, $hData = 0, $pData = 0, $hBitmap = 0, $aStream = 0, $tVARIANT = 0, $aCall = 0, $hHBmp = 0
    If IsBinary($memBitmap) = 0 Then $memBitmap = Binary($memBitmap) ;load image  saved in variable (memory) and convert it to binary
    $len = BinaryLen($memBitmap) ;get length of image
    $hData = _MemGlobalAlloc($len, $GMEM_MOVEABLE) ;allocates movable memory  ($GMEM_MOVEABLE = 0x0002)
    $pData = _MemGlobalLock($hData) ;translate the handle into a pointer
    $tMem = DllStructCreate("byte[" & $len & "]", $pData) ;create struct
    DllStructSetData($tMem, 1, $memBitmap) ;fill struct with image data
    _MemGlobalUnlock($hData) ;decrements the lock count  associated with a memory object that was allocated with GMEM_MOVEABLE
    $aStream = DllCall("ole32.dll", "int", "CreateStreamOnHGlobal", "handle", $pData, "int", True, "ptr*", 0)
    $hBitmap = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromStream", "ptr", $aStream[3], "int*", 0) ;Creates a Bitmap object based on an IStream COM interface
    $hBitmap = $hBitmap[2]
    $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data;ptr")
    $aCall = DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $aStream[3], "dword", 8 + 8 * @AutoItX64, _
            "dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT)) ;release memory from $hStream to avoid memory leak
    $tMem = 0
    If $hHBITMAP Then
        $hHBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
        _GDIPlus_BitmapDispose($hBitmap)
        Return $hHBmp
    EndIf
    Return $hBitmap
EndFunc   ;==>Load_BMP_From_Mem
Br, FireFox.
Link to comment
Share on other sites

nullschrift, I want to understand one part of this - are both ends of the interface going to be running Windows?  (i.e. the destination PC and the source PC).  If so, the binary data can be packaged much more quickly and easily into a BMP file, which is basically a very thin and lightweight wrapper around those 'DIB Bits' I worked with earlier.  Those DIB Bits are the actual binary data of the image in its uncompressed RGBA format.  No GDI+ code is necessary for that kind of work.

Link to comment
Share on other sites

 

What's wrong with the Load_BMP_From_Mem function I linked?

#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include <Memory.au3>
 
Global Const $STM_SETIMAGE = 0x0172
 
$hGUI = GUICreate("MyGUI")
$iMyPic1 = GUICtrlCreatePic("", 0, 0, 400, 400)
GUISetState(@SW_SHOW, $hGUI)
 
Local $hFile = FileOpen("image.bmp", $FO_BINARY)
Local $bData = FileRead($hFile) ;this is your binary data
FileClose($hFile)
 
_GDIPlus_Startup()
Local $hHBmp = Load_BMP_From_Mem($bData, True)
_GDIPlus_Shutdown()
 
_WinAPI_DeleteObject(_SendMessage(GUICtrlGetHandle($iMyPic1), $STM_SETIMAGE, 0, $hHBmp))
_WinAPI_DeleteObject($hHBmp)
 
 
While GUIGetMsg() <> $GUI_EVENT_CLOSE
    Sleep(10)
WEnd
 
Func Load_BMP_From_Mem($memBitmap, $hHBITMAP = False)
    Local $len = 0, $tMem = 0, $hImage = 0, $hData = 0, $pData = 0, $hBitmap = 0, $aStream = 0, $tVARIANT = 0, $aCall = 0, $hHBmp = 0
    If IsBinary($memBitmap) = 0 Then $memBitmap = Binary($memBitmap) ;load image  saved in variable (memory) and convert it to binary
    $len = BinaryLen($memBitmap) ;get length of image
    $hData = _MemGlobalAlloc($len, $GMEM_MOVEABLE) ;allocates movable memory  ($GMEM_MOVEABLE = 0x0002)
    $pData = _MemGlobalLock($hData) ;translate the handle into a pointer
    $tMem = DllStructCreate("byte[" & $len & "]", $pData) ;create struct
    DllStructSetData($tMem, 1, $memBitmap) ;fill struct with image data
    _MemGlobalUnlock($hData) ;decrements the lock count  associated with a memory object that was allocated with GMEM_MOVEABLE
    $aStream = DllCall("ole32.dll", "int", "CreateStreamOnHGlobal", "handle", $pData, "int", True, "ptr*", 0)
    $hBitmap = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromStream", "ptr", $aStream[3], "int*", 0) ;Creates a Bitmap object based on an IStream COM interface
    $hBitmap = $hBitmap[2]
    $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data;ptr")
    $aCall = DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $aStream[3], "dword", 8 + 8 * @AutoItX64, _
            "dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT)) ;release memory from $hStream to avoid memory leak
    $tMem = 0
    If $hHBITMAP Then
        $hHBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
        _GDIPlus_BitmapDispose($hBitmap)
        Return $hHBmp
    EndIf
    Return $hBitmap
EndFunc   ;==>Load_BMP_From_Mem
Br, FireFox.

 

right of course, sorry I haven't slept in a while >.<

Link to comment
Share on other sites

nullschrift, I want to understand one part of this - are both ends of the interface going to be running Windows?  (i.e. the destination PC and the source PC).  If so, the binary data can be packaged much more quickly and easily into a BMP file, which is basically a very thin and lightweight wrapper around those 'DIB Bits' I worked with earlier.  Those DIB Bits are the actual binary data of the image in its uncompressed RGBA format.  No GDI+ code is necessary for that kind of work.

Both ends are going to be windows but I want to use jpeg compression.

Link to comment
Share on other sites

Okay it seems that perhaps there is a bug in the gdi plus udf?

#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <TabConstants.au3>
#include <GDIPlus.au3>
#include <SendMessage.au3>
#include <Memory.au3>
#Region ### START Koda GUI section ### Form=
Global Const $STM_SETIMAGE = 0x0172
$Form1 = GUICreate("Form1", 158, 159, 192, 124)
$Pic1 = GUICtrlCreatePic("", 8, 8, 140, 140,BitOR($GUI_SS_DEFAULT_PIC,$SS_CENTERIMAGE,$SS_BITMAP,$WS_BORDER))
$hPic1 = GUICtrlGetHandle($Pic1)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

    $hBitmapxx = _GDIPlus_BitmapCreateFromfile(FileOpenDialog("", @WorkingDir, "BMP(*.bmp)"))
    $bData = _GDIPlus_SaveImage2Binary($hBitmapxx, 60)

_GDIPlus_Startup()
Local $hHBmp = Load_BMP_From_Mem($bData, True)
_GDIPlus_Shutdown()

    _WinAPI_DeleteObject(_SendMessage($hPic1,0x0172,0,$hHBmp));$__STM_SETIMAGE
    _WinAPI_DeleteObject($hHBmp)

While 1
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit

EndSwitch
WEnd

Func _GDIPlus_SaveImage2Binary($hBitmap, $iQuality = 60) ;Coded by Andreik, modified by UEZ
    Local $sImgCLSID = _GDIPlus_EncodersGetCLSID("jpg")
    Local $tGUID = _WinAPI_GUIDFromString($sImgCLSID)
    Local $pEncoder = DllStructGetPtr($tGUID)
    Local $tParams = _GDIPlus_ParamInit(1)
    Local $tData = DllStructCreate("int Quality")
    DllStructSetData($tData, "Quality", $iQuality) ;quality 0-100
    Local $pData = DllStructGetPtr($tData)
    _GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, $pData)
    Local $pParams = DllStructGetPtr($tParams)
    Local $hStream = DllCall("ole32.dll", "uint", "CreateStreamOnHGlobal", "ptr", 0, "bool", True, "ptr*", 0)
    $hStream = $hStream[3]
    DllCall($ghGDIPDll, "uint", "GdipSaveImageToStream", "ptr", $hBitmap, "ptr", $hStream, "ptr", $pEncoder, "ptr", $pParams)
;~  _GDIPlus_BitmapDispose($hBitmap)
    Local $hMemory = DllCall("ole32.dll", "uint", "GetHGlobalFromStream", "ptr", $hStream, "ptr*", 0)
    $hMemory = $hMemory[2]
    Local $iMemSize = _MemGlobalSize($hMemory)
    Local $pMem = _MemGlobalLock($hMemory)
    $tData = DllStructCreate("byte[" & $iMemSize & "]", $pMem)
    Local $bData = DllStructGetData($tData, 1)
    Local $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data;ptr")
    DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $hStream, "dword", 8 + 8 * @AutoItX64, "dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT))
    _MemGlobalFree($hMemory)
    Return $bData
EndFunc

Func Load_BMP_From_Mem($bImage, $hHBITMAP = False)
If Not IsBinary($bImage) Then Return SetError(1, 0, 0)
Local $aResult
Local Const $memBitmap = Binary($bImage) ;load image saved in variable (memory) and convert it to binary
Local Const $len = BinaryLen($memBitmap) ;get length of image
Local Const $hData = _MemGlobalAlloc($len, $GMEM_MOVEABLE) ;allocates movable memory ($GMEM_MOVEABLE = 0x0002)
Local Const $pData = _MemGlobalLock($hData) ;translate the handle into a pointer
Local $tMem = DllStructCreate("byte[" & $len & "]", $pData) ;create struct
DllStructSetData($tMem, 1, $memBitmap) ;fill struct with image data
_MemGlobalUnlock($hData) ;decrements the lock count associated with a memory object that was allocated with GMEM_MOVEABLE
$aResult = DllCall("ole32.dll", "int", "CreateStreamOnHGlobal", "handle", $pData, "int", True, "ptr*", 0) ;Creates a stream object that uses an HGLOBAL memory handle to store the stream contents
If @error Then Return SetError(2, 0, 0)
Local Const $hStream = $aResult[3]
$aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromStream", "ptr", $hStream, "int*", 0) ;Creates a Bitmap object based on an IStream COM interface
If @error Then Return SetError(3, 0, 0)
Local Const $hBitmap = $aResult[2]
Local $tVARIANT = DllStructCreate("word vt;word r1;word r2;word r3;ptr data; ptr")
DllCall("oleaut32.dll", "long", "DispCallFunc", "ptr", $hStream, "dword", 8 + 8 * @AutoItX64, _
"dword", 4, "dword", 23, "dword", 0, "ptr", 0, "ptr", 0, "ptr", DllStructGetPtr($tVARIANT)) ;release memory from $hStream to avoid memory leak
$tMem = 0
$tVARIANT = 0
If $hHBITMAP Then
Local Const $hHBmp = _GDIPlus_BitmapCreateDIBFromBitmap($hBitmap)
_GDIPlus_BitmapDispose($hBitmap)
Return $hHBmp
EndIf
Return $hBitmap
EndFunc ;==>Load_BMP_From_Mem

Func _GDIPlus_BitmapCreateDIBFromBitmap($hBitmap)
Local $tBIHDR, $Ret, $tData, $pBits, $hResult = 0
$Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImageDimension', 'ptr', $hBitmap, 'float*', 0, 'float*', 0)
If (@error) Or ($Ret[0]) Then Return 0
$tData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $Ret[2], $Ret[3], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
$pBits = DllStructGetData($tData, 'Scan0')
If Not $pBits Then Return 0
$tBIHDR = DllStructCreate('dword;long;long;ushort;ushort;dword;dword;long;long;dword;dword')
DllStructSetData($tBIHDR, 1, DllStructGetSize($tBIHDR))
DllStructSetData($tBIHDR, 2, $Ret[2])
DllStructSetData($tBIHDR, 3, $Ret[3])
DllStructSetData($tBIHDR, 4, 1)
DllStructSetData($tBIHDR, 5, 32)
DllStructSetData($tBIHDR, 6, 0)
$hResult = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBIHDR), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'dword', 0)
If (Not @error) And ($hResult[0]) Then
DllCall('gdi32.dll', 'dword', 'SetBitmapBits', 'ptr', $hResult[0], 'dword', $Ret[2] * $Ret[3] * 4, 'ptr', DllStructGetData($tData, 'Scan0'))
$hResult = $hResult[0]
Else
$hResult = 0
EndIf
_GDIPlus_BitmapUnlockBits($hBitmap, $tData)
Return $hResult
EndFunc ;==>_GDIPlus_BitmapCreateDIBFromBitmap
The above code generates the following error:

 

C:Program Files (x86)AutoIt3IncludeGDIPlus.au3 (957) : ==> Subscript used with non-Array variable.:

For $iI = 1 To $aEncoders[0][0]

For $iI = 1 To $aEncoders^ ERROR

edit: nevermind, initialization error.

Edited by nullschritt
Link to comment
Share on other sites

a different approach: write a temp.jpg and read it again. that cannot take so many milliseconds. imagine all the codelines you can spare... takes time as well

make some speed tests for us :)

Edited by Edano

[color=rgb(255,0,0);][font="'comic sans ms', cursive;"]FukuLeaks[/color][/font]

Link to comment
Share on other sites

a different approach: write a temp.jpg and read it again. that cannot take so many milliseconds. imagine all the codelines you can spare... takes time as well

 

make some speed tests for us :)

Sorry I don't understand the point in this, if it is already in memory why am I writing it to a file then reading it back(I am able to load it in memory with the load_bmp_from_mem function), do you mean this would re-size the image to fit in the control properly? But still I do not see how it would make a difference, it's going to be the same data that I originally wrote to the .jpg file.?

So I suppose then I would have to somehow size the image down using gdiplus?

Edited by nullschritt
Link to comment
Share on other sites

Sorry I don't understand the point in this, if it is already in memory why am I writing it to a file then reading it back(I am able to load it in memory with the load_bmp_from_mem function), do you mean this would re-size the image to fit in the control properly? But still I do not see how it would make a difference, it's going to be the same data that I originally wrote to the .jpg file.?

So I suppose then I would have to somehow size the image down using gdiplus?

.

yes, gdiplus resizes to fit automatically.

[color=rgb(255,0,0);][font="'comic sans ms', cursive;"]FukuLeaks[/color][/font]

Link to comment
Share on other sites

scaling down:

Local $ret=DllCall($ghGDIPDll,"int","GdipGetImageThumbnail","ptr",$hImage,"int",$Widthofcontrol,"int",$Heightofcontrol,"ptr*",0,"ptr",0,"ptr",0)
    $hImage=$ret[4]

.

min. OS win vista. for xp there is a solution

Edited by Edano

[color=rgb(255,0,0);][font="'comic sans ms', cursive;"]FukuLeaks[/color][/font]

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...