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

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

    • 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!
    • UEZ
      By UEZ
      AutoIt Windows Screenshooter
      Key Features:
      takes easily a screenshot from any visible window capture any region of the desktop incl. freehand capturing capture GUI controls and GUI menus separately capture a marked area every x seconds for a duration of y seconds create a GIF animation from saved frames (Vista or higher os required) capture to AVI file (without audio!) takes a screenshot from web sites (available only on Win7+ os and when Aero is enabled) put images to clipboard to paste to other applications easily color picker save image in different formats and also to PDF! add timestamp to saved images simple image editing options: greyscale, b&w, invert, rotate +-90° send image to printer and default email client preview of captured screens incl. zoom option multi monitor support display pixel color under mouse ruler basic image editor (paint, highlight, ellipse, rectangle, text and some graphic FX) watermark captured image no 3rd party tools or DLLs used - pure AutoIt! fully portable - no installation is needed multi language feature (Eng, Ger, Tur, Fra and Rus only) To do:
      capture content of scrollable window/control capture cascaded menus Due to DllCall("User32.dll", "int", "PrintWindow", "hwnd", $hWnd, "handle", $hMemDC, "int", 0) limitation some windows cannot be captured properly (GDI+, ProgDVB, etc.) but can take screenshots of hidden windows. One workaround is to use full screen capturing (F11/F12) or "Grab Screen" function! Or try double click with rmb on listview items (beta).
      Download source code (6295 downloads previously):  AutoIt Windows Screenshooter v1.81 Build 2018-08-12.7z (version 3.3.12.0+ needed!)
      You are not allowed to sell this code or just parts of it in a commercial project or modify it and distribute it with a different name!
      Download compiled Exe only: 4shared / Media Fire / Softpedia (1.54mb)
      Distributing copies of the program in compiled format (exe) must be free of any fee!
      -----> click here to Donate!  
       
      (Current donators: 1. Cuong N.) 
      It is designed for Win7+ operating systems with AERO enabled! E.g. on WinXP machines some functions are not working properly and might crash the application!
      AV scanners may have a negative impact the execution of compiled exe and might report any malware. I guarantee that there is no malicious code in the source code / exe!!! 
      Main GUI:

       
       
      About Intro:

       
       
      Basic Image Editor:

       
       
      Watermark:

       
       
      Click link for an enhanced version of Watermark Image.
      Credits:
      main code by UEZ additional code (alphabetical order) by Authenticity, AutoItObject Team, Eemuli, Eukalyptus, funkey, _Kurt, martin, monoceres, ProgAndy, taietel, trancexx, Ward, wolf9228 and Yashied! mesale0077 for turkish translation wakillon for french translation AZJIO for russian translation Keys:
      Main GUI:
      User your mouse to scroll preview window or
      Numpad 8: Scroll preview window up
      Numpad 2: Scroll preview window down
      Numpad 4: Scroll preview window left
      Numpad 6: Scroll preview window right
      Numpad +: zoom in preview window or mousewheel down
      Numpad -: zoom out preview window or mousewheel up
      F1: capture again on last position
      F5: refresh Windows Name list
      PRINTSCREEN: take screenshot from whole screen
      ALT+PRINTSCR: take a screenshot from active window
      F10: Undo made changes with Image Editing function
      F11: take screenshot from whole screen incl mouse cursor
      F12: take screenshot from whole screen
      Ctrl+Alt+F9 start "Grab Screen" mode
      Ctrl+Alt+F12: take a screenshot from active window using alternative screenshot functionality (beta)!
      Ctrl+r: call ruler
      Ctrl+s: save current displayed image
      Ctrl+x: exit program
      ctrl+w: call web grab input field (availabe only when Aero is enabled)
      Ctrl+i: call image editor
      Ctrl+m: call watermark editor
      Ctrl+z: undo
      Only available on Vista+ os: double click with rmb on list items to use alternative screenshot functionality (beta)!
      When 'Grab Screen' is clicked you can hold down the ctrl key to switch to 'grab controls' mode. Control under mouse will be framed red.
      ctrl + shift will take the screenshot of appropriate control. To capture GUI menues you can press rmb which simulates the lmb. When a menu is opened press shift additionaly to capture it.
      Press and hold only the shift key to capture any region on the desktop using freehand capturing - release it so capture marked regions!
      Or just mark resizeable area which you want to grab. Press CTRL key to grab marked area or right mouse button to capture the marked area every x seconds for a duration of y seconds.
      When saving the image just enter the extension you whish to use (*.jpg;*.png;*.bmp;*.gif;*.tif;*.pdf). Big thanks to taietel for his PDF UDF!
      Image Editor:
      s: save
      c: copy
      n: send
      h: highlighter
      p: pen
      r: rectangle
      e: ellipse
      a: arrow
      o: color
      t: text
      g: text config
      Ctrl+z: undo
      Watermark editor:
      Ctrl+z: undo
       
      To start the app minimized just call it "Windows Screenshooter.exe /min"
      Maybe it is useful for someone...
      Any kind of comment is welcome.
      Br,
      UEZ
      Change log:
       
    • Sven-Seyfert
      By Sven-Seyfert
      Hi Community,

      I'm looking for a way to do a Video Overlay GUI or something like that. The idea is to create a GUI which plays a video loop (with transparency/alpha channel) in front of an other GUI. Before you asking why - because I don't believe that GDIPlus can do it out of the box. My skillset for that kind of graphical things isn't good enough to do that, but here are some specialist like @UEZ maybe who can help.

      Example alpha channel video (visualized as animated *.gif):

      I tried to do the light rays effect directly with GDIPlus, but honestly that's a bit too difficult for me. I would be very glad and grateful if there are some suggestions, ideas or recommendations.

      Code for the Video play:
       
      Example video "End.mpeg":
       
      The next challenge is that the overlay GUI should be not clickable. If I hover over the overlay area, I want to have the possibility to control the GUI or what ever, in the background. But if there is any chance to make it with GDIPlus as a Video Overlay for light rays, I would prefer that approach instead of my crazy work-around idea.

      Thanks for any suggestion - I'm grateful!
      Sven
    • c.haslam
      By c.haslam
      I had thought that _GDIPlus_ImageClone($hImage) removes all property items, but I now know that it copies property items.
      What is the easiest way of copying an image that has property items to another image that does not have property items?
    • c.haslam
      By c.haslam
      I have a strange symptom of a problem somewhere in my code, or in a UDF: when I add code to get all properties of a GDI+ image to a 6000-line script,  the variable type of a parameter is reported as a pointer when the caller clearly has this argument as a string. If I comment out my code that gets the properties, the function properly sees the parameter as a string.
      [Edit: The reporting as a pointer and getting image properties are miles apart, both in where they are in the script code and in where they are run.]
      At this point, I am looking for clues as to why this is happening, so the hunt is on!
      I have noticed one odd thing, in _GDIPlus_ImageGetPropertyIdList() I see a line that begins Local $sPropertyTagInfo = . This "line" is split into 2 lines. SCiTE shows that the first line is 2454 characters and the second 2400. Adding these numbers I get 4854 characters.
      But the Help for AutoIt3 Limits/defaults says that MAXLINESIZE, Maximum size for a line of script, is 4096 characters.
      The line would exceed the limit if AutoIt considers the subject line to be 1 line and not 2 lines.
      My question: is this line legal? Is buffer overun possible?
×