Jump to content
c.haslam

Rethinking _GDIPlus_Image*PropertyItem* functions

Recommended Posts

c.haslam
Posted (edited)

I think that _GDIPlus_ImageGetPropertyItem should return a Property Item that can readily be set as a property of another image. Why would one want to do this? A script might (as one of mine does) edit an image of a .jpg file then write the result to a .jpg file. In editing it, in my case, the number of horizontal and vertical pixels change, and the date/time edited should be set as a property. All other property items remain the same. Other GDI+ users may change other properties.

So an approach is to copy all the property items from image1 to image2, then update a few properties.

M$ provides a Property Item class (id, length, pointer to an array of values) but _GDIPlus_ImageGetPropertyItem returns something different.

I think that, wherever reasonable, UDFs that are wrappers for M$ methods should work like M$'s methods. _GDIPlus_ImageGetPropertyItem does not do this:

  • While M$ returns 2 values for a value that is a ratio of 2 numbers,  _GDIPlus_ImageGetPropertyItem returns numerator/denominator as a single value (often a Double). _GDIPlus_ImageSetPropertyItem (when included in GDIPlus.au3) will be unable to set ratio property items properly because it cannot know what the numerator and denominator are. So copying such property items will not work properly.
  • M$ has a Void* buffer where the buffer is an array of values but _GDIPlus_ImageGetPropertyItem() returns the values in the same 1-d array as id, length and type. M$'s approach produces a 1-d array with the same number of elements for all property items while _GDIPlus_ImageGetPropertyItem produces a 1-d array with various numbers of elements. To me, this is not good programming practice. For a photo from a Sony camera, the worst case has 1-d array with 67 elements. When combined into a 2-d array with the property items of all properties, there are 66 rows and 67 columns, with many elements not used.

So I suggest that _GDIPlus_ImageGetPropertyItem look like this:

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ImageGetPropertyItem
; Description ...: Gets a specified property item (piece of meta data) from an Image object
; Syntax ........: cGDIPlus_ImageGetPropertyItem($hImage, $iPropID)
; Parameters ....: $hImage              - Pointer to an image object
;                  $iPropID             - Identifier of the property item to be retrieved
; Return values .: Success: Array containing the values of the property item
;                                    [0] - identifier
;                                    [1] - size, in bytes, of the value array
;                                    [2] - type of value(s) in the value array
;                                    [3] - value array
;                  Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*).
; Author ........: Eukalyptus
; Modified ......: c.haslam
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, undefined = 7, signed long = 9, signed rational = 10
; Related .......: _GDIPlus_ImageGetPropertyIdList
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx
; Example .......: Yes
; ===============================================================================================================================
Func cGDIPlus_ImageGetPropertyItem($hImage, $iPropID)
    Local $iSize = __GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
    If @error Then Return SetError(@error, @extended, -1)

    Local $tBuffer = DllStructCreate("byte[" & $iSize & "];")
    Local $pBuffer = DllStructGetPtr($tBuffer)
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetPropertyItem", "handle", $hImage, "uint", _
        $iPropID, "uint", $iSize, "struct*", $tBuffer)
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)

    Local $tPropertyItem = DllStructCreate("int id; int length; short type; ptr pvalue;", $pBuffer)
    Local $iBytes = DllStructGetData($tPropertyItem, "length")
    Local $pValue = DllStructGetData($tPropertyItem, "pvalue")

    Local $aRet[4]
    Local $type = DllStructGetData($tPropertyItem,'type')
    Local $tValues, $iValues
    Switch $type
        Case 2 ;ASCII String
            $iValues = 1
            $tValues = DllStructCreate("char[" & $iBytes & "];", $pValue)
        Case 3 ;Array of UShort
            $iValues = Int($iBytes / 2)
            $tValues = DllStructCreate("ushort[" & $iValues & "];", $pValue)
        Case 4, 5 ;Array of UInt / Fraction
            $iValues = Int($iBytes / 4)
            $tValues = DllStructCreate("uint[" & $iValues & "];", $pValue)
        Case 9, 10 ;Array of Int / Fraction
            $iValues = Int($iBytes / 4)
            $tValues = DllStructCreate("int[" & $iValues & "];", $pValue)
        Case Else ;Array of Bytes
            $iValues = 1
            $tValues = DllStructCreate("byte[" & $iBytes & "];", $pValue)
    EndSwitch
    $aRet[0] = DllStructGetData($tPropertyItem,'id')
    $aRet[1] = $iBytes
    $aRet[2] = $type
    Local $aVals[$iValues]
    If $type=2 Or $type=7 Then  ; ASCII string or undefined
        $aVals[0] = DllStructGetData($tValues,1)
    Else
        For $i = 0 To $iValues-1
            $aVals[$i] = DllStructGetData($tValues,1,$i+1)
        Next
    EndIf
    $aRet[3] = $aVals
    Return $aRet
EndFunc

And here is an example:

#include <GDIPlus.au3>
#include <Array.au3>

Example()

Func Example()
    _GDIPlus_Startup()
    Local $hImage = _GDIPlus_ImageLoadFromFile(RegRead((@AutoItX64 = True ? "HKLM\SOFTWARE\Wow6432Node\AutoIt v3\AutoIt" : "HKLM\SOFTWARE\AutoIt v3\AutoIt"), "InstallDir") & "\Examples\GUI\Torus.png")
    If @error Then
        _GDIPlus_Shutdown()
        MsgBox(16, "", "An error has occured - unable to load image!", 30)
        Return False
    EndIf
    Local $ar = _GDIPlus_ImageGetPropertyIdList($hImage)
    Local $vPropNbrs[UBound($ar,1)-1]
    ; Extract ID numbers
    For $i = 1 To UBound($ar,1)-1
        $vPropNbrs[$i-1] = $ar[$i][0]
    Next

    ; Get all property items
    Local $aPropItems[UBound($vPropNbrs)][4],$vPropItem
    For $i = 0 To UBound($vPropNbrs)-1
        $vPropItem = cGDIPlus_ImageGetPropertyItem($hImage,$vPropNbrs[$i])
        For $j = 0 To 3
            $aPropItems[$i][$j] = $vPropItem[$j]
        Next
    Next

    ; Collapse values arrays so _ArrayDisplay can display them
    Local $ar = $aPropItems
    For $i = 0 To UBound($aPropItems,1)-1
        $ar[$i][0] = '0x'&Hex($ar[$i][0],4)
        $ar[$i][3] = ''
        For $j = 0 To UBound($aPropItems[$i][3])-1
            $ar[$i][3] &= ($aPropItems[$i][3])[$j]&'|'
        Next
        $ar[$i][3] = StringTrimRight($ar[$i][3],1)
    Next
    _ArrayDisplay($ar)

    _GDIPlus_Shutdown()
EndFunc

Unfortunately this example (based on one now in the Help) does not exercise most of the item types, but I do not know of a file with EXIF metadata that is on most PCs. I have tested this code by updating and adding property items to torus.jpg and to a photo taken by a Sony camera. The code for implementing and calling _GDIPlus_ImageSetPropertyItem will be fairly simple [see below].

 

Your thoughts?

 

Edited by c.haslam
clarification; no bug for type 7

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam
Posted (edited)

And here is cGDIPlus_ImageSetPropertyItem, the inverse of cGDIPlus_ImageGetPropertyItem

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ImageSetPropertyItem
; Description ...: Sets a specified property item (piece of meta data) for an Image object
; Syntax ........: cGDIPlus_ImageGetPropertyItem($hImage, $a1PropertyItem)
; Parameters ....: $hImage              - Pointer to an image object
;                  $a1PropertyItem      - Array containing the values of the property item
;                      [0] - identifier
;                      [1] - size,of the value array
;                               positive: in bytes
;                               negative: for numeric types: in number of values
;                      [2] - type of value(s) in the value array
;                      [3] - value array
; Return values .: Success: @error = 0
;                  Failure: sets the @error flag to non-zero
;                  +   >0: DllCall failed. @extended contains GPSTATUS error code ($GPID_ERR*).
;                  +   -1: size cannot be negative for ASCII string and undefined types
; Author ........: Eukalyptus
; Modified ......: c.haslam
; Remarks .......: If size parameter is negative, calculates size in bytes from type.
;                  Convenient when setting a few property items
;                  +
;                  types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, undefined = 7, signed long = 9, signed rational = 10
; Related .......: _GDIPlus_ImageGetPropertyIdList, cGDIPlus_ImageGetPropertyItem
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx
; Example .......: Yes
; ===============================================================================================================================
Func cGDIPlus_ImageSetPropertyItem($hImage,$a1PropertyItem)
    Local $iId = $a1PropertyItem[0]
    Local $iLength = $a1PropertyItem[1]
    Local $iType = $a1PropertyItem[2]
    Local $a1values = $a1PropertyItem[3]

    Local $iBytes,$iqValues
    If $iLength>0 Then                  ; useful when copying all property items
        $iBytes = $iLength
        Switch $iType
            Case 2 ;ASCII String
                $iqValues = 1
            Case 3 ;Array of UShort
                $iqValues = Int($iLength / 2)
            Case 4, 5, 9, 10 ;Array of UInt / Fraction
                $iqValues = Int($iLength / 4)
            Case Else ; Array of Bytes, undefined
                $iqValues = 1
        EndSwitch
    ElseIf $iLength<0 Then              ; convenient when setting a few property items
        Switch $iType
            Case 2, 7 ;ASCII String, undefined
                Return SetError(-1)
            Case 3 ;Array of UShort
                $iBytes = -$iLength*2
            Case 4, 5, 9, 10 ;Array of UInt / Fraction
                $iBytes = -$iLength*4
            Case Else ;Array of Bytes
                $iqValues = 1
                $iBytes = -$iLength
        EndSwitch
        $iqValues = -$iLength
    EndIf

    Local $tPropItem = DllStructCreate("int id; int length; short type; ptr pValue;")
    DllStructSetData($tPropItem,'id',$iId)
    DllStructSetData($tPropItem,'length',$iBytes)
    DllStructSetData($tPropItem,'type',$iType)

    Local $tValues

    Switch $iType
        Case 2 ;ASCII String
            $tValues = DllStructCreate("char[" & $iBytes & "];")
        Case 3 ;Array of UShort
            $tValues = DllStructCreate("ushort[" & $iqValues & "];")
        Case 4, 5 ;Array of UInt / Fraction
            $tValues = DllStructCreate("uint[" & $iqValues & "];")
        Case 9, 10 ;Array of Int / Fraction
            $tValues = DllStructCreate("int[" & $iqValues & "];")
        Case Else ;Array of Bytes
            $tValues = DllStructCreate("byte[" & $iBytes & "];")
    EndSwitch
    If $iType=2 Or $iType=7 Then    ; ASCII string or undefined
        DllStructSetData($tValues,1,$a1values[0])
    Else
        For $i = 0 To $iqValues-1
            DllStructSetData($tValues,1,$a1values[$i],$i+1)
        Next
    EndIf
    DllStructSetData($tPropItem,'pValue',DllStructGetPtr($tValues))

    Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipSetPropertyItem", "hwnd", $hImage, "struct*", $tPropItem)
    If @error Then Return SetError(@error, @extended, -1)
EndFunc

While I was at it, I made it convenient for updating or adding properties: if the value(s) are numeric, if size is negative, the function determines the number of bytes.

Here is an example of both Get and Set:

Func Example()
    _GDIPlus_Startup()
    Local $hImage = _GDIPlus_ImageLoadFromFile(RegRead((@AutoItX64 = True ? "HKLM\SOFTWARE\Wow6432Node\AutoIt v3\AutoIt" : "HKLM\SOFTWARE\AutoIt v3\AutoIt"), "InstallDir") & "\Examples\GUI\Torus.png")
    Local $a2PropertyItems = GetAllProjectItems($hImage)
    DisplayPropertyItems($a2PropertyItems)

    Local $hImageClone = _GDIPlus_ImageClone($hImage)   ; copy image without property items

    Local $a1[4]
    For $i = 0 To UBound($a2PropertyItems,1)-1      ; set all property items
        For $j = 0 To 3
            $a1[$j] = $a2PropertyItems[$i][$j]
        Next
        cGDIPlus_ImageSetPropertyItem($hImageClone,$a1)
    Next

    ; update a property item
    Local $a1value = ['Your name']
    Local $a1 = [0x13B,20,2,$a1value]       ; Artist
    cGDIPlus_ImageSetPropertyItem($hImageClone,$a1)

    ; add a property item
    Local $a1value = [2000]
    Local $a1 = [0xa002,-1,4,$a1value]  ; ExifWidth
    cGDIPlus_ImageSetPropertyItem($hImageClone,$a1)

    Local $a2PropertyItems = GetAllProjectItems($hImageClone)
    DisplayPropertyItems($a2PropertyItems)

    _GDIPlus_Shutdown()
EndFunc

Func GetAllProjectItems($hImage)
    Local $a2 = _GDIPlus_ImageGetPropertyIdList($hImage)
    Local $a1propertyIds[UBound($a2,1)-1]
    ; Extract ID numbers
    For $i = 1 To UBound($a2,1)-1
        $a1propertyIds[$i-1] = $a2[$i][0]
    Next

    Local $a2PropertyItems[UBound($a1propertyIds)][4],$a1
    For $i = 0 To UBound($a1propertyIds)-1
        $a1 = cGDIPlus_ImageGetPropertyItem($hImage,$a1propertyIds[$i])
        For $j = 0 To 3
            $a2PropertyItems[$i][$j] =  $a1[$j]
        Next
    Next
    Return $a2PropertyItems
EndFunc

Func DisplayPropertyItems($a2PropertyItems)
    ; Collapse values arrays so _ArrayDisplay can display them
    Local $a2 = $a2PropertyItems
    For $i = 0 To UBound($a2,1)-1
        $a2[$i][0] = '0x'&Hex($a2PropertyItems[$i][0],4)
        $a2[$i][3] = ''
        For $j = 0 To UBound($a2PropertyItems[$i][3])-1
            $a2[$i][3] &= ($a2PropertyItems[$i][3])[$j]&'|'
        Next
        $a2[$i][3] = StringTrimRight($a2[$i][3],1)
    Next
    _ArrayDisplay($a2)
EndFunc

I have also tested these functions with a .jpg produced by a camera.

Edited by c.haslam
Fixed capitalization of parameter for clarity

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam
Posted (edited)

Here is cGDIPlus_ImageGetAllPropertyItems. Some of the code is the same as for cGDIPlus_ImageGetPropertyItem so I have rewritten cGDIPlus_ImageGetPropertyItem and added an internal function __ConvertProjectItemToNestedArrays. They are also here:

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ImageGetAllPropertyItems
; Description ...: Gets all property item (piece of meta data) from an Image object
; Syntax ........: cGDIPlus_ImageGetAllPropertyItems($hImage)
; Parameters ....: $hImage              - Pointer to an image object
; Return values .: Success: Array in which each row contains these columns:
;                      [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
;                  Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*).
; Author ........: c.haslam
; Modified ......:
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......: cGDIPlus_ImageGetPropertyItem, _GDIPlus_ImageGetPropertyIdList, cGDIPlus_ImageSetPropertyItem
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx
; Example .......: Yes
; ===============================================================================================================================

Func cGDIPlus_ImageGetAllPropertyItems($hImage)
    Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetPropertySize", "hwnd", $hImage, "uint*", 0, "uint*", 0)
    Local $iTotalBufferSize = $aResult[2]
    Local $iNumProperties = $aResult[3]
    If @error Then Return SetError(@error, @extended, -1)

    Local $tBuffer = DllStructCreate("byte[" & $iTotalBufferSize & "]")
    Local $pBuffer = DllStructGetPtr($tBuffer)

    Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetAllPropertyItems", "hwnd", $hImage, _
        "uint", $iTotalBufferSize, "uint", $iNumProperties, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, -1)

    Local $aPropertyItems[$iNumProperties][4]
    Local $a1
    Local $tPropertyItem = DllStructCreate("int id; int length; short type; ptr value;")

    For $iI = 0 To $iNumProperties-1
        $a1 = __ConvertProjectItemToNestedArrays($pBuffer)
        For $j = 0 To 3
            $aPropertyItems[$iI][$j] = $a1[$j]
        Next
        $pBuffer += DllStructGetSize($tPropertyItem)
    Next
    Return $aPropertyItems
EndFunc

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ImageGetPropertyItem
; Description ...: Gets a specified property item (piece of meta data) from an Image object
; Syntax ........: cGDIPlus_ImageGetPropertyItem($hImage, $iPropID)
; Parameters ....: $hImage              - Pointer to an image object
;                  $iPropID             - Identifier of the property item to be retrieved
; Return values .: Success: Array containing the values of the property item
;                      [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
;                  Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*).
; Author ........: Eukalyptus
; Modified ......: c.haslam
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......: _GDIPlus_ImageGetPropertyIdList, cGDIPlus_ImageSetPropertyItem
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx
; Example .......: Yes
; ===============================================================================================================================
Func cGDIPlus_ImageGetPropertyItem($hImage, $iPropID)
    Local $iSize = __GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
    If @error Then Return SetError(@error, @extended, -1)

    Local $tBuffer = DllStructCreate("byte[" & $iSize & "];")
    Local $pBuffer = DllStructGetPtr($tBuffer)
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetPropertyItem", "handle", $hImage, "uint", _
        $iPropID, "uint", $iSize, "struct*", $tBuffer)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)
    If @error Then Return SetError(@error, @extended, -1)

    Return __ConvertProjectItemToNestedArrays($pBuffer)
EndFunc

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name ..........: __ConvertProjectItemToNestedArrays($pBuffer)
; Description ...: Converts a project item from structured to equivalent nested arrays
; Syntax ........: __ConvertProjectItemToNestedArrays($pBuffer)
; Parameters ....: $bBuffer             - Pointer to start of Property Item sructure
; Return values .:     [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
; Author ........: c.haslam
; Modified ......:
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================

Func __ConvertProjectItemToNestedArrays($pBuffer)
    Local $tPropertyItem = DllStructCreate("int id; int length; short type; ptr value;", $pBuffer)
    Local $iBytes = DllStructGetData($tPropertyItem, "length")
    Local $pValue = DllStructGetData($tPropertyItem, "value")

    Local $aRet[4]
    Local $type = DllStructGetData($tPropertyItem,'type')
    Local $tValues, $iValues
    Switch $type
        Case 2 ;ASCII String
            $iValues = 1
            $tValues = DllStructCreate("char[" & $iBytes & "];", $pValue)
        Case 3 ;Array of UShort
            $iValues = Int($iBytes / 2)
            $tValues = DllStructCreate("ushort[" & $iValues & "];", $pValue)
        Case 4, 5 ;Array of UInt / Fraction
            $iValues = Int($iBytes / 4)
            $tValues = DllStructCreate("uint[" & $iValues & "];", $pValue)
        Case 9, 10 ;Array of Int / Fraction
            $iValues = Int($iBytes / 4)
            $tValues = DllStructCreate("int[" & $iValues & "];", $pValue)
        Case Else ;Array of Bytes
            $iValues = 1
            $tValues = DllStructCreate("byte[" & $iBytes & "];", $pValue)
    EndSwitch
    $aRet[0] = DllStructGetData($tPropertyItem,'id')
    $aRet[1] = $iBytes
    $aRet[2] = $type
    Local $a1values[$iValues]
    If $type=2 Or $type=7 Then  ; ASCII string or undefined
        $a1values[0] = DllStructGetData($tValues,1)
    Else
        For $i = 0 To $iValues-1
            $a1values[$i] = DllStructGetData($tValues,1,$i+1)
        Next
    EndIf
    $aRet[3] = $a1values
    Return $aRet
EndFunc

The example, which exemplifies Get, Set and GetAll, is here:

Func Example()
    _GDIPlus_Startup()
    Local $hImage = _GDIPlus_ImageLoadFromFile(RegRead((@AutoItX64 = True ? "HKLM\SOFTWARE\Wow6432Node\AutoIt v3\AutoIt" : "HKLM\SOFTWARE\AutoIt v3\AutoIt"), "InstallDir") & "\Examples\GUI\Torus.png")
    Local $a2PropertyItems = cGDIPlus_ImageGetAllPropertyItems($hImage)
    DisplayPropertyItems($a2PropertyItems)

    Local $hImageClone = _GDIPlus_ImageClone($hImage)   ; copy image without property items

    Local $a1[4]
    For $i = 0 To UBound($a2PropertyItems,1)-1      ; set all property items
        For $j = 0 To 3
            $a1[$j] = $a2PropertyItems[$i][$j]
        Next
        cGDIPlus_ImageSetPropertyItem($hImageClone,$a1)
    Next

    ; update a property item
    Local $a1value = ['Your name']
    Local $a1 = [0x13B,20,2,$a1value]       ; Artist
    cGDIPlus_ImageSetPropertyItem($hImageClone,$a1)

    ; add a property item
    Local $a1value = [2000]
    Local $a1 = [0xa002,-1,4,$a1value]  ; ExifWidth
    cGDIPlus_ImageSetPropertyItem($hImageClone,$a1)

    Local $a1value = [0xFFFE01]
    Local $a1 = [0x927C,3,7,$a1value]   ; MakerNote
    cGDIPlus_ImageSetPropertyItem($hImageClone,$a1)

    Local $a2PropertyItems = cGDIPlus_ImageGetAllPropertyItems($hImageClone)
    DisplayPropertyItems($a2PropertyItems)

    Local $a1 = cGDIPlus_ImageGetPropertyItem($hImageClone,0x927c)
    Local $a2[1][4]
    For $i = 0 To 3
        $a2[0][$i] = $a1[$i]
    Next
    DisplayPropertyItems($a2)

    _GDIPlus_Shutdown()
EndFunc

Func DisplayPropertyItems($a2PropertyItems)
    ; Collapse values arrays so _ArrayDisplay can display them
    Local $a2 = $a2PropertyItems
    For $i = 0 To UBound($a2,1)-1
        $a2[$i][0] = '0x'&Hex($a2PropertyItems[$i][0],4)
        $a2[$i][3] = ''
        For $j = 0 To UBound($a2PropertyItems[$i][3])-1
            $a2[$i][3] &= ($a2PropertyItems[$i][3])[$j]&'|'
        Next
        $a2[$i][3] = StringTrimRight($a2[$i][3],1)
    Next
    _ArrayDisplay($a2)
EndFunc

 

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam
Posted (edited)

I suggest that there are 2 disadvantages with the implementation of _GDIPlus_ImageGetPropertyIdList:

  • $sPropertyTagInfo, which contains 217 numbers and names, is incomplete. There are literally hundreds of tags: see http://owl.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html for a long list. Because $sPropertyTagInfo is incomplete, users of this function are likely to ask that it be updated from time to time -- when gurus would prefer to be handling real technical problems, rather than answering users.
  • StringRegExp is relatively CPU-intensive. While torus.jpg has only 8 properties, the photograph .JPEGs from my 2 cameras have 66 and 52 property items respectively, causing StringRegExp to be executed once, and the For ... Next loop to be executed many times. This is OK if a user needs all the item names but will slow down his script unnecessarily if he does not. On a photo JPEG, removing returning the names reduces the CPU time by 60%

I suggest that the Help include a link such as the one above so users can themselves link tag to tag name.

Another observation: in the Help, I found Property identifier and Property ID Info to be confusing. If you decide to keep this function as it is, I suggest Number and Name.

Further, I personally have gone to making all arrays ref 0 rather than ref 1. There may be a mixture of ref 1 and ref 0 in GDIPlus.au3.

Of course, I am free to use whatever variations of functions I like in my scripts. My suggestions are for the common good.

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


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

@c.haslam thanks for your contribution. I need to check first in detail your posted code and do some research. This may take some days (weeks?).

 

@Melba23, @JLogan3o13 can you move this topic to "AutoIt Technical Discussion" please?

 

 

Edited by UEZ

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
c.haslam

UEZ,

Good to hear from you! No rush -- and a I am sure that your have much else to do!


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam

In debugging my versions of the above functions, I have used one function and one tool.

The function is here:

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ReportIfErrorInDLLcall
; Description ...: Reports and exits if @error non-zero or $aResult[0] non-zero
; Syntax ........: cGDIPlus_ReportIfErrorInDLLcall($iError, $iStatus, $sFuncName)
; Parameters ....: $iError             - @error from DllCall()
;                  $iStatus            - $aResult[0] from DLLCall
;                  $sFuncName          - function parameter of DLLCall
; Return values .: None
; Author ........: c.haslam
; Modified ......:
; Remarks .......: Example: cGDIPlus_ReportIfErrorInDLLCall(@error, $aResult[0],'GdipSetPropItemItem')
; Related .......: all GDIPlus_* functions
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms534175(v=vs.85).aspx
; Example .......: No
; ===============================================================================================================================

Func cGDIPlus_ReportIfErrorInDLLcall($iError,$iStatus,$sFuncName)
    If $iError=0 And $iStatus=0 Then
        Return
    EndIf
    If $iError<>0 Then
        MsgBox($MB_ICONERROR,'GDIPlus call error',$sFuncName&' @error = '&$iError)
        Exit
    EndIf

Local $a1Status = ['Ok','GenericError','InvalidParameter','OutOfMemory','ObjectBusy','InsufficientBuffer', _
    'NotImplemented','Win32Error','WrongState','Aborted','FileNotFound','ValueOverflow','AccessDenied', _
    'UnknownImageFormat','FontFamilyNotFound','FontStyleNotFound','NotTrueTypeFont','UnsupportedGdiplusVersion', _
    'GdiplusNotInitialized','PropertyNotFound','PropertyNotSupported','ProfileNotFound']
    If $iStatus<>0 Then
        MsgBox($MB_ICONERROR,'GDIPlus call error',$sFuncName&' '&$a1Status[$iStatus])
        Exit
    EndIf
EndFunc

Because users should only be calling GDIPlus_* functions, they should not be calling DLLCall(), so they should not need this function (unless they forget to call GDIPlus_Startup!); however, there are some 600 GDIPlus_* functions, so some may write functions that are not yet in GDIPlus.au3. For them, this function may be useful. So perhaps it should be added to GDIPlus.au3.

The tool is my cDebug. I have used it a lot to report structures and nested arrays.


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam

UEZ,

It just occurred to me to mention that types 6 (signed byte) and 8 (signed short) were in the original EXIF standard, but, as far as I can figure out, were never used and have been removed from the current standard.

For the list of types per M$, see https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam
Posted (edited)

UEZ,

A word of warning: when I incorporate calls to my cGDI* functions into my DeskewaPic function (which is based on the one you provided months back), AutoIt crashes. I am yet to find out why, despite considerable effort. I have never seen examples for my cGDI* functions crash AutoIt. My script does not crash when cGDI* functions are not called.

I do remember that you posted making (I think) the buffer static. As I have time, I will put some more effort in that direction.

For my DeskewaPic function, I need to copy all property items from the skewed picture to the de-skewed picture, and update 3 property items: DateTIme (ox132), ExifImageWidth (0xA002) and ExifImageHeight (0xa003).

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


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

@c.haslam I checked out shortly what you did I like your approach.

Let me dig in a little bit more...

 

Thanks so far for your contribution to GDI+. :thumbsup:

Edited by UEZ

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
UEZ
Posted (edited)

What I did so far:

#include <GDIPlus.au3>
#include <Array.au3>
#include <WinAPIDiag.au3>

;--------- should be moved to GDIPlusConstants.au3
Global Const $GDIP_PROPERTYTAGTYPEBYTE = 1, $GDIP_PROPERTYTAGTYPEASCII = 2, $GDIP_PROPERTYTAGTYPESHORT = 3, _
             $GDIP_PROPERTYTAGTYPELONG = 4, $GDIP_PROPERTYTAGTYPERATIONAL = 5, $GDIP_PROPERTYTAGTYPEUNDEFINED = 7, _
             $GDIP_PROPERTYTAGTYPESLONG = 9, $GDIP_PROPERTYTAGTYPESRATIONAL = 10
;-------------------------------------------------

Global $aPropID

Example()


Func Example()
    Local $sImagefile = FileOpenDialog("Select a JPG image file", "", "JPG Image (*.jpg;*.jpeg)")
    If @error Then Exit
    _GDIPlus_Startup()
    Local $hImage = _GDIPlus_ImageLoadFromFile($sImagefile)
    $aPropID = _GDIPlus_ImageGetPropertyIdList($hImage)
    Local $a2PropertyItems = _GDIPlus_ImageGetAllPropertyItems($hImage)
    DisplayPropertyItems($a2PropertyItems)

    Local $hImageClone = _GDIPlus_ImageClone($hImage) ; copy image without property items

    Local $a1[4]
    For $i = 0 To UBound($a2PropertyItems, 1) - 1 ; set all property items
        For $j = 0 To 3
            $a1[$j] = $a2PropertyItems[$i][$j]
        Next
        _GDIPlus_ImageSetPropertyItem($hImageClone, $a1)
    Next

    ; update a property item
    Local $a1value = ['Your name']
    Local $a1 = [0x13B, 20, 2, $a1value] ; Artist
    _GDIPlus_ImageSetPropertyItem($hImageClone, $a1)

    ; add a property item
    Local $a1value = [2000]
    Local $a1 = [0xa002, -1, 4, $a1value] ; ExifWidth
    _GDIPlus_ImageSetPropertyItem($hImageClone, $a1)

    Local $a1value = [0xFFFE01]
    Local $a1 = [0x927C, 3, 7, $a1value] ; MakerNote
    _GDIPlus_ImageSetPropertyItem($hImageClone, $a1)

    $a2PropertyItems = _GDIPlus_ImageGetAllPropertyItems($hImageClone)
    DisplayPropertyItems($a2PropertyItems)

    $a1 = _GDIPlus_ImageGetPropertyItemEx($hImageClone, 0x927c) ;https://msdn.microsoft.com/en-us/library/ms534417.aspx
    Local $a2[1][4]
    For $i = 0 To 3
        $a2[0][$i] = $a1[$i]
    Next
    DisplayPropertyItems($a2)

    _GDIPlus_Shutdown()
EndFunc   ;==>Example

Func DisplayPropertyItems($a2PropertyItems)
    ; Collapse values arrays so _ArrayDisplay can display them
    Local $a2 = $a2PropertyItems, $iPos
    ReDim $a2[UBound($a2PropertyItems)][5]

    For $i = 0 To UBound($a2, 1) - 1
        $a2[$i][0] = '0x' & Hex($a2PropertyItems[$i][0], 4)
        $a2[$i][3] = ''
        For $j = 0 To UBound($a2PropertyItems[$i][3]) - 1
            $a2[$i][3] &= ($a2PropertyItems[$i][3])[$j] & '|'
        Next
        $a2[$i][3] = StringTrimRight($a2[$i][3], 1)
        $iPos = _ArraySearch($aPropID, $a2[$i][0])
        If $iPos > -1 Then $a2[$i][4] = $aPropID[$iPos][1]
    Next
    _ArrayDisplay($a2, "Image Property Items", Default, 0, Default, "Identifier|Size|Type|Value|Description")
EndFunc   ;==>DisplayPropertyItems

; #FUNCTION# ====================================================================================================================
; Name ..........: _GDIPlus_ImageGetAllPropertyItems
; Description ...: Gets all property item (piece of meta data) from an Image object
; Syntax ........: _GDIPlus_ImageGetAllPropertyItems($hImage)
; Parameters ....: $hImage              - Pointer to an image object
; Return values .: Success: Array in which each row contains these columns:
;                      [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
;                  Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*).
; Author ........: c.haslam
; Modified ......:
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......: _GDIPlus_ImageGetPropertyItemEx, _GDIPlus_ImageGetPropertyIdList, _GDIPlus_ImageSetPropertyItem
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/ms534416.aspx#_gdiplus_constant_propertytaggpsver
; Example .......: Yes
; ===============================================================================================================================
Func _GDIPlus_ImageGetAllPropertyItems($hImage)
    Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetPropertySize", "handle", $hImage, "uint*", 0, "uint*", 0)
    If @error Then Return SetError(@error + 10, @extended, -1)
    If $aResult[0] Then Return SetError(20, $aResult[0], -1)
    
    Local $iTotalBufferSize = $aResult[2]
    Local $iNumProperties = $aResult[3]
    Local $tBuffer = DllStructCreate("byte[" & $iTotalBufferSize & "]")
    Local $pBuffer = DllStructGetPtr($tBuffer)

    $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetAllPropertyItems", "handle", $hImage, _
            "uint", $iTotalBufferSize, "uint", $iNumProperties, "ptr", $pBuffer)
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], -1)

    Local $aPropertyItems[$iNumProperties][4]
    Local $a1
    Local $tPropertyItem = DllStructCreate("int id; int length; short type; ptr value;")

    For $iI = 0 To $iNumProperties - 1
        $a1 = __GDIPlus_ImageGetPropertyItemValues($pBuffer)
        For $j = 0 To 3
            $aPropertyItems[$iI][$j] = $a1[$j]
        Next
        $pBuffer += DllStructGetSize($tPropertyItem)
    Next

    Return $aPropertyItems
EndFunc   ;==>_GDIPlus_ImageGetAllPropertyItems

; #FUNCTION# ====================================================================================================================
; Name ..........: _GDIPlus_ImageGetPropertyItemEx
; Description ...: Gets a specified property item (piece of meta data) from an Image object
; Syntax ........: _GDIPlus_ImageGetPropertyItemEx($hImage, $iPropID)
; Parameters ....: $hImage              - Pointer to an image object
;                  $iPropID             - Identifier of the property item to be retrieved
; Return values .: Success: Array containing the values of the property item
;                      [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
;                  Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*).
; Author ........: Eukalyptus
; Modified ......: c.haslam
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......: _GDIPlus_ImageGetPropertyIdList, _GDIPlus_ImageSetPropertyItem
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/ms534416.aspx#_gdiplus_constant_propertytaggpsver
; Example .......: Yes
; ===============================================================================================================================
Func _GDIPlus_ImageGetPropertyItemEx($hImage, $iPropID)
    Local $iSize = __GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
    If @error Then Return SetError(@error + 10, @extended, False)

    Local $tBuffer = DllStructCreate("byte[" & $iSize & "];")
    Local $pBuffer = DllStructGetPtr($tBuffer)
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetPropertyItem", "handle", $hImage, "uint", _
            $iPropID, "uint", $iSize, "struct*", $tBuffer)
    If @error Then Return SetError(@error, @extended, False)
    If $aResult[0] Then Return SetError(10, $aResult[0], False)

    Return __GDIPlus_ImageGetPropertyItemValues($pBuffer)
EndFunc   ;==>_GDIPlus_ImageGetPropertyItemEx

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name ..........: __GDIPlus_ImageGetPropertyItemValues($pBuffer)
; Description ...: Converts a project item from structured to equivalent nested arrays
; Syntax ........: __GDIPlus_ImageGetPropertyItemValues($pBuffer)
; Parameters ....: $bBuffer             - Pointer to start of Property Item sructure
; Return values .:     [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
; Author ........: c.haslam
; Modified ......: UEZ
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsigned rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func __GDIPlus_ImageGetPropertyItemValues($pBuffer)
    Local $tPropertyItem = DllStructCreate("int id; int length; short type; ptr value;", $pBuffer)
    Local $iBytes = DllStructGetData($tPropertyItem, "length")
    Local $pValue = DllStructGetData($tPropertyItem, "value")

    Local $aRet[4]
    Local $type = DllStructGetData($tPropertyItem, 'type')
    Local $tValues, $iValues

    Switch $type
        Case $GDIP_PROPERTYTAGTYPEASCII ;ASCII String
            $iValues = 1
            $tValues = DllStructCreate("char[" & $iBytes & "];", $pValue)
        Case $GDIP_PROPERTYTAGTYPESHORT ;Array of UShort
            $iValues = Int($iBytes / 2)
            $tValues = DllStructCreate("ushort[" & $iValues & "];", $pValue)
        Case $GDIP_PROPERTYTAGTYPELONG, $GDIP_PROPERTYTAGTYPERATIONAL ;Array of UInt / Fraction
            $iValues = Int($iBytes / 4)
            $tValues = DllStructCreate("uint[" & $iValues & "];", $pValue)
        Case $GDIP_PROPERTYTAGTYPESLONG, $GDIP_PROPERTYTAGTYPESRATIONAL ;Array of Int / Fraction
            $iValues = Int($iBytes / 4)
            $tValues = DllStructCreate("int[" & $iValues & "];", $pValue)
        Case Else ;Array of Bytes
            $iValues = 1
            $tValues = DllStructCreate("byte[" & $iBytes & "];", $pValue)
    EndSwitch
    $aRet[0] = DllStructGetData($tPropertyItem, 'id')
    $aRet[1] = $iBytes
    $aRet[2] = $type
    Local $a1values[$iValues]
    If $type = $GDIP_PROPERTYTAGTYPEASCII Or $type = $GDIP_PROPERTYTAGTYPEUNDEFINED Then ; ASCII string or undefined
        $a1values[0] = DllStructGetData($tValues, 1)
    Else
        For $i = 0 To $iValues - 1
            $a1values[$i] = DllStructGetData($tValues, 1, $i + 1)
        Next
    EndIf
    $aRet[3] = $a1values
    Return $aRet
EndFunc   ;==>__GDIPlus_ImageGetPropertyItemValues

; #FUNCTION# ====================================================================================================================
; Name ..........: _GDIPlus_ImageSetPropertyItem
; Description ...: Sets a specified property item (piece of meta data) for an Image object
; Syntax ........: _GDIPlus_ImageGetPropertyItemEx($hImage, $a1PropertyItem)
; Parameters ....: $hImage              - Pointer to an image object
;                  $a1PropertyItem      - Array containing the values of the property item
;                      [0] - identifier
;                      [1] - size,of the value array
;                               positive: in bytes
;                               negative: for numeric types: in number of values
;                      [2] - type of value(s) in the value array
;                      [3] - value array
; Return values .: Success: True and @error = 0
;                  Failure: sets the @error flag to non-zero
;                  +   >0: DllCall failed. @extended contains GPSTATUS error code ($GPID_ERR*).
;                  +   -1: size cannot be negative for ASCII string and undefined types
; Author ........: Eukalyptus
; Modified ......: c.haslam, UEZ
; Remarks .......: If size parameter is negative, calculates size in bytes from type.
;                  Convenient when setting a few property items
;                  +
;                  types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, undefined = 7, signed long = 9, signed rational = 10
; Related .......: _GDIPlus_ImageGetPropertyIdList, _GDIPlus_ImageGetPropertyItemEx
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx
; Example .......: Yes
; ===============================================================================================================================
Func _GDIPlus_ImageSetPropertyItem($hImage, $a1PropertyItem)
    Local $iId = $a1PropertyItem[0]
    Local $iLength = $a1PropertyItem[1]
    Local $iType = $a1PropertyItem[2]
    Local $a1values = $a1PropertyItem[3]

    Local $iBytes, $iqValues
    If $iLength > 0 Then ; useful when copying all property items
        $iBytes = $iLength
        Switch $iType
            Case $GDIP_PROPERTYTAGTYPEASCII ;ASCII String
                $iqValues = 1
            Case $GDIP_PROPERTYTAGTYPESHORT ;Array of UShort
                $iqValues = Int($iLength / 2)
            Case $GDIP_PROPERTYTAGTYPELONG, $GDIP_PROPERTYTAGTYPERATIONAL, $GDIP_PROPERTYTAGTYPESLONG, $GDIP_PROPERTYTAGTYPESRATIONAL ;Array of UInt / Fraction
                $iqValues = Int($iLength / 4)
            Case Else ; Array of Bytes, undefined
                $iqValues = 1
        EndSwitch
    ElseIf $iLength < 0 Then ; convenient when setting a few property items
        Switch $iType
            Case $GDIP_PROPERTYTAGTYPEASCII, $GDIP_PROPERTYTAGTYPEUNDEFINED ;ASCII String, undefined
                Return SetError(-1)
            Case $GDIP_PROPERTYTAGTYPESHORT ;Array of UShort
                $iBytes = -$iLength * 2
            Case $GDIP_PROPERTYTAGTYPELONG, $GDIP_PROPERTYTAGTYPERATIONAL, $GDIP_PROPERTYTAGTYPESLONG, $GDIP_PROPERTYTAGTYPESRATIONAL ;Array of UInt / Fraction
                $iBytes = -$iLength * 4
            Case Else ;Array of Bytes
                $iqValues = 1
                $iBytes = -$iLength
        EndSwitch
        $iqValues = -$iLength
    EndIf

    Local $tPropItem = DllStructCreate("int id; int length; short type; ptr pValue;")
    DllStructSetData($tPropItem, 'id', $iId)
    DllStructSetData($tPropItem, 'length', $iBytes)
    DllStructSetData($tPropItem, 'type', $iType)

    Local $tValues

    Switch $iType
        Case $GDIP_PROPERTYTAGTYPEASCII ;ASCII String
            $tValues = DllStructCreate("char[" & $iBytes & "];")
        Case $GDIP_PROPERTYTAGTYPESHORT ;Array of UShort
            $tValues = DllStructCreate("ushort[" & $iqValues & "];")
        Case $GDIP_PROPERTYTAGTYPELONG, $GDIP_PROPERTYTAGTYPERATIONAL ;Array of UInt / Fraction
            $tValues = DllStructCreate("uint[" & $iqValues & "];")
        Case $GDIP_PROPERTYTAGTYPESLONG, $GDIP_PROPERTYTAGTYPESRATIONAL ;Array of Int / Fraction
            $tValues = DllStructCreate("int[" & $iqValues & "];")
        Case Else ;Array of Bytes
            $tValues = DllStructCreate("byte[" & $iBytes & "];")
    EndSwitch
    If $iType = $GDIP_PROPERTYTAGTYPEASCII Or $iType = $GDIP_PROPERTYTAGTYPEUNDEFINED Then ; ASCII string or undefined
        DllStructSetData($tValues, 1, $a1values[0])
    Else
        For $i = 0 To $iqValues - 1
            DllStructSetData($tValues, 1, $a1values[$i], $i + 1)
        Next
    EndIf
    DllStructSetData($tPropItem, 'pValue', DllStructGetPtr($tValues))

    Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipSetPropertyItem", "handle", $hImage, "struct*", $tPropItem)
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], -1)
    Return True
EndFunc   ;==>_GDIPlus_ImageSetPropertyItem

 

Any suggestion?

Edited by UEZ
added JPM's suggestions
  • 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
jpm
Posted (edited)

error checking is not perfect

can those functions replace the current UDF standard without script breaking

#AutoIt3Wrapper_UseX64=n
#include <GDIPlus.au3>
#include <Array.au3>
#include <WinAPIDiag.au3>


;--------- should be moved to GDIPlusConstants.au3
Global Const $GDIP_PROPERTYTAGTYPEBYTE = 1, $GDIP_PROPERTYTAGTYPEASCII = 2, $GDIP_PROPERTYTAGTYPESHORT = 3, $GDIP_PROPERTYTAGTYPELONG = 4, _
  $GDIP_PROPERTYTAGTYPERATIONAL = 5, $GDIP_PROPERTYTAGTYPEUNDEFINED = 7, $GDIP_PROPERTYTAGTYPESLONG = 9, _
  $GDIP_PROPERTYTAGTYPESRATIONAL = 10
;-------------------------------------------------

Global $aPropID

Example()


Func Example()
 Local $sImagefile = FileOpenDialog("Select a JPG image file", "", "JPG Image (*.jpg;*.jpeg)")
 If @error Then Exit
 _GDIPlus_Startup()
 Local $hImage = _GDIPlus_ImageLoadFromFile($sImagefile)
 $aPropID = _GDIPlus_ImageGetPropertyIdList($hImage)
 Local $a2PropertyItems = cGDIPlus_ImageGetAllPropertyItems($hImage)
 DisplayPropertyItems($a2PropertyItems)

 Local $hImageClone = _GDIPlus_ImageClone($hImage) ; copy image without property items

 Local $a1[4]
 For $i = 0 To UBound($a2PropertyItems, 1) - 1 ; set all property items
  For $j = 0 To 3
   $a1[$j] = $a2PropertyItems[$i][$j]
  Next
  cGDIPlus_ImageSetPropertyItem($hImageClone, $a1)
 Next

 ; update a property item
 Local $a1value = ['Your name']
 Local $a1 = [0x13B, 20, 2, $a1value] ; Artist
 cGDIPlus_ImageSetPropertyItem($hImageClone, $a1)

 ; add a property item
 Local $a1value = [2000]
 Local $a1 = [0xa002, -1, 4, $a1value] ; ExifWidth
 cGDIPlus_ImageSetPropertyItem($hImageClone, $a1)

 Local $a1value = [0xFFFE01]
 Local $a1 = [0x927C, 3, 7, $a1value] ; MakerNote
 cGDIPlus_ImageSetPropertyItem($hImageClone, $a1)

 $a2PropertyItems = cGDIPlus_ImageGetAllPropertyItems($hImageClone)
 DisplayPropertyItems($a2PropertyItems)

 $a1 = cGDIPlus_ImageGetPropertyItem($hImageClone, 0x927c) ;https://msdn.microsoft.com/en-us/library/ms534417.aspx
 Local $a2[1][4]
 For $i = 0 To 3
  $a2[0][$i] = $a1[$i]
 Next
 DisplayPropertyItems($a2)

 _GDIPlus_Shutdown()
EndFunc   ;==>Example

Func DisplayPropertyItems($a2PropertyItems)
 ; Collapse values arrays so _ArrayDisplay can display them
 Local $a2 = $a2PropertyItems, $iPos
 ReDim $a2[UBound($a2PropertyItems)][5]

 For $i = 0 To UBound($a2, 1) - 1
  $a2[$i][0] = '0x' & Hex($a2PropertyItems[$i][0], 4)
  $a2[$i][3] = ''
  For $j = 0 To UBound($a2PropertyItems[$i][3]) - 1
   $a2[$i][3] &= ($a2PropertyItems[$i][3])[$j] & '|'
  Next
  $a2[$i][3] = StringTrimRight($a2[$i][3], 1)
  $iPos = _ArraySearch($aPropID, $a2[$i][0])
  If $iPos > -1 Then $a2[$i][4] = $aPropID[$iPos][1]
 Next
 _ArrayDisplay($a2, "Image Property Items", Default, 0, Default, "Identifier|Size|Type|Value|Description")
EndFunc   ;==>DisplayPropertyItems

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ImageGetAllPropertyItems
; Description ...: Gets all property item (piece of meta data) from an Image object
; Syntax ........: cGDIPlus_ImageGetAllPropertyItems($hImage)
; Parameters ....: $hImage              - Pointer to an image object
; Return values .: Success: Array in which each row contains these columns:
;                      [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
;                  Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*).
; Author ........: c.haslam
; Modified ......:
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......: cGDIPlus_ImageGetPropertyItem, _GDIPlus_ImageGetPropertyIdList, cGDIPlus_ImageSetPropertyItem
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/ms534416.aspx#_gdiplus_constant_propertytaggpsver
; Example .......: Yes
; ===============================================================================================================================

Func cGDIPlus_ImageGetAllPropertyItems($hImage)
 Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetPropertySize", "handle", $hImage, "uint*", 0, "uint*", 0)
 Local $iTotalBufferSize = $aResult[2]
 Local $iNumProperties = $aResult[3]
 If @error Then Return SetError(@error + 10, @extended, -1)
 If $aResult[0] Then Return SetError(20, $aResult[0], -1)

 Local $tBuffer = DllStructCreate("byte[" & $iTotalBufferSize & "]")
 Local $pBuffer = DllStructGetPtr($tBuffer)

 $aResult = DllCall($__g_hGDIPDll, "uint", "GdipGetAllPropertyItems", "handle", $hImage, _
   "uint", $iTotalBufferSize, "uint", $iNumProperties, "ptr", $pBuffer)
 If @error Then Return SetError(@error, @extended, -1)
 If $aResult[0] Then Return SetError(10, $aResult[0], -1)

 Local $aPropertyItems[$iNumProperties][4]
 Local $a1
 Local $tPropertyItem = DllStructCreate("int id; int length; short type; ptr value;")

 For $iI = 0 To $iNumProperties - 1
  $a1 = __GDIPlus_ImageGetPropertyItemValues($pBuffer)
  For $j = 0 To 3
   $aPropertyItems[$iI][$j] = $a1[$j]
  Next
  $pBuffer += DllStructGetSize($tPropertyItem)
 Next

 Return $aPropertyItems
EndFunc   ;==>cGDIPlus_ImageGetAllPropertyItems

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ImageGetPropertyItem
; Description ...: Gets a specified property item (piece of meta data) from an Image object
; Syntax ........: cGDIPlus_ImageGetPropertyItem($hImage, $iPropID)
; Parameters ....: $hImage              - Pointer to an image object
;                  $iPropID             - Identifier of the property item to be retrieved
; Return values .: Success: Array containing the values of the property item
;                      [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
;                  Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*).
; Author ........: Eukalyptus
; Modified ......: c.haslam
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......: _GDIPlus_ImageGetPropertyIdList, cGDIPlus_ImageSetPropertyItem
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/ms534416.aspx#_gdiplus_constant_propertytaggpsver
; Example .......: Yes
; ===============================================================================================================================
Func cGDIPlus_ImageGetPropertyItem($hImage, $iPropID)
 Local $iSize = __GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
 If @error Then Return SetError(@error + 10, @extended, False)

 Local $tBuffer = DllStructCreate("byte[" & $iSize & "];")
 Local $pBuffer = DllStructGetPtr($tBuffer)
 Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetPropertyItem", "handle", $hImage, "uint", _
   $iPropID, "uint", $iSize, "struct*", $tBuffer)
 If @error Then Return SetError(@error, @extended, False)
 If $aResult[0] Then Return SetError(10, $aResult[0], False)

 Return __GDIPlus_ImageGetPropertyItemValues($pBuffer)
EndFunc   ;==>cGDIPlus_ImageGetPropertyItem

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Name ..........: __GDIPlus_ImageGetPropertyItemValues($pBuffer)
; Description ...: Converts a project item from structured to equivalent nested arrays
; Syntax ........: __GDIPlus_ImageGetPropertyItemValues($pBuffer)
; Parameters ....: $bBuffer             - Pointer to start of Property Item sructure
; Return values .:     [0] - identifier
;                      [1] - size, in bytes, of the value array
;                      [2] - type of value(s) in the value array
;                      [3] - value array
; Author ........: c.haslam
; Modified ......: UEZ
; Remarks .......: types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsigned rational = 5, signed byte = 6, undefined = 7, signed long = 9,
;                         signed rational = 10
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================

Func __GDIPlus_ImageGetPropertyItemValues($pBuffer)
 Local $tPropertyItem = DllStructCreate("int id; int length; short type; ptr value;", $pBuffer)
 Local $iBytes = DllStructGetData($tPropertyItem, "length")
 Local $pValue = DllStructGetData($tPropertyItem, "value")

 Local $aRet[4]
 Local $type = DllStructGetData($tPropertyItem, 'type')
 Local $tValues, $iValues

 Switch $type
  Case $GDIP_PROPERTYTAGTYPEASCII ;ASCII String
   $iValues = 1
   $tValues = DllStructCreate("char[" & $iBytes & "];", $pValue)
  Case $GDIP_PROPERTYTAGTYPESHORT ;Array of UShort
   $iValues = Int($iBytes / 2)
   $tValues = DllStructCreate("ushort[" & $iValues & "];", $pValue)
  Case $GDIP_PROPERTYTAGTYPELONG, $GDIP_PROPERTYTAGTYPERATIONAL ;Array of UInt / Fraction
   $iValues = Int($iBytes / 4)
   $tValues = DllStructCreate("uint[" & $iValues & "];", $pValue)
  Case $GDIP_PROPERTYTAGTYPESLONG, $GDIP_PROPERTYTAGTYPESRATIONAL ;Array of Int / Fraction
   $iValues = Int($iBytes / 4)
   $tValues = DllStructCreate("int[" & $iValues & "];", $pValue)
  Case Else ;Array of Bytes
   $iValues = 1
   $tValues = DllStructCreate("byte[" & $iBytes & "];", $pValue)
 EndSwitch
 $aRet[0] = DllStructGetData($tPropertyItem, 'id')
 $aRet[1] = $iBytes
 $aRet[2] = $type
 Local $a1values[$iValues]
 If $type = $GDIP_PROPERTYTAGTYPEASCII Or $type = $GDIP_PROPERTYTAGTYPEUNDEFINED Then ; ASCII string or undefined
  $a1values[0] = DllStructGetData($tValues, 1)
 Else
  For $i = 0 To $iValues - 1
   $a1values[$i] = DllStructGetData($tValues, 1, $i + 1)
  Next
 EndIf
 $aRet[3] = $a1values
 Return $aRet
EndFunc   ;==>__GDIPlus_ImageGetPropertyItemValues

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ImageSetPropertyItem
; Description ...: Sets a specified property item (piece of meta data) for an Image object
; Syntax ........: cGDIPlus_ImageGetPropertyItem($hImage, $a1PropertyItem)
; Parameters ....: $hImage              - Pointer to an image object
;                  $a1PropertyItem      - Array containing the values of the property item
;                      [0] - identifier
;                      [1] - size,of the value array
;                               positive: in bytes
;                               negative: for numeric types: in number of values
;                      [2] - type of value(s) in the value array
;                      [3] - value array
; Return values .: Success: True and @error = 0
;                  Failure: sets the @error flag to non-zero
;                  +   >0: DllCall failed. @extended contains GPSTATUS error code ($GPID_ERR*).
;                  +   -1: size cannot be negative for ASCII string and undefined types
; Author ........: Eukalyptus
; Modified ......: c.haslam, UEZ
; Remarks .......: If size parameter is negative, calculates size in bytes from type.
;                  Convenient when setting a few property items
;                  +
;                  types: unsigned byte = 1, ASCII string = 2, unsigned short = 3, unsigned long = 4,
;                         unsinged rational = 5, undefined = 7, signed long = 9, signed rational = 10
; Related .......: _GDIPlus_ImageGetPropertyIdList, cGDIPlus_ImageGetPropertyItem
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms535390(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534493(v=vs.85).aspx,
;                  https://msdn.microsoft.com/en-us/library/windows/desktop/ms534414(v=vs.85).aspx
; Example .......: Yes
; ===============================================================================================================================
Func cGDIPlus_ImageSetPropertyItem($hImage, $a1PropertyItem)
 Local $iId = $a1PropertyItem[0]
 Local $iLength = $a1PropertyItem[1]
 Local $iType = $a1PropertyItem[2]
 Local $a1values = $a1PropertyItem[3]

 Local $iBytes, $iqValues
 If $iLength > 0 Then ; useful when copying all property items
  $iBytes = $iLength
  Switch $iType
   Case $GDIP_PROPERTYTAGTYPEASCII ;ASCII String
    $iqValues = 1
   Case $GDIP_PROPERTYTAGTYPESHORT ;Array of UShort
    $iqValues = Int($iLength / 2)
   Case $GDIP_PROPERTYTAGTYPELONG, $GDIP_PROPERTYTAGTYPERATIONAL, $GDIP_PROPERTYTAGTYPESLONG, $GDIP_PROPERTYTAGTYPESRATIONAL ;Array of UInt / Fraction
    $iqValues = Int($iLength / 4)
   Case Else ; Array of Bytes, undefined
    $iqValues = 1
  EndSwitch
 ElseIf $iLength < 0 Then ; convenient when setting a few property items
  Switch $iType
   Case $GDIP_PROPERTYTAGTYPEASCII, $GDIP_PROPERTYTAGTYPEUNDEFINED ;ASCII String, undefined
    Return SetError(-1)
   Case $GDIP_PROPERTYTAGTYPESHORT ;Array of UShort
    $iBytes = -$iLength * 2
   Case $GDIP_PROPERTYTAGTYPELONG, $GDIP_PROPERTYTAGTYPERATIONAL, $GDIP_PROPERTYTAGTYPESLONG, $GDIP_PROPERTYTAGTYPESRATIONAL ;Array of UInt / Fraction
    $iBytes = -$iLength * 4
   Case Else ;Array of Bytes
    $iqValues = 1
    $iBytes = -$iLength
  EndSwitch
  $iqValues = -$iLength
 EndIf

 Local $tPropItem = DllStructCreate("int id; int length; short type; ptr pValue;")
 DllStructSetData($tPropItem, 'id', $iId)
 DllStructSetData($tPropItem, 'length', $iBytes)
 DllStructSetData($tPropItem, 'type', $iType)

 Local $tValues

 Switch $iType
  Case $GDIP_PROPERTYTAGTYPEASCII ;ASCII String
   $tValues = DllStructCreate("char[" & $iBytes & "];")
  Case $GDIP_PROPERTYTAGTYPESHORT ;Array of UShort
   $tValues = DllStructCreate("ushort[" & $iqValues & "];")
  Case $GDIP_PROPERTYTAGTYPELONG, $GDIP_PROPERTYTAGTYPERATIONAL ;Array of UInt / Fraction
   $tValues = DllStructCreate("uint[" & $iqValues & "];")
  Case $GDIP_PROPERTYTAGTYPESLONG, $GDIP_PROPERTYTAGTYPESRATIONAL ;Array of Int / Fraction
   $tValues = DllStructCreate("int[" & $iqValues & "];")
  Case Else ;Array of Bytes
   $tValues = DllStructCreate("byte[" & $iBytes & "];")
 EndSwitch
 If $iType = $GDIP_PROPERTYTAGTYPEASCII Or $iType = $GDIP_PROPERTYTAGTYPEUNDEFINED Then ; ASCII string or undefined
  DllStructSetData($tValues, 1, $a1values[0])
 Else
  For $i = 0 To $iqValues - 1
   DllStructSetData($tValues, 1, $a1values[$i], $i + 1)
  Next
 EndIf
 DllStructSetData($tPropItem, 'pValue', DllStructGetPtr($tValues))

 Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipSetPropertyItem", "handle", $hImage, "struct*", $tPropItem)
 If @error Then Return SetError(@error, @extended, -1)
 If $aResult[0] Then Return SetError(10, $aResult[0], -1)
 Return True
EndFunc   ;==>cGDIPlus_ImageSetPropertyItem

 

Edited by Melba23
Code tags and not quote

Share this post


Link to post
Share on other sites
jpm

for non script Breaking the best can be cGDIPlus_ImageGetPropertyItem -> _GDIPlus_ImageGetPropertyItemEX

for the other cGDI* _GDI* as they are new

Share this post


Link to post
Share on other sites
UEZ

thanks @jpm. I updated the code above accordingly.


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
c.haslam

Would you like me to add more error checking, or will UEZ do it?


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
UEZ

Is there any need to more error checks?


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
c.haslam

I see no need for more error checks.


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
c.haslam
Posted (edited)

For many _GDI* functions as they are now (including mine and my revisions of functions written by others), the Help says

Failure: Sets the @error flag to non-zero, @extended may contain GPSTATUS error code ($GPID_ERR*).

This does not say where to find the $GPID_ERR* constants.

IMHO it should be possible to use any of the _GDI functions without needing to look at GDIPlus.au3 or GDIPlusConstants.au3: the Help should be sufficient.

So I suggest that a function be added for which the Help might be:

; #FUNCTION# ====================================================================================================================
; Name ..........: cGDIPlus_ReportIfErroIFromCall
; Description ...: Checks for errors in calling any other GDIPlus function
; Syntax ........: cGDIPlus_ReportIfErroFromCall($iError, $iStatus, $sFuncName)
; Parameters ....: $iError             - @error returned by a _GDIPlus* function
;                  $iExtended          - @extended returned by a _GDIPlus* function
;                  $sFuncName          - name of _GDIPlus* function
; Return values .: None
; Author ........: c.haslam
; Modified ......:
; Renmarks ......: Useful for diagnosing errors in calling _GDIPlus functions
;                  If _GDIPlus* function set neither @error nor @extended, this function does nothing, so can be left ion your debugged script
; Related .......: all other _GDIPlus_* functions
; Link ..........: https://msdn.microsoft.com/en-us/library/windows/desktop/ms534175(v=vs.85).aspx
; Example .......: Yes
; ===============================================================================================================================

The Help for many other functions might then say something like:

Failure: Sets @error flag to non-zero. @extended may contain additional information. Call cGDIPlus_ReportIFErrorFrom Call() for details.

I have a draft of cGDIPlus_ReportIFErroFromCall(), but I need to look at the error reporting in all the GDIPlus* functions before suggesting what the code should be. It would avoid the user having to look in GDIPlusConstants.au3 for the error code.

I do now recognize that the Help for cGDIPlus_ImageGetAllProperties() does not mention the error code returned when the user forgets to call GDIPLus_Startup(). Indeed, I need to do some more thinking about what to set @extended to (and may be @error) when there are 2 DLLCalls in a GDIPlus* function, as is the case with cGDIPlus_ImageGetAllProperties(). It needs to be consistent with already existing GDIPlus* functions.

 

Edited by c.haslam

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Share this post


Link to post
Share on other sites
jpm

why not to mention ($GPID_ERR* defined in GDIPLusConstants.au3) certainly other GPIPlus UDF must be updated too.

in other standard UDF when the error code is completly defined the related *Constants.au3 is only mention when it is not included by the .au3 which define the function

Share this post


Link to post
Share on other sites
c.haslam

True: other standard UDFs do only mention the related *Constants.au3 when it is not included by the .au3; however, the user can be helped further by including a function such as I am suggesting. In working on an application script I have found an error-reporting function to save a chunk of development time.

It is up to the developers to decide whether GDIPlus,au3 goes beyond what has been done for other standard UDFs.

 


Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

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

  • Similar Content

    • Valiante
      By Valiante
      I'm creating a tool which automatically saves screenshots.  I've found that some images appear corrupt after saving.  I've narrowed the source down to screenshots taken from within an RDP session via the Ctrl+Alt+Plus (PrtScn equivalent) and Ctrl+Alt+Minus (Alt+PrtScn equivalent) key combos.
      Here is the example code:
      #include <ClipBoard.au3> #include <GDIPlus.au3> If _ClipBoard_IsFormatAvailable($CF_BITMAP) Then ConsoleWrite("+Bitmap found on Clipboard" & @CRLF) If Not _ClipBoard_Open(0) Then MsgBox(16, "Error", "_ClipBoard_Open failed") Exit EndIf $hClipboardImage = _ClipBoard_GetDataEx($CF_BITMAP) _ClipBoard_Close() _GDIPlus_Startup() $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hClipboardImage) $sCLSID = _GDIPlus_EncodersGetCLSID("JPG") _GDIPlus_ImageSaveToFileEx($hBitmap, @ScriptDir & "\" & TimerInit() & "_Clipboard_Image.jpg", $sCLSID, 0) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_Shutdown() Else MsgBox(48, @ScriptName, "No Bitmap found on Clipboard") EndIf If you copy a local window to the clipboard via Alt+PrtScn the above works fine.  If you copy a window in an RDP session via Ctrl+Alt+Minus it saves the image, but the left-hand edge appears to contain a few pixels sliced off the right-hand side of the bitmap (see two attached images for examples; one good, one bad).  If you paste directly into MSPaint, the image appears correctly, so the clipboard contents is good. It seems to be the process of converting the bitmap handle to an image file via GDIPlus which corrupts it (though I may be wrong about this).
      I've tried inspecting the contents of the clipboard via the _ClipBoard_EnumFormats example and I've noticed the clipboard from the RDP session contains a couple more formats;
      Local:
      Clipboard formats ..: 3 Clipboard format 1 .: Bitmap Clipboard format 2 .: DIB Clipboard format 3 .: DIB V5 RDP:
      Clipboard formats ..: 5 Clipboard format 1 .: DataObject Clipboard format 2 .: DIB Clipboard format 3 .: DIB V5 Clipboard format 4 .: Ole Private Data Clipboard format 5 .: Bitmap However the _ClipBoard_GetDataEx function is specifying the $CF_BITMAP constant for the format, which both instances contain, so I'm not sure the extra formats have any impact?
      I've tried using a combination of _ClipBoard_GetDataEx($CF_DIB) and _GDIPlus_BitmapCreateFromMemory in an effort to write the binary directly to a file, instead of using a bitmap handle, however this doesn't appear to work and just returns a zero and doesn't set @error to anything, which isn't covered in the help file (a failure should return a zero and set the @error level to something).
      I've hunted around the forums and tried everything I can think of. I can normally figure most things out without posting but I've been dipping in and out of this script for a few months now and have finally thrown in the towel and must ask you guys for help, which isn't a decision I take lightly.  Your help is, as always, greatly appreciated.


    • UEZ
      By UEZ
      Here another example to mark the desktop to get the marked region for capturing. This example is not perfect and not very fast (room for improvements).
      ;coded by UEZ build 2018-11-30 beta ;code cleanup up mLipok #include <APISysConstants.au3> #include <Array.au3> #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WinAPIGdi.au3> #include <WinAPISysWin.au3> #include <WindowsConstants.au3> Global $__g_hGUI_MarkArea, $__g_hGUI_Bg, $__g_iLabel_TL, $__g_iLabel_TM, $__g_iLabel_TR, $__g_iLabel_LM, $__g_iLabel_RM, $__g_iLabel_BL, $__g_iLabel_BM, _ $__g_iLabel_BR, $__g_iOldCursor, $__g_iW, $__g_iH, $__g_iColor_ResizeDots = 0xFFFFFF, $__g_iBorder = 4, $__g_bSelectionDone = False Global $aRect = _GDIPlus_MarkScreenRegionAnimated() _ArrayDisplay($aRect, "Marked area coordinates") Func _GDIPlus_MarkScreenRegionAnimated($bAnim = True) _GDIPlus_Startup() Local Const $hFullScreen = WinGetHandle("[TITLE:Program Manager;CLASS:Progman]") Local Const $aFullScreen = WinGetPos($hFullScreen) $__g_hGUI_Bg = GUICreate("", $aFullScreen[2], $aFullScreen[3], $aFullScreen[0], $aFullScreen[1], BitOR($WS_CLIPCHILDREN, $WS_POPUP), $WS_EX_TOPMOST) ;to avoid cursor flickering and for proper control read WinSetTrans($__g_hGUI_Bg, "", 0x01) $__g_hGUI_MarkArea = GUICreate("", 1, 1, -1, -1, $bAnim ? $WS_POPUP : BitOR($WS_POPUP, $WS_BORDER), BitOR($WS_EX_TOPMOST, $WS_EX_LAYERED), $__g_hGUI_Bg) GUISetBkColor(0xABCDEF, $__g_hGUI_MarkArea) If Not $bAnim Then $__g_iColor_ResizeDots = 0xFF0000 $__g_iLabel_TL = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top left GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_TM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_TR = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top right GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_LM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;left mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_RM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;right mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BL = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom left GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BR = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom right GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) GUISetState(@SW_SHOWNA, $__g_hGUI_Bg) GUISetState(@SW_SHOW, $__g_hGUI_MarkArea) $__g_iOldCursor = MouseGetCursor() GUISetCursor(3, 1, $__g_hGUI_Bg) GUISetCursor(3, 1, $__g_hGUI_MarkArea) _WinAPI_SetLayeredWindowAttributes($__g_hGUI_MarkArea, 0xABCDEF, 0xF0) Local $aMPos, $aPrevMPos[2] = [MouseGetPos(0) + 1, MouseGetPos(1) + 1], $iID, $aCI, $iX, $iY, $aOldWinPos, $aOldMPos, $bMoved Local $aGUIStartPos, $iKey_Exit = GUICtrlCreateButton("", $aFullScreen[0] - 10, $aFullScreen[1] - 10, 1, 1), $aAccelKeys[1][2] = [["{ENTER}", $iKey_Exit]] GUISetAccelerators($aAccelKeys, $__g_hGUI_Bg) GUISetAccelerators($aAccelKeys, $__g_hGUI_MarkArea) #forceref $bMoved Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $iKey_Exit If $bAnim Then GUIRegisterMsg($WM_TIMER, "") DllCall("user32.dll", "bool", "KillTimer", "hwnd", $__g_hGUI_MarkArea, "uint_ptr", $iID) GUIRegisterMsg($WM_ERASEBKGND, "") EndIf _GDIPlus_Shutdown() Local $aResult = WinGetPos($__g_hGUI_MarkArea) $aResult[2] = WinGetClientSize($__g_hGUI_MarkArea)[0] $aResult[3] = WinGetClientSize($__g_hGUI_MarkArea)[1] GUIDelete($__g_hGUI_MarkArea) GUIDelete($__g_hGUI_Bg) If Not $__g_bSelectionDone Then $aResult = 0 Return $aResult EndSwitch $aMPos = MouseGetPos() If ($aMPos[0] <> $aPrevMPos[0] Or $aMPos[1] <> $aPrevMPos[1]) And (Not $__g_bSelectionDone) Then WinMove($__g_hGUI_MarkArea, "", $aMPos[0], $aMPos[1]) $aPrevMPos = $aMPos EndIf $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) If $aCI[2] And (Not $__g_bSelectionDone) Then $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If $bAnim Then GUIRegisterMsg($WM_ERASEBKGND, "WM_ERASEBKGND") GUIRegisterMsg($WM_TIMER, "PlayBorderAnim") $iID = DllCall("User32.dll", "uint_ptr", "SetTimer", "hwnd", $__g_hGUI_MarkArea, "uint_ptr", 1, "uint", 50, "ptr", 0)[0] EndIf While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) $aMPos = MouseGetPos() $__g_iW = Abs($aMPos[0] - $aGUIStartPos[0]) + 1 $__g_iH = Abs($aMPos[1] - $aGUIStartPos[1]) + 1 If $aMPos[0] < $aGUIStartPos[0] Then $iX = $aMPos[0] Else $iX = $aGUIStartPos[0] EndIf If $aMPos[1] < $aGUIStartPos[1] Then $iY = $aMPos[1] Else $iY = $aGUIStartPos[1] EndIf WinMove($__g_hGUI_MarkArea, "", $iX, $iY, $__g_iW, $__g_iH) UpdateCtrlPos($bAnim) WEnd $__g_bSelectionDone = True GUISetCursor(3, 1, $__g_hGUI_MarkArea) ElseIf $aCI[3] And $__g_bSelectionDone Then $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If _WinAPI_PtInRectEx(MouseGetPos(0), MouseGetPos(1), $aGUIStartPos[0], $aGUIStartPos[1], $aGUIStartPos[0] + $aGUIStartPos[2], $aGUIStartPos[1] + $aGUIStartPos[3]) Then $aMPos = MouseGetPos() $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) While $aCI[3] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aGUIStartPos[0] - ($aMPos[0] - MouseGetPos(0)), $aGUIStartPos[1] - ($aMPos[1] - MouseGetPos(1)), $__g_iW, $__g_iH) GUISetCursor(0, 1, $__g_hGUI_Bg) GUISetCursor(0, 1, $__g_hGUI_MarkArea) WEnd GUISetCursor(3, 1, $__g_hGUI_Bg) GUISetCursor(3, 1, $__g_hGUI_MarkArea) EndIf EndIf If $__g_bSelectionDone Then $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) If @error Then ContinueLoop Switch $aCI[4] Case $__g_iLabel_TL GUISetCursor(12, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), MouseGetPos(1), $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BR GUISetCursor(12, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_TR GUISetCursor(10, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], MouseGetPos(1), $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BL GUISetCursor(10, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), $aOldWinPos[1], $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_LM GUISetCursor(13, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), $aOldWinPos[1], $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3]) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_RM GUISetCursor(13, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3]) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_TM GUISetCursor(11, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], MouseGetPos(1), $aOldWinPos[2], $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BM GUISetCursor(11, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2], $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case Else GUISetCursor(3, 1, $__g_hGUI_MarkArea) EndSwitch EndIf Until False EndFunc ;==>_GDIPlus_MarkScreenRegionAnimated Func UpdateCtrlPos($bAnim = True) Local Const $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If $__g_bSelectionDone And $bAnim Then GUIRegisterMsg($WM_TIMER, "") $__g_iW = $aGUIStartPos[2] $__g_iH = $aGUIStartPos[3] ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TL, 0, 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TM, ($__g_iW - $__g_iBorder) / 2, 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TR, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_LM, 0, ($__g_iH - $__g_iBorder) / 2, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_RM, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), ($__g_iH - $__g_iBorder) / 2, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BL, 0, ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BM, ($__g_iW - $__g_iBorder) / 2, ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BR, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) If $__g_bSelectionDone And $bAnim Then GUIRegisterMsg($WM_TIMER, "PlayBorderAnim") EndFunc ;==>UpdateCtrlPos Func PlayBorderAnim() Local $aWinPos = WinGetClientSize($__g_hGUI_MarkArea), $iW = $aWinPos[0], $iH = $aWinPos[1] Local Static $fOffset = 0 Local Const $iSize = $__g_iBorder / 2 Local Const $hDC = _WinAPI_GetDC($__g_hGUI_MarkArea) Local Const $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local Const $hDC_backbuffer = _WinAPI_CreateCompatibleDC($hDC) Local Const $DC_obj = _WinAPI_SelectObject($hDC_backbuffer, $hHBitmap) Local Const $hCanvas = _GDIPlus_GraphicsCreateFromHDC($hDC_backbuffer) Local Const $hPen = _GDIPlus_PenCreate(0xFF0178D7, $iSize), $hPen2 = _GDIPlus_PenCreate(0xFFFFFFFF, $iSize), _ $hBrush = _GDIPlus_BrushCreateSolid(0xFF000000 + $__g_iColor_ResizeDots), $hPen3 = _GDIPlus_PenCreate(0xFF000000) _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDASHDOT) _GDIPlus_GraphicsClear($hCanvas, 0xFFABCDEF) ;for faster performance direct dll calls DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen2, "float", 1 + $iSize, "float", 1 + $iSize, "float", $iW - 2 * $iSize - 2, "float", $iH - 2 * $iSize - 2) DllCall($__g_hGDIPDll, "int", "GdipSetPenDashOffset", "handle", $hPen, "float", $fOffset) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen, "float", 1 + $iSize, "float", 1 + $iSize, "float", $iW - 2 * $iSize - 2, "float", $iH - 2 * $iSize - 2) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) / 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) / 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) / 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) / 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hDC_backbuffer, 0, 0, $SRCCOPY) $fOffset += 0.5 _GDIPlus_GraphicsDispose($hCanvas) _WinAPI_SelectObject($hDC_backbuffer, $DC_obj) _WinAPI_DeleteDC($hDC_backbuffer) _WinAPI_DeleteObject($hHBitmap) _WinAPI_ReleaseDC($__g_hGUI_MarkArea, $hDC) _GDIPlus_PenDispose($hPen) _GDIPlus_PenDispose($hPen2) _GDIPlus_PenDispose($hPen3) _GDIPlus_BrushDispose($hBrush) EndFunc ;==>PlayBorderAnim Func WM_ERASEBKGND($hWnd, $iMsgm, $wParam, $lParam) ;suppress repainting to avoid flickering but causes some other side effects #forceref $iMsgm, $wParam, $lParam, $hWnd Local Const $hBrush = _WinAPI_CreateSolidBrush(0xEFCDAB) ;BGR format ;~ _WinAPI_RedrawWindow($__g_hGUI_MarkArea, 0, 0, BitOR($RDW_NOERASE, $RDW_NOCHILDREN, $RDW_NOFRAME, $RDW_VALIDATE)) _WinAPI_SetClassLongEx($__g_hGUI_MarkArea, $GCL_HBRBACKGROUND, $hBrush) _WinAPI_DeleteObject($hBrush) Return 0 EndFunc ;==>WM_ERASEBKGND  
      Just press the lmb and move your mouse. When lmb is released you can adjust the size of the window by dragging the white rectangle to any direction. Rmb will move the marked area.
      Press ESC to get the coordinates of the marked region.
      If you have any improvements, please post it here.
       
      Tested on Win10 x64 only.
       
    • badcoder123
      By badcoder123
      Hey, All!
       
      I was looking into the help file at all the drawing utilities and I was wondering if you draw a translucent line that follows your cursor. Upon looking for ideas I came across this thread (1.0) and saw UEZ's response. I also came across another post that UEZ replied to and found this reply (1.1) where he shows how you can draw on the desktop. This is what I'm looking for however I'd still like to be able to interact with a designated application and have the line/curve/vector passively follow it. Obviously we don't move our cursor very linearly so it would have to be able to draw on vectors. Am I over complicating this? 
      Any ideas or starting points I should look more into? 
       
       
       
      1.0
      #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Global Const $aFullScreen = WinGetPos(WinGetHandle("[TITLE:Program Manager;CLASS:Progman]")) Global $iHeight = 4 Global Const $hGUI = GUICreate("Screen Ruler Underline for free :-)", $aFullScreen[2], $iHeight, $aFullScreen[0], MouseGetPos(1), $WS_POPUP, BitOR($WS_EX_TOPMOST, $WS_EX_TRANSPARENT)) GUISetBkColor(0x000000) WinSetTrans($hGUI, "", 0xA0) GUISetState() HotKeySet("{ESC}", "_Exit") Do WinMove($hGUI, "", $aFullScreen[0], MouseGetPos(1)) Until Not Sleep(50) Func _Exit() GUIDelete() Exit EndFunc _____________
      1.1
      #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPI.au3> AutoItSetOption("GUIOnEventMode", 1) Global $hGUI, $hDC, $hPen, $obj_orig $hGUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP) WinSetTrans($hGUI, "", 1) GUISetState() _line() Func _line() $hDC = _WinAPI_GetWindowDC(0) ; DC of entire screen (desktop) $hPen = _WinAPI_CreatePen($PS_SOLID, 2, 0x00ff) $obj_orig = _WinAPI_SelectObject($hDC, $hPen) GUISetOnEvent($GUI_EVENT_PRIMARYDOWN, "Draw", $hGUI) GUISetOnEvent(-3, "_Exit") Do Until Not Sleep(1000) EndFunc ;==>_line Func Draw() Local $aMC, $mxo, $myo $aMC = GUIGetCursorInfo($hGUI) Do GUISetCursor(0, 1, 0) $mxo = $aMC[0] $myo = $aMC[1] $aMC = GUIGetCursorInfo($hGUI) If $mxo <> $aMC[0] Or $myo <> $aMC[1] Then _WinAPI_DrawLine($hDC, $aMC[0], $aMC[1], $mxo, $myo) _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE) $mxo = $aMC[0] $myo = $aMC[1] EndIf Sleep(10) Until Not $aMC[2] EndFunc Func _Exit() _WinAPI_SelectObject($hDC, $obj_orig) _WinAPI_DeleteObject($hPen) _WinAPI_ReleaseDC(0, $hDC) Exit EndFunc  
    • Pricehacker
      By Pricehacker
      Hello,
      I am making a program where the button is an image that "changes" when specific conditions are fullfilled. Problem is that these images have different dimensions and when a smaller picture is displayed over a bigger one both will be seen, therefore i would like the images to be hidden, invincible or, alternatively, deleted.
      I have tried using _GDIPlus_GraphicsClear() with no luck
      However that might just be me not using it right as im quite new to autoit
      Here is the code if you want to test run it:
      Thanks to everyone helping!
×