Jump to content

GDI+ Bezier Curve Examples


Malkey
 Share

Recommended Posts

A utility for getting the points array of a bezier curve (spline) for use elsewhere.

About Bezier Curve

The two end points ( start and last point) have ony one control point. The intermediate points on the bezier curve have two control points.

The control points have a thin red line to the curve point they control. Each control point of a curve point governs the entry an exit shape of the curve at that curve point. The angle to, and distance away from the curve point determines the shape of the curve before and after that point on the bezier curve.

User Guide

A single click and drag on a red spot that does not turn green, drags the desktop size, invisible, layered GUI.

A double click and drag on a red spot that does turn green, allows repositioning of that spot (point). And the bezier curve moves in response.

Once a point turns green, a single click on another red point is all that is needed the turn other points green for repositioning.

When the point turns green and the left mouse button is held down, the tooltip appears showing the point number in the array of points, and the x and y coordinate values.

Context Menu

Right mouse button click on a point or on the curve brings up a context menu containing:-

Toggle hide/show points

Add a point - Actually adds three points, a curve point and two control points.

Delete a point - Actually deletes three points.

Write points array to text file, PolyDat.txt in same directory as script. Notepad.exe is used for display of data.

Set space size around bezier points. - Should a point be dragged off layered GUI, entering a space value around all the points will reposition all the points on the layered gui with the space specified.

When the bezier curve is how you want it, you can set the space boundary size to zero. Then when you write points to text file, the recommended size width x height, is the minimun size rectangle that will contain all the points.

Exit - To exit

#include <GDIPlus.au3>
#include <GuiConstantsEx.au3>
#include <GuiSlider.au3>
#include <Date.au3>
#include <WindowsConstants.au3>
#include <misc.au3>
#include <GuiMenu.au3>
#include <WinAPI.au3>

Global Const $iOpacity = 255
Global $hGui, $hGraphic, $hBitmap, $hBrush, $hBrush, $SBoth, $GrnPt, $hBrushGrad, $pt = 0
Global $iMinBorder = 25, $bStatFlag = False
Global $dll = DllOpen("user32.dll")
Global $GuiSizeX = @DesktopWidth, $GuiSizeY = @DesktopHeight ; 200 ;
;Global Const $WM_LBUTTONDOWN = 0x0201 ; Drag Window 1 of 3 addin
Global $msg, $exit, $moveAll, $viewpoints, $pointsVisible = 1
Global Const $SS_CENTER = 1
Global $aPoints

Opt("MouseCoordMode", 0)
Opt("GUIOnEventMode", 1)
Opt("WinTitleMatchMode", 2)

Local $aPointsJigSaw[38][2] = [[37, 0],[45, 134],[85, 142],[94, 148],[91, 127],[81, 98],[128, 100], _
        [112, 130],[105, 143],[123, 153],[161, 138],[173, 220],[154, 177],[147, 183], _
        [121, 184],[132, 215],[148, 205],[179, 194],[162, 233],[157, 256],[137, 253], _
        [114, 240],[111, 268],[131, 291],[80, 292],[97, 268],[103, 250],[85, 254], _
        [44, 257],[41, 237],[25, 204],[62, 218],[80, 218],[79, 186],[59, 194], _
        [29, 211],[38, 173],[45, 134]]
Local $aPoints26A[26][2] = [[25, 0],[215, 117],[289, 54],[269, 136],[355, 118],[306, 184],[394, 197], _
        [309, 225],[385, 274],[287, 270],[313, 346],[227, 288],[198, 366],[163, 284], _
        [88, 333],[122, 259],[35, 280],[109, 221],[25, 201],[108, 180],[41, 130], _
        [127, 138],[96, 64],[162, 121],[187, 42],[215, 117]]
Local $aPoints19A[20][2] = [[19, 0],[348, 25],[348, 94],[206, 94],[281, 198],[344, 198],[344, 250], _
        [198, 250],[198, 198],[255, 198],[172, 94],[114, 177],[145, 177],[145, 229], _
        [36, 229],[36, 177],[89, 177],[145, 94],[25, 94],[25, 25]]
Local $aPoints10A[11][2] = [[10, 0],[618, 105],[278, 131],[334, 187],[801, 411],[52, 377],[604, 165], _
        [123, 240],[101, 137],[483, 521],[185, 97]]
Local $aPoints10B[11][2] = [[10, 0],[367, 53],[590, 152],[881, 185],[788, 418],[902, 667],[569, 674], _
        [308, 847],[253, 547],[56, 377],[287, 248]]

BezierCurve($aPointsJigSaw) ; <============= Start ==================

Func BezierCurve($aPoints1)
    Local $0nPoint, $mouseDiffX, $mouseDiffY, $MouseStartPos, $pos
    $aPoints = $aPoints1
    $hGui = GUICreate("GDI+", $GuiSizeX, $GuiSizeY, -1, -1, 0, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))

    GUIRegisterMsg($WM_LBUTTONDOWN, "_WinMove") ; Drag Window 2 of 3 addin
    $ContextMenu = GUICtrlCreateContextMenu()
    $viewpoints = GUICtrlCreateMenuItem("Show points", $ContextMenu, 1)
    GUICtrlSetState($viewpoints, $GUI_CHECKED)
    GUICtrlSetOnEvent($viewpoints, "ShowaPoints")

    $addpoint = GUICtrlCreateMenuItem("Add a point numbered after selected point number", $ContextMenu)
    GUICtrlSetOnEvent($addpoint, "AddPoint")
    $substractpoint = GUICtrlCreateMenuItem("Delete the selected (green) point ", $ContextMenu)
    GUICtrlSetOnEvent($substractpoint, "SubstractPoint")
    $separator1 = GUICtrlCreateMenuItem("", $ContextMenu) ; create a separator line
    $Currentpoints = GUICtrlCreateMenuItem("Write points to 'PolyDat.txt' file", $ContextMenu)
    GUICtrlSetOnEvent($Currentpoints, "CurrentPoints2Console")

    $Border = GUICtrlCreateMenuItem("Set Space Size around Bezier Points", $ContextMenu)
    GUICtrlSetOnEvent($Border, "Border")
    $separator1 = GUICtrlCreateMenuItem("", $ContextMenu) ; create a separator line
    $MenuItemExit = GUICtrlCreateMenuItem("Exit", $ContextMenu)
    GUICtrlSetOnEvent($MenuItemExit, "quitclk")

    GUISetState()
    Draw(-1)

    Do
        $msg = GUIGetMsg()
        If $msg = $GUI_EVENT_CLOSE Or $exit = 1 Then ExitLoop
        If _IsPressed("01", $dll) Then ; Virtual-Key Code (0x01) Left mouse button
            $MouseStartPos = MouseGetPos()
            $0nPoint = CheckOverPoint($MouseStartPos[0], $MouseStartPos[1])
            $mouseDiffX = 0
            If $0nPoint > 0 Then
                ToolTip(TooltipFunc($0nPoint), _ClientToScreen($hGui, $aPoints, $0nPoint, 0) - 30, _
                        _ClientToScreen($hGui, $aPoints, $0nPoint, 1) + 20)
                $moveAll = 1
                Draw($0nPoint)
                $GrnPt = $0nPoint
                While _IsPressed("01", $dll) ; Virtual-Key Code (0x01) Left mouse button
                    $pos = MouseGetPos()
                    $mouseDiffX = Int(($pos[0] - $MouseStartPos[0]))
                    $mouseDiffY = Int(($pos[1] - $MouseStartPos[1]))
                    If Abs($mouseDiffX) > 0 Or Abs($mouseDiffY) > 0 Then
                        $aPoints[$0nPoint][0] = $pos[0]
                        $aPoints[$0nPoint][1] = $pos[1]
                        Draw($0nPoint)
                        ToolTip(TooltipFunc($0nPoint), _ClientToScreen($hGui, $aPoints, $0nPoint, 0) - 30, _
                                _ClientToScreen($hGui, $aPoints, $0nPoint, 1) + 20)
                        Sleep(200)
                    EndIf
                    Sleep(20)
                WEnd
                ToolTip("")
            Else
                $moveAll = 0
                Draw(-1)
            EndIf
        EndIf ; mouse BTN 1 pressed??
        Sleep(20)
    Until _IsPressed("1B") ; ESC key
    DllClose($dll)
EndFunc ;==>BezierCurve

;Check if mouse pointer is over a red/green spot
Func CheckOverPoint($MouseX, $MouseY)
    Local $x, $retValue = -1
    For $x = 0 To UBound($aPoints) - 1
        If $MouseX < $aPoints[$x][0] + 5 And $MouseX > $aPoints[$x][0] - 5 And _
                $MouseY < $aPoints[$x][1] + 5 And $MouseY > $aPoints[$x][1] - 5 Then
            $retValue = $x
        EndIf
    Next
    Return $retValue
EndFunc ;==>CheckOverPoint

Func TooltipFunc($0nPoint)
    Local $sText

    $sText = "Point: " & $0nPoint & @CRLF & " X: " & $aPoints[$0nPoint][0] & _
            "   Y: " & $aPoints[$0nPoint][1] & @CRLF
    Return $sText
EndFunc ;==>TooltipFunc

Func Draw($pt)
    Local $hWnd, $hDC, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend, $hBrushRed, $hBrushGreen, $hPen, $aCentPt
    $GrnPt = $pt
    _GDIPlus_Startup()
    $hWnd = _WinAPI_GetDC(0)
    $hDC = _WinAPI_CreateCompatibleDC($hWnd)
    $hBitmap = _WinAPI_CreateCompatibleBitmap($hWnd, $GuiSizeX, $GuiSizeY)
    _WinAPI_SelectObject($hDC, $hBitmap)
    $hGraphic = _GDIPlus_GraphicsCreateFromHDC($hDC)
    $hPen = _GDIPlus_PenCreate(0xFF010101, 2)
    $hPenRed = _GDIPlus_PenCreate(0xFFFF0000, 1)
    $hBrushRed = _GDIPlus_BrushCreateSolid(0x8fff0000) ;red
    $hBrushGreen = _GDIPlus_BrushCreateSolid(0x8f00ff00) ;Green
    _GDIPlus_GraphicsClear($hGraphic)

    _GDIPlus_GraphicsDrawBeziers($hGraphic, $aPoints, $hPen)

    If $pointsVisible = 1 Then
        For $x = 1 To UBound($aPoints) - 1
            If $x = $pt Then
                _GDIPlus_GraphicsFillEllipse($hGraphic, $aPoints[$x][0] - 5, $aPoints[$x][1] - 5, 10, 10, $hBrushGreen)
            Else
                _GDIPlus_GraphicsFillEllipse($hGraphic, $aPoints[$x][0] - 5, $aPoints[$x][1] - 5, 10, 10, $hBrushRed)
            EndIf
            _GDIPlus_GraphicsDrawEllipse($hGraphic, $aPoints[$x][0] - 5, $aPoints[$x][1] - 5, 10, 10)
            If Mod($x - 1, 3) = 0 And $x > 3 And $x < UBound($aPoints) - 3 Then
                _GDIPlus_GraphicsDrawLine($hGraphic, $aPoints[$x][0], $aPoints[$x][1], $aPoints[$x + 1][0], $aPoints[$x + 1][1], $hPenRed)
                _GDIPlus_GraphicsDrawLine($hGraphic, $aPoints[$x][0], $aPoints[$x][1], $aPoints[$x - 1][0], $aPoints[$x - 1][1], $hPenRed)
            EndIf
        Next
        _GDIPlus_GraphicsDrawLine($hGraphic, $aPoints[1][0], $aPoints[1][1], $aPoints[2][0], $aPoints[2][1], $hPenRed)
        _GDIPlus_GraphicsDrawLine($hGraphic, $aPoints[UBound($aPoints) - 1][0], $aPoints[UBound($aPoints) - 1][1], _
                $aPoints[UBound($aPoints) - 2][0], $aPoints[UBound($aPoints) - 2][1], $hPenRed)
    EndIf
    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", $GuiSizeX)
    DllStructSetData($tSize, "Y", $GuiSizeY)
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", 1)
    _WinAPI_UpdateLayeredWindow($hGui, $hWnd, 0, $pSize, $hDC, $pSource, 0, $pBlend, $ULW_ALPHA)
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_PenDispose($hPenRed)
    ; _GDIPlus_BrushDispose($hBrushGrad[2])
    _GDIPlus_BrushDispose($hBrushRed)
    _GDIPlus_BrushDispose($hBrushGreen)
    _GDIPlus_GraphicsDispose($hGraphic)
    _WinAPI_DeleteObject($hBitmap)
    _GDIPlus_Shutdown()
    _WinAPI_ReleaseDC(0, $hWnd)
    _WinAPI_DeleteDC($hDC)
    Return
EndFunc ;==>Draw

;Called from context menu check / uncheck Show Points
Func ShowaPoints()
    If $pointsVisible = 1 Then
        GUICtrlSetState($viewpoints, $GUI_UNCHECKED)
        $pointsVisible = 0
    Else
        GUICtrlSetState($viewpoints, $GUI_CHECKED)
        $pointsVisible = 1
    EndIf
    Draw(-1)
    Return
EndFunc ;==>ShowaPoints

;Called from context menu Write Current points to console
Func CurrentPoints2Console()
    If WinExists("PolyDat.txt") Then
        WinActivate("PolyDat.txt")
        WinWaitActive("PolyDat.txt")
        Send("^s")
        WinWaitActive("PolyDat.txt")
        Send("{ALT}")
        Send("f")
        Send("x")
    EndIf
    $hFile = FileOpen("PolyDat.txt", 1)
    $aPoints[0][0] = UBound($aPoints) - 1
    $aPoints[0][1] = 0
    $FromStats = SizeStats()
    $text = "Local $aPoints[" & UBound($aPoints) & "][2] = [[" & $aPoints[0][0] & "," & $aPoints[0][1] & "],"

    For $x = 1 To UBound($aPoints) - 1
        If Mod($x, 7) = 0 Then $text &= " _" & @CRLF & "    "
        $text &= "[" & $aPoints[$x][0] & "," & $aPoints[$x][1] & "],"
    Next
    $text = StringTrimRight($text, 1) & "]"
    FileWriteLine($hFile, "; =========== " & _Now() & " ===================" & @CRLF & @CRLF)
    FileWriteLine($hFile, $text & @CRLF & @CRLF)
    FileWriteLine($hFile, "Recommended GUI size     : Width X Height = " & $FromStats[4] & " X " & $FromStats[5] & @CRLF & _
            "About the points in array: MiniX, MiniY = " & $FromStats[0] & ", " & $FromStats[1] & _
            " MaxX, MaxY = " & $FromStats[2] & ", " & $FromStats[3] & _
            " Border set to " & $iMinBorder & @CRLF & @CRLF)
    FileClose($hFile)
    Run("Notepad.exe PolyDat.txt")
    Return
EndFunc ;==>CurrentPoints2Console

; Called from context menu Exit script.
Func quitclk()
    $exit = 1 ; Chr(27) ;
EndFunc ;==>quitclk

; Returns a suitable Width and Height to encompass polygon for use in
; save as image and write to console. Max & Min points are just for info.
Func SizeStats()
    Local $iMinX = $aPoints[1][0], $iMaxX = $aPoints[1][0], $x = 0, $y = 0
    Local $iMinY = $aPoints[1][1], $iMaxY = $aPoints[1][1]
    Local $iMinWidth, $iMinHeigth

    For $r = 1 To UBound($aPoints) - 1
        If $aPoints[$r][0] < $iMinX Then $iMinX = $aPoints[$r][0]
        If $aPoints[$r][1] < $iMinY Then $iMinY = $aPoints[$r][1]
        If $aPoints[$r][0] > $iMaxX Then $iMaxX = $aPoints[$r][0]
        If $aPoints[$r][1] > $iMaxY Then $iMaxY = $aPoints[$r][1]
    Next

    Local $iMaxBorder = 80
    If Not $bStatFlag Then
        If $iMinX < $iMinBorder Then $x = $iMinBorder - $iMinX
        If $iMinY < $iMinBorder Then $y = $iMinBorder - $iMinY
        If ($iMinX - $iMinBorder) > $iMaxBorder Then $x = $x - ($iMinX - $iMinBorder)
        If ($iMinY - $iMinBorder) > $iMaxBorder Then $y = $y - ($iMinY - $iMinBorder)
        If $x <> 0 Or $y <> 0 Then $aPoints = arrayplusScalarPoint($aPoints, $x, $y);
        If $iMinBorder = 0 Then $aPoints = arrayplusScalarPoint($aPoints, -$iMinX, 0);
        $bStatFlag = True
        SizeStats()
    EndIf
    $bStatFlag = False

    $iMinWidth = $iMinX + $iMaxX ; = (2 * $iMinX) + actual width
    $iMinHeigth = $iMinY + $iMaxY ; = (2 * $iMinY) + actual height

    Local $aStats[6] = [$iMinX, $iMinY, $iMaxX, $iMaxY, $iMinWidth, $iMinHeigth]
    Draw(-1)
    Return $aStats
EndFunc ;==>SizeStats

;Called from context menu. Adds a points. eg. if point3 is selected (green) then a new point 4 is added
Func AddPoint()
    ;Local $LastColor
    If $GrnPt <> Mod($GrnPt - 1, 3) And $GrnPt < 3 And $GrnPt > UBound($aPoints) - 3 Then
        MsgBox(0, "Add a Point", "Select a point.(NOT Endpoints). (Click on a red point to turn it green)", 0, _
                WinGetHandle('Program Manager'));$hGui );
    Else
        Dim $aRET[UBound($aPoints) + 3][2]
        For $r = 1 To UBound($aPoints) - 1
            If $r = $GrnPt Then
                $aRET[$r][0] = $aPoints[$r][0]
                $aRET[$r][1] = $aPoints[$r][1]
                $aRET[$r + 1][0] = $aPoints[$r][0] + 10
                $aRET[$r + 1][1] = $aPoints[$r][1] + 10
                $aRET[$r + 2][0] = $aPoints[$r][0] + 20
                $aRET[$r + 2][1] = $aPoints[$r][1] + 20
                $aRET[$r + 3][0] = $aPoints[$r][0] + 30
                $aRET[$r + 3][1] = $aPoints[$r][1] + 30
            ElseIf $r > $GrnPt Then
                $aRET[$r + 3][0] = $aPoints[$r][0]
                $aRET[$r + 3][1] = $aPoints[$r][1]
            Else
                $aRET[$r][0] = $aPoints[$r][0]
                $aRET[$r][1] = $aPoints[$r][1]
            EndIf
        Next
        $aPoints = $aRET
        $aRET = ""
        Draw(-1)
    EndIf
    Return
EndFunc ;==>AddPoint

; Called from context menu. Deletes the selected (green) point.
Func SubstractPoint()
    If $GrnPt <> Mod($GrnPt - 1, 3) And $GrnPt < 3 And $GrnPt > UBound($aPoints) - 3 Then
        MsgBox(0, "Substract a point", "Select a point. (Click on a red point to turn it green", 0, $hGui)
    Else
        Dim $aRET[UBound($aPoints) - 3][2]

        For $r = 1 To UBound($aRET) - 1
            If $r >= $GrnPt - 1 Then
                $aRET[$r][0] = $aPoints[$r + 2][0]
                $aRET[$r][1] = $aPoints[$r + 2][1]
            Else
                $aRET[$r][0] = $aPoints[$r][0]
                $aRET[$r][1] = $aPoints[$r][1]
            EndIf
        Next
        $aPoints = $aRET
        $aRET = ""
        Draw(-1)
    EndIf
    Return
EndFunc ;==>SubstractPoint


Func Border()
    Local $x = 0, $y = 0
    $Bdr = InputBox("Change border space size around the image to be saved", _
            "Current border size is " & $iMinBorder & @CRLF & @CRLF & _
            "Enter new border size, or Cancel" & @CRLF & @CRLF, $iMinBorder, "", 400, 150, -1, -1, -1, $hGui)
    If Not @error And Number($Bdr) >= 0 Then $iMinBorder = Number($Bdr) ; Min border size = 1
    SizeStats()
    Draw(-1)
    Return
EndFunc ;==>Border

;Matrix $a plus a Scalar (number) $k (Used in Margin/border Utility)
Func arrayplusScalarPoint(ByRef $pts, $x = 0, $y = 0)
    Dim $aRET[UBound($pts)][2]

    For $r = 0 To UBound($pts) - 1
        $aRET[$r][0] = $pts[$r][0] + $x
        $aRET[$r][1] = $pts[$r][1] + $y
    Next
    Return $aRET
EndFunc ;==>arrayplusScalarPoint

; =================================================================
; Drag Window 3 of 3 addin
; =================================================================
Func _WinMove($hWnd, $Command, $wParam, $lParam)
    If BitAND(WinGetState($hWnd), 32) Then Return $GUI_RUNDEFMSG
    If $moveAll = 0 Then
        DllCall("user32.dll", "int", "SendMessage", "hWnd", $hWnd, "int", $WM_NCLBUTTONDOWN, "int", $HTCAPTION, "int", 0)
    EndIf
    Return
EndFunc ;==>_WinMove

;_ClientToScreen() Function - Converts client (gui) coordinates to Screen coordinates
;Input - $hwnd - Handle from GUICreate() function
;   $cPoint - Array of points in $cPoint[n+1][2] = [[n,0],[x1,y1],[x2,y2],...[xn,yn]] format
;   Where n = Number of points
;   $index - Index of array e.g for point $cPoint[2][0] and $cPoint[2][1] $index = 2
;   $xy     - if 0 then returns screen coordinate of x
;   - If 1 then returns screen coordinate of y
;   - if 2 then returns array where return array[0] = x, and array[1] = y value
Func _ClientToScreen($hWnd, ByRef $cPoint, $index, $xy = 2)
    Local $tpoint = DllStructCreate("int X;int Y")
    Local $ret[2]
    DllStructSetData($tpoint, "X", $cPoint[$index][0])
    DllStructSetData($tpoint, "Y", $cPoint[$index][1])
    _WinAPI_ClientToScreen($hWnd, $tpoint)
    $ret[0] = DllStructGetData($tpoint, "X")
    $ret[1] = DllStructGetData($tpoint, "Y")
    If $xy = 0 Then Return $ret[0] ; x value
    If $xy = 1 Then Return $ret[1] ; y value
    If $xy = 2 Then Return $ret ; array
EndFunc ;==>_ClientToScreen

; #FUNCTION# =====================================================================
; Name...........: _GDIPlus_GraphicsDrawBeziers ==========================================
#cs
    ; Parameters ....:
    ;$hGraphics Handle to a Graphics object
    ;$aPoints - An array of points
    $aPoints[0][0] Total number of points (3*n - 2), where n is number of points on curve
    $aPoints[0][1] Y coordinate of the 1st (starting) point
    $aPoints[1][0] X coordinate of the 1st (starting) point
    $aPoints[1][1] Y coordinate of the 1st (starting) point
    $aPoints[2][0] X coordinate of the control point for 1st (starting) point
    $aPoints[2][1] Y coordinate of the first control for 1st (starting) point
    
    $aPoints[3][0] X coordinate of the first control point for 2nd point
    $aPoints[3][1] Y coordinate of the first control point for 2nd point
    $aPoints[4][0] X coordinate of the 2nd point
    $aPoints[4][1] Y coordinate of the 2nd point
    $aPoints[5][0] X coordinate of the second control point for 2nd point
    $aPoints[5][1] Y coordinate of the second control point for 2nd point
    
    $aPoints[n][0] X coordinate of the first control point for nth point
    $aPoints[n][1] Y coordinate of the first control point for nth point
    $aPoints[n+1][0] X coordinate of the nth point
    $aPoints[n+1][1] Y coordinate of the nth point
    $aPoints[n+2][0] X coordinate of the second control point for nth point
    $aPoints[n+2][1] Y coordinate of the second control point for nth point
    
    $aPoints[Second Last point][0] X coordinate of the first control point for last point
    $aPoints[Second Last point][1] Y coordinate of the first control point for last point.
    $aPoints[Last point][0]     X coordinate of the ending point
    $aPoints[Last point][1]     Y coordinate of the ending point
    
    $hPen   Handle to a pen object that is used to draw the bezier. If 0, a solid black pen with a width of
    1 will be used.
    GdipDrawBeziersI(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points, INT count)
    
#ce
Func _GDIPlus_GraphicsDrawBeziers($hGraphics, $aPoints, $hPen = 0)
    Local $iI, $iCount, $pPoints, $tPoints, $aResult, $tmpError, $tmpExError

    $iCount = UBound($aPoints) - 1 ; Modified was $iCount = $aPoints[0][0]
    $tPoints = DllStructCreate("int[" & $iCount * 2 & "]")
    $pPoints = DllStructGetPtr($tPoints)
    For $iI = 1 To $iCount
        DllStructSetData($tPoints, 1, $aPoints[$iI][0], (($iI - 1) * 2) + 1)
        DllStructSetData($tPoints, 1, $aPoints[$iI][1], (($iI - 1) * 2) + 2)
    Next

    ;_GDIPlus_PenDefCreate($hPen)
    $aResult = DllCall($ghGDIPDll, "int", "GdipDrawBeziersI", "hwnd", $hGraphics, "hwnd", $hPen, "ptr", $pPoints, "int", $iCount)
    $tmpError = @error
    $tmpExError = @extended
    _GDIPlus_PenDispose($hPen)
    If $tmpError Then Return SetError($tmpError, $tmpExError, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>_GDIPlus_GraphicsDrawBeziers

Enjoy.

Edit: Updated to run on AutoIt version 3.3.6.1 (on 31/10/2010).

Edited by Malkey
Link to comment
Share on other sites

This shows the creation and use of a two coloured gradient path brush. The path used is a bezier curve.

One colour is the centre colour. The other colour is the boundary or surround colour.

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>

Opt("GUIOnEventMode", 1)

; Creating a Path Gradient @ http://msdn.microsoft.com/en-us/library/ms533917(VS.85).aspx
Global $aPoints[11][2] = [[10, 0],[123, 77],[199, 25],[593, 143],[624, 251],[652, 343],[250, 429], _
        [171, 403],[78, 381],[25, 125],[123, 77]]


Local $hPath, $hGui, $Exit, $hGraphicGUI, $hBMPBuff, $hGraphic, $hPen, $hBrushGrad, $hBitmap = ""
Global $GuiSizeX = 680, $GuiSizeY = 480

$hGui = GUICreate("Paths", $GuiSizeX, $GuiSizeY)
GUISetOnEvent($GUI_EVENT_CLOSE, "close")
$Exit = GUICtrlCreateButton("Exit", 10, 20, 40, 30, -1, $WS_EX_TOPMOST)
GUICtrlSetBkColor($Exit, 0x8080f0)
GUICtrlSetOnEvent($Exit, "close")

GUISetState()

_GDIPlus_Startup()

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
;End Double Buffer add-in 1 of 3

$hPath = GDIPlus_CreatePath()
_GDIPlus_AddPathBeziers($hPath, $aPoints)

$hPen = _GDIPlus_PenCreate(0xFFFF0000, 4)

$hBrushGrad = GDIPlus_CreatePathGradientBrushFromPath($hPath);,0xFFFFA0A0, 0xFFA0A0FF,True) ; Gamma correction on
;$hBrushGrad = GDIPlus_CreatePathGradientBrushFromPath($hPath,"","",false) ; Gamma correction off

_GDIPlus_GraphicsClear($hGraphic, 0xFFFFFFB0)

_GDIPlus_GraphicsDrawBeziers($hGraphic, $aPoints, $hPen) ; Draws bezier outline
;GDIPlus_DrawPath($hGraphic, $hPen, $hPath) ; Draws path outline, same result as above.

GDIPlus_FillPath($hGraphic, $hBrushGrad, $hPath)

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT") ; $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize._GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
_WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)) ; , $RDW_ALLCHILDREN
;End Double Buffer add-in 2 of 3

;$hBitmap = ImageMakeTransparentBkGnd($hBMPBuff, 0, 0, $GuiSizeX, $GuiSizeY)
;_GDIPlus_ImageSaveToFile($hBitmap, @DesktopDir & "\TestWrite1.png")
;ShellExecute(@DesktopDir & "\TestWrite1.png")

While 1
    Sleep(10)
WEnd

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)) ; , $RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc ;==>MY_PAINT

Func close()
    _GDIPlus_BrushDispose($hBrushGrad)
    _GDIPlus_PenDispose($hPen)
    GDIPlus_DeletePath($hPath)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hGraphicGUI)
    _WinAPI_DeleteObject($hBMPBuff)
    If $hBitmap <> "" Then _WinAPI_DeleteObject($hBitmap)
    _GDIPlus_Shutdown()
    Exit
EndFunc ;==>close

Func GDIPlus_ClosePathFigure($hPath)
    Local $aResult1 = DllCall($ghGDIPDll, "int", "GdipClosePathFigure", "hwnd", $hPath)
    Return
EndFunc ;==>GDIPlus_ClosePathFigure

;======== GDIPlus_CreatePath =====
; $aResult = DllCall($ghGDIPDll, "int", "GdipCreatePath", "int", $FillModeAlternate, "ptr", $pPath)
; $FillModeAlternate = 0
; $FillModeWinding = 1
Func GDIPlus_CreatePath()
    Local $hPath = DllCall($ghGDIPDll, "int", "GdipCreatePath", "int", 0, "int*", 0)
    Return $hPath[2]
EndFunc ;==>GDIPlus_CreatePath

Func GDIPlus_DeletePath($hPath)
    DllCall($ghGDIPDll, "int", "GdipDeletePath", "hwnd", $hPath)
    Return
EndFunc ;==>GDIPlus_DeletePath

; Two colours used. $iARGBCentre - A centre color. $pArgbSurround - A boundary color.
Func GDIPlus_CreatePathGradientBrushFromPath($hPath, $iARGBCentre = 0xFFFFFFFF, $pArgbSurround = 0xFF000000, $useGammaCorrection = True)
    Local $hBrush, $tArgb, $pArgb, $result
    If $iARGBCentre = "" Then $iARGBCentre = 0xFFFFFFFF
    If $pArgbSurround = "" Then $pArgbSurround = 0xFF000000
    $hBrush = DllCall($ghGDIPDll, "int", "GdipCreatePathGradientFromPath", "hwnd", $hPath, "int*", 0)
    $hBrush = $hBrush[2]
    $result = DllCall($ghGDIPDll, "int", "GdipSetLineGammaCorrection", "hwnd", $hBrush, "int", $useGammaCorrection)
    $result = DllCall($ghGDIPDll, "int", "GdipSetPathGradientCenterColor", "hwnd", $hBrush, "int", $iARGBCentre)
    $tArgb = DllStructCreate("int")
    $pArgb = DllStructGetPtr($tArgb)
    $result = DllStructSetData($tArgb, 1, $pArgbSurround, 1)
    $result = DllCall($ghGDIPDll, "int", "GdipSetPathGradientSurroundColorsWithCount", "hwnd", $hBrush, "int", $pArgb, "int*", 1)
    Return $hBrush
EndFunc ;==>GDIPlus_CreatePathGradientBrushFromPath

;========= GDIPlus_DrawPath =========
Func GDIPlus_DrawPath($hGraphic, $hPen, $hPath)
    Local $aResult2 = DllCall($ghGDIPDll, "int", "GdipDrawPath", "hwnd", $hGraphic, "hwnd", $hPen, "hwnd", $hPath)
    Return
EndFunc ;==>GDIPlus_DrawPath

;======= Fill Path - Color path object ==
;GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path)
Func GDIPlus_FillPath($hGraphic, $hBrushGrad, $hPath)
    DllCall($ghGDIPDll, "int", "GdipFillPath", "hwnd", $hGraphic, "hwnd", $hBrushGrad, "hwnd", $hPath)
    Return
EndFunc ;==>GDIPlus_FillPath

Func ImageMakeTransparentBkGnd($hImage2, $iStartPosX = 0, $iStartPosY = 0, $GuiSizeX = Default, $GuiSizeY = Default, $iColor = Default)
    Local $hBitmap1, $Reslt, $width, $height, $stride, $format, $Scan0, $v_Buffer, $v_Value
    $iIW = _GDIPlus_ImageGetWidth($hImage2)
    $iIH = _GDIPlus_ImageGetHeight($hImage2)
    If $GuiSizeX = Default Or $GuiSizeX > $iIW - $iStartPosX Then $GuiSizeX = $iIW - $iStartPosX
    If $GuiSizeY = Default Or $GuiSizeY > $iIH - $iStartPosY Then $GuiSizeY = $iIH - $iStartPosY
    $hBitmap1 = _GDIPlus_BitmapCloneArea($hImage2, $iStartPosX, $iStartPosY, $GuiSizeX, $GuiSizeY, $GDIP_PXF32ARGB)
    If $iColor = Default Then $iColor = GDIPlus_BitmapGetPixel($hBitmap1, 1, 1) ; Transparent color
    ProgressOn("Making a color Transparent", "The image is being processed.", "0 percent", -1, -1, 16)

    $Reslt = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $GuiSizeX, $GuiSizeY, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)

    ;Get the returned values of _GDIPlus_BitmapLockBits ()
    $width = DllStructGetData($Reslt, "width")
    $height = DllStructGetData($Reslt, "height")
    $stride = DllStructGetData($Reslt, "stride")
    $format = DllStructGetData($Reslt, "format")
    $Scan0 = DllStructGetData($Reslt, "Scan0")

    For $i = 0 To $GuiSizeX - 1
        For $j = 0 To $GuiSizeY - 1
            $v_Buffer = DllStructCreate("dword", $Scan0 + ($j * $stride) + ($i * 4))
            $v_Value = DllStructGetData($v_Buffer, 1)
            If Hex($v_Value, 6) = Hex($iColor, 6) Then
                DllStructSetData($v_Buffer, 1, Hex($iColor, 6)) ; Sets Transparency here. Alpha Channel = 00, not written to.
            EndIf
        Next
        ProgressSet(Int(100 * $i / ($GuiSizeX)), Int(100 * $i / ($GuiSizeX)) & " percent")
    Next
    _GDIPlus_BitmapUnlockBits($hBitmap1, $Reslt)
    ProgressOff()
    Return $hBitmap1
EndFunc ;==>ImageMakeTransparentBkGnd

;The GetPixel method gets the color of a specified pixel in this bitmap.
Func GDIPlus_BitmapGetPixel($hBitmap, $iX, $iY)
    Local $tArgb, $pArgb, $aRet
    $tArgb = DllStructCreate("dword Argb")
    $pArgb = DllStructGetPtr($tArgb)
    $aRet = DllCall($ghGDIPDll, "int", "GdipBitmapGetPixel", "hwnd", $hBitmap, "int", $iX, "int", $iY, "ptr", $pArgb)
    Return "0x" & Hex(DllStructGetData($tArgb, "Argb"))
EndFunc ;==>GDIPlus_BitmapGetPixel

Func _GDIPlus_BitmapSetPixel($hBitmap, $iX, $iY, $iARGB)
    Local $aRet
    $aRet = DllCall($ghGDIPDll, "int", "GdipBitmapSetPixel", "hwnd", $hBitmap, "int", $iX, "int", $iY, "dword", $iARGB)
    Return
EndFunc ;==>_GDIPlus_BitmapSetPixel

Func GDIPlus_AntiAlias($hGraphics)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetSmoothingMode", "hwnd", $hGraphics, "int", 2)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>GDIPlus_AntiAlias

Func GDIPlus_SetLineGammaCorrection($hBrush, $useGammaCorrection = True)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetLineGammaCorrection", "hwnd", $hBrush, "int", $useGammaCorrection)
    Return $aResult[0]
EndFunc ;==>GDIPlus_SetLineGammaCorrection

Func _GDIPlus_GraphicsDrawBeziers($hGraphics, $aPoints, $hPen = 0)
    Local $iI, $iCount, $pPoints, $tPoints, $aResult, $tmpError, $tmpExError
    $iCount = UBound($aPoints) - 1 ; or $iCount = $aPoints[0][0]
    $tPoints = DllStructCreate("int[" & $iCount * 2 & "]")
    $pPoints = DllStructGetPtr($tPoints)
    For $iI = 1 To $iCount
        DllStructSetData($tPoints, 1, $aPoints[$iI][0], (($iI - 1) * 2) + 1)
        DllStructSetData($tPoints, 1, $aPoints[$iI][1], (($iI - 1) * 2) + 2)
    Next
    ;_GDIPlus_PenDefCreate($hPen)
    $aResult = DllCall($ghGDIPDll, "int", "GdipDrawBeziersI", "hwnd", $hGraphics, "hwnd", $hPen, "ptr", $pPoints, "int", $iCount)
    $tmpError = @error
    $tmpExError = @extended
    ;_GDIPlus_PenDispose()
    If $tmpError Then Return SetError($tmpError, $tmpExError, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>_GDIPlus_GraphicsDrawBeziers

;GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points, INT count)
Func _GDIPlus_AddPathBeziers($hPath, $aPoints)
    Local $iI, $iCount, $pPoints, $tPoints, $aResult, $tmpError, $tmpExError
    $iCount = UBound($aPoints) - 1
    $tPoints = DllStructCreate("float[" & $iCount * 2 & "]")
    $pPoints = DllStructGetPtr($tPoints)
    For $iI = 1 To $iCount
        DllStructSetData($tPoints, 1, $aPoints[$iI][0], (($iI - 1) * 2) + 1)
        DllStructSetData($tPoints, 1, $aPoints[$iI][1], (($iI - 1) * 2) + 2)
    Next
    $aResult = DllCall($ghGDIPDll, "int", "GdipAddPathBeziers", "hwnd", $hPath, "ptr", $pPoints, "int", $iCount)
    $tmpError = @error
    $tmpExError = @extended
    If $tmpError Then Return SetError($tmpError, $tmpExError, False)
    Return SetError($aResult[2], 0, $aResult[1])
EndFunc ;==>_GDIPlus_AddPathBeziers

Edit: Updated to run on AutoIt version 3.3.6.1 (on 31/10/2010).

Edited by Malkey
Link to comment
Share on other sites

This example is of a multi-coloured, gradient filled, bezier path.

It uses all the points of the bezier array of points, (curve, control , and end points ), to locate the boundary (surround) colours. The points act as a polygon and at each point of the polygon is a colour which blends with the centre colour and the two adjoining colours at the points before and after along the polygon boundary.

This only works because all the points in the array lie on, or outside the bezier curve. When the gradient brush is created from the bezier curve path, there are no missing bits of colour where the polygon might cross over to the inside of the path. There would be no colour from the outside of the polygon to the inside of the bezier curved path when filled with the gradient brush.

I haven't tried this yet. Compile the first post (Bezier Utility) and/or compile the script at

http://www.autoitscript.com/forum/index.ph...st&p=552977

With this script you can create a coloured polygon. The Bezier Utility is a stripped down modified version of this coloured polygon script.

With both scripts running, it should be possible to manipulate the surrounding polyon, the colours at each point of the polygon, the centre point colour, and the shape of the bezier curve and position.

Both scripts write its data to a PolyDat.txt file.

From the coloured polygon script you get the points and colours arrays, and centre colour, for the _GDIPlus_CreateBezierGradientBrush() function in the script at this post before the loop.

From Bezier Utility you get the array of points for _GDIPlus_AddPathBeziers($hPath, $aPoints) in the loop.

So what you saw inside the bezier curve should be what is displayed with this script, when the data from PolyDat.txt is added.

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
HotKeySet("{ESC}", "close")

; Creating a Path Gradient @ http://msdn.microsoft.com/en-us/library/ms533917(VS.85).aspx
Global $aPoints[11][2] = [[10, 0],[123, 77],[199, 25],[593, 143],[624, 251],[652, 343],[250, 429], _
        [171, 403],[78, 381],[25, 125],[123, 77]]
Global $aColors[10] = [0xFF0000FF, 0xFFFF0000, 0xFF0000FF, 0xFFFFFF00, 0xFF00FF00, _
        0xFF0000FF, 0xFFFF0000, 0xFF0000FF, 0xFFFFFF00, 0xFF00FF00]
Global $GuiSizeX = 680, $GuiSizeY = 480
Local $hPath, $hBrushGrad[10], $aColorB

$hGui = GUICreate("Paths", $GuiSizeX, $GuiSizeY)

_GDIPlus_Startup()

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
;End Double Buffer add-in 1 of 3
_GDIPlus_GraphicsClear($hGraphic, 0xfFfffff0)
;Create array of different gradient brushes by rotating values in $aColors array.
$aColorB = $aColors
For $n = 0 To UBound($aColors) - 1
    For $m = 0 To UBound($aColors) - 1 ; Rotate values in $aColors array.
        $aColorB[Mod($m + $n, UBound($aColors))] = $aColors[$m]
    Next
    $aColorB[0] = $aColorB[UBound($aColorB) - 1]
    $hBrushGrad[$n] = _GDIPlus_CreateBezierGradientBrush($hBMPBuff, $hGraphic, 0xFFFFB0B0, $aColorB, $aPoints, False, 1.0)
    _GDIPlus_GraphicsClear($hGraphic, 0xfFfffff0); Always start with a clean buffer!
Next

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT") ; $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
;End Double Buffer add-in 2 of 3

GUISetState()

Local $m = 0
While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            close()
    EndSwitch
    $n = Mod($n + 1, UBound($aColors)) ; $hBrushGrad index number
    $hPath = GDIPlus_CreatePath()
    _GDIPlus_AddPathBeziers($hPath, $aPoints)
    GDIPlus_ClosePathFigure($hPath)
    GDIPlus_FillPath($hGraphic, $hBrushGrad[$n], $hPath)
    GDIPlus_DeletePath($hPath)
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    ; Increase & decrease sleep lenght time.
    If $m = 0 Then $p = 1
    If $m = 101 Then $p = -1
    $m += $p
    Sleep(50 + 2 * $m)
WEnd

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)) ; , $RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc ;==>MY_PAINT

Func close()
    For $n = 0 To UBound($hBrushGrad) - 1
        _GDIPlus_BrushDispose($hBrushGrad[$n])
    Next
    ;_GDIPlus_PenDispose($hPen)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_GraphicsDispose($hGraphicGUI)
    _WinAPI_DeleteObject($hBMPBuff)
    _GDIPlus_Shutdown()
    Exit
EndFunc ;==>close

;Use bezier $aPoints here only when all path and control points lie outside or on bezier path.
; Otherwise, $aPoints should be points of a polygon which lies outside or on bezier path. These
; polygon points should have corresponding color values in the $aColors array.
Func _GDIPlus_CreateBezierGradientBrush($hBMPBuff, $hGraphic, $iColorCentre, $aColors, $aPoints, _
        $bGammaCorrection = True, $iTransparency = 1.0)
    Local $hBrushGrad, $hPath, $status, $hImage, $oImage
    $hPath = GDIPlus_CreatePath()
    GDIPlus_AddPathLine2($hPath, $aPoints)
    $hBrushGrad = GDIPlus_CreatePathGradientFromPath($hPath)
    GDIPlus_SetLineGammaCorrection($hBrushGrad, $bGammaCorrection)
    GDIPlus_SetPathGradientCenterColor($hBrushGrad, $iColorCentre)
    $status = GDIPlus_SetPathGradientSurroundColorsWithCount($hBrushGrad, $aColors)

    GDIPlus_ClosePathFigure($hPath)
    GDIPlus_FillPath($hGraphic, $hBrushGrad, $hPath)

    $hImage = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBMPBuff)
    $oImage = _GDIPlus_BitmapCreateFromHBITMAP($hImage)
    _GDIPlus_BrushDispose($hBrushGrad)
    $hBrushGrad = _GDIPlus_CreateTextureTrans($oImage, 1.0, 0, 0, "", ""); Adds the color to $hBrushGrad brush.
    GDIPlus_SetLineGammaCorrection($hBrushGrad, $bGammaCorrection)

    _WinAPI_DeleteObject($hImage)
    _WinAPI_DeleteObject($oImage)
    GDIPlus_DeletePath($hPath)
    Return $hBrushGrad
EndFunc ;==>_GDIPlus_CreateBezierGradientBrush

;GpStatus WINGDIPAPI GdipAddPathLine2(GpPath *path, GDIPCONST GpPointF *points, INT count)
Func GDIPlus_AddPathLine2($hPath, $aPoints)
    Local $iI, $iCount, $pPoints, $tPoints, $aResult, $tmpError, $tmpExError

    $iCount = UBound($aPoints) - 1
    $tPoints = DllStructCreate("int[" & $iCount * 2 & "]")
    $pPoints = DllStructGetPtr($tPoints)
    For $iI = 1 To $iCount
        DllStructSetData($tPoints, 1, _WinAPI_FloatToInt($aPoints[$iI][0]), (($iI - 1) * 2) + 1)
        DllStructSetData($tPoints, 1, _WinAPI_FloatToInt($aPoints[$iI][1]), (($iI - 1) * 2) + 2)
    Next

    $aResult = DllCall($ghGDIPDll, "int", "GdipAddPathLine2", "hwnd", $hPath, "ptr", _
            $pPoints, "int", $iCount)
    $tmpError = @error
    $tmpExError = @extended
    ;_GDIPlus_BrushDispose()
    If $tmpError Then Return SetError($tmpError, $tmpExError, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>GDIPlus_AddPathLine2

Func GDIPlus_ClosePathFigure($hPath)
    Local $aResult1 = DllCall($ghGDIPDll, "int", "GdipClosePathFigure", "hwnd", $hPath)
    Return
EndFunc ;==>GDIPlus_ClosePathFigure

Func GDIPlus_AddPathEllipse($hPath, $iX, $iY, $iWidth, $iHeight)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipAddPathEllipse", "hwnd", $hPath, "int", _WinAPI_FloatToInt($iX), _
            "int", _WinAPI_FloatToInt($iY), "int", _WinAPI_FloatToInt($iWidth), "int", _WinAPI_FloatToInt($iHeight))
EndFunc ;==>GDIPlus_AddPathEllipse

;======== GDIPlus_CreatePath =====
; $aResult = DllCall($ghGDIPDll, "int", "GdipCreatePath", "int", $FillModeAlternate, "ptr", $pPath)
; $FillModeAlternate = 0
; $FillModeWinding = 1
; GdipCreatePath(GpFillMode brushMode, GpPath **path)
Func GDIPlus_CreatePath()
    Local $hPath = DllCall($ghGDIPDll, "int", "GdipCreatePath", "int", 0, "int*", 0)
    Return $hPath[2]
EndFunc ;==>GDIPlus_CreatePath

Func GDIPlus_DeletePath($hPath)
    DllCall($ghGDIPDll, "int", "GdipDeletePath", "hwnd", $hPath)
    Return
EndFunc ;==>GDIPlus_DeletePath

;====== Create Gradient Brush from Path =======
;GdipCreatePathGradientFromPath(GDIPCONST GpPath* path, GpPathGradient **polyGradient)
Func GDIPlus_CreatePathGradientFromPath($hPath)
    Local $hBrushGrad
    $hBrushGrad = DllCall($ghGDIPDll, "int", "GdipCreatePathGradientFromPath", "hwnd", $hPath, "int*", 0)
    Return $hBrushGrad[2]
EndFunc ;==>GDIPlus_CreatePathGradientFromPath
;======> End of GDIPlus_CreatePathGradientFromPath =======

Func GDIPlus_CreatePathGradientBrushFromPath($hPath, $iARGBCentre = 0xFFFFFFFF, $pArgbSurround = 0xFF000000, _
        $bGammaCorrection = True)
    Local $hBrush, $tArgb, $pArgb, $result
    If $iARGBCentre = "" Then $iARGBCentre = 0xFFFFFFFF
    If $pArgbSurround = "" Then $pArgbSurround = 0xFF000000
    ;$pArgbSurround = String($pArgbSurround)
    $hBrush = DllCall($ghGDIPDll, "int", "GdipCreatePathGradientFromPath", "hwnd", $hPath, "int*", 0)
    $hBrush = $hBrush[2]
    $result = DllCall($ghGDIPDll, "int", "GdipSetLineGammaCorrection", "hwnd", $hBrush, "int", $bGammaCorrection)
    $result = DllCall($ghGDIPDll, "int", "GdipSetPathGradientCenterColor", "hwnd", $hBrush, "int", $iARGBCentre)
    $tArgb = DllStructCreate("int")
    $pArgb = DllStructGetPtr($tArgb)
    $result = DllStructSetData($tArgb, 1, $pArgbSurround, 1)
    $result = DllCall($ghGDIPDll, "int", "GdipSetPathGradientSurroundColorsWithCount", "hwnd", $hBrush, _
            "int", $pArgb, "int*", 1)
    Return $hBrush
EndFunc ;==>GDIPlus_CreatePathGradientBrushFromPath


;========= GDIPlus_DrawPath =========
Func GDIPlus_DrawPath($hGraphic, $hPen, $hPath)
    Local $aResult2
    $aResult2 = DllCall($ghGDIPDll, "int", "GdipDrawPath", "hwnd", $hGraphic, "hwnd", $hPen, "hwnd", $hPath)
    Return
EndFunc ;==>GDIPlus_DrawPath

;======= Fill Path - Color path object ==
;GdipFillPath(GpGraphics *graphics, GpBrush *brush, GpPath *path)
Func GDIPlus_FillPath($hGraphic, $hBrushGrad, $hPath)
    DllCall($ghGDIPDll, "int", "GdipFillPath", "hwnd", $hGraphic, "hwnd", $hBrushGrad, "hwnd", $hPath)
    Return
EndFunc ;==>GDIPlus_FillPath
;=======> End of GDIPlus_FillPath ==============

;================> GDIPlus_SetPathGradientCenterColor ===============
; Description   Sets the center color of this path gradient brush. The center color is the
;   color that appears at the brush's center point.
;Parameters
;brush  [in] Pointer to the PathGradientBrush object.
;colors [in] An ARGB color that specifies the center color.
;Remarks    By default the center point is the centroid of the brush's boundary path,
;   but you can set the center point to any location inside or outside the path.
;
Func GDIPlus_SetPathGradientCenterColor($hBrush, $iARGB)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetPathGradientCenterColor", "hwnd", $hBrush, "int", $iARGB)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult);$aResult ;
EndFunc ;==>GDIPlus_SetPathGradientCenterColor
;=================================================

;GdipGetPathGradientCenterPoint( GpPathGradient *brush, GpPointF* points)
;
Func GDIPlus_GetPathGradientCenterPoint($hBrush)
    Local $aResult, $res, $iX, $iY, $Pt, $pPt, $aPt[2]
    $Pt = DllStructCreate("int X;int Y")
    $pPt = DllStructGetPtr($Pt)
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetPathGradientCenterPoint", "hwnd", $hBrush, "ptr", $pPt)
    $iX = Round(_WinAPI_IntToFloat(DllStructGetData($Pt, 'X')), 0)
    $iY = Round(_WinAPI_IntToFloat(DllStructGetData($Pt, 'Y')), 0)
    ;$res = "GdipGetPathGradientCenterPoint" & @CRLF
    $aPt[0] = $iX
    $aPt[1] = $iY
    Return $aPt
EndFunc ;==>GDIPlus_GetPathGradientCenterPoint
;=================================================

;==============> GDIPlus_SetPathGradientSurroundColorsWithCount ===================================
;Description    Sets the surround colors of this path gradient brush. The surround colors are colors
;   specified for discrete points on the brush's boundary path.
;Parameters
;brush  [in] Pointer to the PathGradientBrush object.
;colors [in] Pointer to an array of ARGB colors that specify the surround colors.
;count  [in, out] Pointer to a long integer that, on input, specifies the number of Color objects
;   in the colors array. If the method succeeds, this parameter, on output, receives the number
;   of surround colors set. If the method fails, this parameter does not receive a value.
;Remarks    A path gradient brush has a boundary path and a center point. The center point is set
;   to a single color, but you can specify different colors for several points on the boundary.
;   For example, suppose you specify red for the center color, and you specify blue, green,
;   and yellow for distinct points on the boundary. Then as you move along the boundary,
;   the color will change gradually from blue to green to yellow and back to blue.
;   As you move along a straight line from any point on the boundary to the center point,
;   the color will change from that boundary point's color to red.
;
Func GDIPlus_SetPathGradientSurroundColorsWithCount($hBrush, $aArgb)
    Local $iI, $iCount, $aResult, $res, $x, $tArgb, $pArgb
    If IsArray($aArgb) Then
        $iCount = UBound($aArgb) ;_WinAPI_FloatToInt(UBound($aArgb)) ;
        $tArgb = DllStructCreate("int[" & $iCount & "]")
        $pArgb = DllStructGetPtr($tArgb)
        For $iI = 0 To $iCount - 1
            DllStructSetData($tArgb, 1, $aArgb[$iI], $iI + 1)
        Next
    Else
        $iCount = 1
        $tArgb = DllStructCreate("int")
        $pArgb = DllStructGetPtr($tArgb)
        DllStructSetData($tArgb, 1, $aArgb, 1)
    EndIf
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetPathGradientSurroundColorsWithCount", "hwnd", $hBrush, _
            "int", $pArgb, "int*", $iCount)
    If @error Then Return SetError(@error, @extended, 0)
    Return SetError(0, 0, $aResult) ; $aResult ;
EndFunc ;==>GDIPlus_SetPathGradientSurroundColorsWithCount
;=================================================


; Gets the number of colors that have been specified for the boundary path of this path gradient brush.
;
Func GDIPlus_GetPathGradientSurroundColorCount($hBrush)
    Local $iCount, $res, $x
    $iCount = DllCall($ghGDIPDll, "int", "GdipGetPathGradientSurroundColorCount", "hwnd", $hBrush, "int*", 0)
    Return $iCount[2]
EndFunc ;==>GDIPlus_GetPathGradientSurroundColorCount

;GdipGetPathGradientSurroundColorsWithCount( GpPathGradient *brush, ARGB* color, INT* count)
Func GDIPlus_GetPathGradientSurroundColorsWithCount($hBrush)
    Local $iI, $iCount, $aArgb, $tArgb, $pArgb, $aResult, $res, $iCount1
    $iCount1 = GDIPlus_GetPathGradientSurroundColorCount($hBrush)
    Local $aArgb[$iCount1 - 1]
    $iCount1 = UBound($aArgb) ;_WinAPI_FloatToInt(UBound($aArgb)) ;
    $tArgb = DllStructCreate("int[" & $iCount & "]")
    $pArgb = DllStructGetPtr($tArgb)
    $aResult = DllCall($ghGDIPDll, "int", "GdipGetPathGradientSurroundColorsWithCount", "hwnd", $hBrush, "int*", $pArgb, "int*", $iCount)
    For $iI = 1 To $iCount1
        $aArgb[$iI - 1] = DllStructGetData($tArgb, 1, "")
    Next
    If @error Then Return SetError(@error, @extended, 0)
    Return $aResult ;SetError($aResult[0], 0, $aResult[2])
EndFunc ;==>GDIPlus_GetPathGradientSurroundColorsWithCount

Func GDIPlus_AntiAlias($hGraphics)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetSmoothingMode", "hwnd", $hGraphics, "int", 2)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>GDIPlus_AntiAlias

Func GDIPlus_SetLineGammaCorrection($hBrush, $bGammaCorrection = True)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetLineGammaCorrection", "hwnd", $hBrush, "int", $bGammaCorrection)
    Return $aResult[0]
EndFunc ;==>GDIPlus_SetLineGammaCorrection

Func _GDIPlus_GraphicsDrawBeziers($hGraphics, $aPoints, $hPen = 0)
    Local $iI, $iCount, $pPoints, $tPoints, $aResult, $tmpError, $tmpExError
    $iCount = UBound($aPoints) - 1 ; or $iCount = $aPoints[0][0]
    $tPoints = DllStructCreate("int[" & $iCount * 2 & "]")
    $pPoints = DllStructGetPtr($tPoints)
    For $iI = 1 To $iCount
        DllStructSetData($tPoints, 1, $aPoints[$iI][0], (($iI - 1) * 2) + 1)
        DllStructSetData($tPoints, 1, $aPoints[$iI][1], (($iI - 1) * 2) + 2)
    Next
    ;_GDIPlus_PenDefCreate($hPen)
    $aResult = DllCall($ghGDIPDll, "int", "GdipDrawBeziersI", "hwnd", $hGraphics, "hwnd", $hPen, "ptr", $pPoints, "int", $iCount)
    $tmpError = @error
    $tmpExError = @extended
    ;_GDIPlus_PenDispose()
    If $tmpError Then Return SetError($tmpError, $tmpExError, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>_GDIPlus_GraphicsDrawBeziers

;GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points, INT count)
Func _GDIPlus_AddPathBeziers($hPath, $aPoints)
    Local $iI, $iCount, $pPoints, $tPoints, $aResult, $tmpError, $tmpExError

    $iCount = UBound($aPoints) - 1
    $tPoints = DllStructCreate("float[" & $iCount * 2 & "]")
    $pPoints = DllStructGetPtr($tPoints)
    For $iI = 1 To $iCount
        DllStructSetData($tPoints, 1, $aPoints[$iI][0], (($iI - 1) * 2) + 1)
        DllStructSetData($tPoints, 1, $aPoints[$iI][1], (($iI - 1) * 2) + 2)
    Next

    $aResult = DllCall($ghGDIPDll, "int", "GdipAddPathBeziers", "hwnd", $hPath, "ptr", $pPoints, "int", $iCount)
    $tmpError = @error
    $tmpExError = @extended
    If $tmpError Then Return SetError($tmpError, $tmpExError, False)
    Return SetError($aResult[2], 0, $aResult[1]) ; $aResult[1] ;
EndFunc ;==>_GDIPlus_AddPathBeziers

Func GDIPlus_SetClipGraphics($hGraphics, $hsrcgraphics, $combineMode)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetClipGraphics", "hwnd", $hGraphics, "hwnd", $hsrcgraphics, "int", $combineMode)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>GDIPlus_SetClipGraphics

Func GDIPlus_SetClipPath($hGraphics, $hPath, $combineMode)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetClipPath", "hwnd", $hGraphics, "hwnd", $hPath, "int", $combineMode)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>GDIPlus_SetClipPath

; GdipResetClip(GpGraphics *graphics)
Func GDIPlus_ResetClip($hGraphics)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipResetClip", "hwnd", $hGraphics)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc ;==>GDIPlus_ResetClip

Func _GDIPlus_CreateTextureTrans($hImage, $nTrans = 0.5, $iX = 0, $iY = 0, $iWidth = "", $iHeight = "")
    Local $tColorMatrix, $x, $hImgAttrib, $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage)
    If $iWidth = 0 Or $iWidth = "" Then $iWidth = $iW
    If $iHeight = 0 Or $iHeight = "" Then $iHeight = $iH
    ;;create color matrix data
    $tColorMatrix = DllStructCreate("float[5];float[5];float[5];float[5];float[5]")
    ;blending values:
    $x = DllStructSetData($tColorMatrix, 1, 1, 1) * DllStructSetData($tColorMatrix, 2, 1, 2) * DllStructSetData($tColorMatrix, 3, 1, 3) * _
            DllStructSetData($tColorMatrix, 4, $nTrans, 4) * DllStructSetData($tColorMatrix, 5, 1, 5)
    ;;create an image attributes object and update its color matrix
    $hImgAttrib = DllCall($ghGDIPDll, "int", "GdipCreateImageAttributes", "ptr*", 0)
    $hImgAttrib = $hImgAttrib[1]
    DllCall($ghGDIPDll, "int", "GdipSetImageAttributesColorMatrix", "ptr", $hImgAttrib, "int", 1, _
            "int", 1, "ptr", DllStructGetPtr($tColorMatrix), "ptr", 0, "int", 0)
    ;;draw image into graphic object with alpha blend
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateTextureIAI", "hwnd", $hImage, "ptr", $hImgAttrib, "int", $iX, "int", _
            $iY, "int", $iWidth, "int", $iHeight, "ptr*", 0)
    ;clean up
    DllCall($ghGDIPDll, "int", "GdipDisposeImageAttributes", "ptr", $hImgAttrib)
    Return $aResult[7]
EndFunc ;==>_GDIPlus_CreateTextureTrans

Edit: Updated to run on AutoIt version 3.3.6.1 (on 31/10/2010).

Edited by Malkey
Link to comment
Share on other sites

This script creates a centre jigsaw piece from a bezier curve and fills that piece with a clipped image. The finished jigsaw piece can be rotated at 90 degree increments. using the middle mouse button or spacebar.

Just wanted to see if it could be done completely in AutoIt.

What would be really good if a bevelled edge could be added to the jigsaw piece as ImageMagick can do - without using ImageMagick.

This script leave an image file, JigSawCentrePiece.png, on the desktop.

#include <GuiConstantsEx.au3>
#include <GDIPlus.au3>
#include <Misc.au3>
#include <WindowsConstants.au3>

Global Const $GUI_Width = 400, $GUI_Height = 400
Global $hGui1

$hGui = GUICreate("GDI+", $GUI_Width, $GUI_Height, (@DesktopWidth - $GUI_Width) / 2, 10)
GUISetState()
; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT") ; $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
_GDIPlus_Startup()
$hImage = _GDIPlus_ImageLoadFromFile(@WindowsDir & "\Web\Wallpaper\Ascent.jpg")
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GUI_Width, $GUI_Height, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
_GDIPlus_GraphicsClear($hGraphic, 0xFFF8FFE8)
_AntiAlias($hGraphic)
_GDIPlus_GraphicsClear($hGraphic, 0xFFF8FFE8)
Local $aPoints[38][2] = [[37, 0],[20, 36],[60, 44],[69, 50],[66, 29],[56, 0],[103, 2], _
        [87, 32],[80, 45],[98, 55],[136, 40],[148, 122],[129, 79],[122, 85], _
        [96, 86],[107, 117],[123, 107],[154, 96],[137, 135],[132, 158],[112, 155], _
        [89, 142],[86, 170],[106, 193],[55, 194],[72, 170],[78, 152],[60, 156], _
        [19, 159],[16, 139],[0, 106],[37, 120],[55, 120],[54, 88],[34, 96], _
        [4, 113],[13, 75],[20, 36]]
Local $x = 0, $y = 10
_SetClipBezier($hGraphic, $aPoints, $x, $y)
_GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage, 0, 0, $GUI_Width, $GUI_Height)
_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
$hBitmap = ImageColorToTransparent($hBMPBuff, $x, $y, 154, 194);, 0xFFFFFFFF)
_GDIPlus_ImageSaveToFile($hBitmap, @DesktopCommonDir & "\JigSawCentrePiece.png")
;ShellExecute(@DesktopCommonDir & "\JigSawCentrePiece.png")
GDIPlus_ResetClip($hGraphic)
_GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage, $GUI_Width / 2 - 50, $GUI_Height / 2 - 30, $GUI_Width / 2 + 50, $GUI_Height / 2 + 30)
_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
GUICtrlCreateLabel("Press middle mouse button or spacebar" & @CRLF & _
        "to rotate layered GUI ( JigSaw piece )." & @CRLF & "   And, it is draggable.", $GUI_Width / 2, 10)
_GDIPlus_GraphicsDispose($hGraphic)
_WinAPI_DeleteObject($hBitmap)
_GDIPlus_GraphicsDispose($hGraphic)
_GDIPlus_ImageDispose($hImage)
;==============================================================================
Global Const $iOpacity = 254
;Global Const $ULW_ALPHA = 2
Global $GuiSize = 200
Global Const $nPI = 3.1415926535897932384626433832795
Global Const $WM_LBUTTONDOWN = 0x0201 ; Drag Window 1 of 3 addin
Global $iPath = @DesktopCommonDir & "\JigSawCentrePiece.png"
Global $angle ;$nAngle = 0
GUIRegisterMsg($WM_LBUTTONDOWN, "_WinMove") ; Drag Window 2 of 3 addin
$hGui1 = GUICreate("GDI+ Rotate", $GuiSize, $GuiSize, @DesktopWidth/2 - 230, 200, 0, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))
GUISetState()
RotatePiece()

Do
    $msg = GUIGetMsg()
    If _IsPressed("20") Or _IsPressed("04") Then ;   SpaceBar or middle mouse button
        $angle = Mod($angle + 90, 360) ; 10deg increments (plus clockwise)
        RotatePiece($angle)
    EndIf
Until _IsPressed("1B") Or $msg = -3 ; ESC key
; Clean up resources
_WinAPI_DeleteObject($hBMPBuff)
_GDIPlus_GraphicsDispose($hGraphicGUI)
_GDIPlus_Shutdown()

Func RotatePiece($angle = 0)
    Local $hMatrix, $nX, $nY, $x, $y, $Pos[4], $radius, $hGraphic, $hImage
    Local $hWnd, $hDC, $hBitmap, $pSize, $tSize, $pSource, $tSource, $pBlend, $tBlend, $nXt, $nYt
    $hWnd = _WinAPI_GetDC(0)
    $hDC = _WinAPI_CreateCompatibleDC($hWnd)
    $hBitmap = _WinAPI_CreateCompatibleBitmap($hWnd, $GuiSize, $GuiSize)
    _WinAPI_SelectObject($hDC, $hBitmap)
    $hGraphic = _GDIPlus_GraphicsCreateFromHDC($hDC)
    $hImage = _GDIPlus_ImageLoadFromFile($iPath)
    $Pos = WinGetPos($hGui1) ; "GDI+ Rotate")
    ConsoleWrite($Pos & @CRLF)
    $nX = $Pos[0]
    $nY = $Pos[1]
    $hMatrix = _GDIPlus_MatrixCreate()
    _GDIPlus_MatrixRotate($hMatrix, $angle, False)
    _GDIPlus_GraphicsSetTransform($hGraphic, $hMatrix)
    $x = ($GuiSize / 2) * Cos($angle * $nPI / 180) - ($GuiSize / 2) + $nX - ($GuiSize / 2) * Sin($angle * $nPI / 180);Parametric equations for a circle
    $y = ($GuiSize / 2) * Sin($angle * $nPI / 180) - ($GuiSize / 2) + $nY + ($GuiSize / 2) * Cos($angle * $nPI / 180); and adjusts for center of text box
    $nXt = ($nX - $x) * Cos($angle * $nPI / 180) + ($nY - $y) * Sin($angle * $nPI / 180)
    $nYt = -($nX - $x) * Sin($angle * $nPI / 180) + ($nY - $y) * Cos($angle * $nPI / 180)
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage, $nXt + ($GuiSize * 0.2), $nYt + ($GuiSize * 0.2), $GuiSize * 0.6, $GuiSize * 0.6)
    $tSize = DllStructCreate($tagSIZE)
    $pSize = DllStructGetPtr($tSize)
    DllStructSetData($tSize, "X", $GuiSize) ;$iWidth )
    DllStructSetData($tSize, "Y", $GuiSize) ;$iHeight)
    $tSource = DllStructCreate($tagPOINT)
    $pSource = DllStructGetPtr($tSource)
    $tBlend = DllStructCreate($tagBLENDFUNCTION)
    $pBlend = DllStructGetPtr($tBlend)
    DllStructSetData($tBlend, "Alpha", $iOpacity)
    DllStructSetData($tBlend, "Format", 1)
    _WinAPI_UpdateLayeredWindow($hGui1, $hWnd, 0, $pSize, $hDC, $pSource, 0, $pBlend, $ULW_ALPHA)
    Sleep(500)
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_MatrixDispose($hMatrix)
    _WinAPI_ReleaseDC(0, $hWnd)
    _WinAPI_DeleteObject($hBitmap)
    _GDIPlus_ImageDispose($hImage)
    _WinAPI_DeleteDC($hDC)
    Return 1
EndFunc   ;==>RotatePiece

; =================================================================
; Drag Window 3 of 3 addin (from AutoIt forum)
; =================================================================
Func _WinMove($hWnd, $Command, $wParam, $lParam)
    If BitAND(WinGetState($hWnd), 32) Then Return $GUI_RUNDEFMSG
    DllCall("user32.dll", "int", "SendMessage", "hWnd", $hWnd, "int", $WM_NCLBUTTONDOWN, "int", $HTCAPTION, "int", 0)
EndFunc   ;==>_WinMove


Func _SetClipBezier($hGraphics, $aPoints, $x, $y)
    Local $aResult, $hPath = GDIPlus_CreatePath()
    Local $aTempPoints = ArrayPlusScalar($aPoints, $x, $y)
    _GDIPlus_AddPathBeziers($hPath, $aTempPoints)
    ;Trace path with pen
    Local $hPen = _GDIPlus_PenCreate()
    _GDIPlus_PenDispose($hPen)
    ;Apply mask
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetClipPath", "hwnd", $hGraphics, "ptr", $hPath, "int", 1)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc   ;==>_SetClipBezier

Func ArrayPlusScalar($pts, $x = 0, $y = 0)
    Dim $aRET[UBound($pts)][2]
    For $r = 0 To UBound($pts) - 1
        $aRET[$r][0] = $pts[$r][0] + $x
        $aRET[$r][1] = $pts[$r][1] + $y
    Next
    Return $aRET
EndFunc   ;==>ArrayPlusScalar

Func _AntiAlias($hGraphics)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipSetSmoothingMode", "hwnd", $hGraphics, "int", 2)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc   ;==>_AntiAlias

Func _GDIPlus_CreateTextureTrans($hImage, $nTrans = 0.5, $iX = 0, $iY = 0, $iWidth = "", $iHeight = "")
    Local $tColorMatrix, $x, $hImgAttrib, $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage)
    If $iWidth = 0 Or $iWidth = "" Then $iWidth = $iW
    If $iHeight = 0 Or $iHeight = "" Then $iHeight = $iH
    ;;create color matrix data
    $tColorMatrix = DllStructCreate("float[5];float[5];float[5];float[5];float[5]")
    ;blending values:
    $x = DllStructSetData($tColorMatrix, 1, 1, 1) * DllStructSetData($tColorMatrix, 2, 1, 2) * DllStructSetData($tColorMatrix, 3, 1, 3) * _
            DllStructSetData($tColorMatrix, 4, $nTrans, 4) * DllStructSetData($tColorMatrix, 5, 1, 5)
    ;;create an image attributes object and update its color matrix
    $hImgAttrib = DllCall($ghGDIPDll, "int", "GdipCreateImageAttributes", "ptr*", 0)
    $hImgAttrib = $hImgAttrib[1]
    DllCall($ghGDIPDll, "int", "GdipSetImageAttributesColorMatrix", "ptr", $hImgAttrib, "int", 1, _
            "int", 1, "ptr", DllStructGetPtr($tColorMatrix), "ptr", 0, "int", 0)
    ;;draw image into graphic object with alpha blend
    Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateTextureIAI", "hwnd", $hImage, "ptr", $hImgAttrib, "int", $iX, "int", _
            $iY, "int", $iWidth, "int", $iHeight, "ptr*", 0)
    ;clean up
    DllCall($ghGDIPDll, "int", "GdipDisposeImageAttributes", "ptr", $hImgAttrib)
    Return $aResult[7]
EndFunc   ;==>_GDIPlus_CreateTextureTrans

Func GDIPlus_CreatePath()
    Local $hPath, $res
    $hPath = DllCall($ghGDIPDll, "int", "GdipCreatePath", "int", 0, "int*", 0)
    Return $hPath[2]
EndFunc   ;==>GDIPlus_CreatePath

; GdipResetClip(GpGraphics *graphics)
Func GDIPlus_ResetClip($hGraphics)
    Local $aResult
    $aResult = DllCall($ghGDIPDll, "int", "GdipResetClip", "hwnd", $hGraphics)
    If @error Then Return SetError(@error, @extended, False)
    Return SetError($aResult[0], 0, $aResult[0] = 0)
EndFunc   ;==>GDIPlus_ResetClip

;GdipAddPathBeziers(GpPath *path, GDIPCONST GpPointF *points, INT count)
Func _GDIPlus_AddPathBeziers($hPath, $aPoints)
    Local $iI, $iCount, $pPoints, $tPoints, $aResult, $tmpError, $tmpExError
    $iCount = UBound($aPoints) - 1
    $tPoints = DllStructCreate("float[" & $iCount * 2 & "]")
    $pPoints = DllStructGetPtr($tPoints)
    For $iI = 1 To $iCount
        DllStructSetData($tPoints, 1, $aPoints[$iI][0], (($iI - 1) * 2) + 1)
        DllStructSetData($tPoints, 1, $aPoints[$iI][1], (($iI - 1) * 2) + 2)
    Next
    $aResult = DllCall($ghGDIPDll, "int", "GdipAddPathBeziers", "hwnd", $hPath, "ptr", $pPoints, "int", $iCount)
    $tmpError = @error
    $tmpExError = @extended
    If $tmpError Then Return SetError($tmpError, $tmpExError, False)
    Return SetError($aResult[2], 0, $aResult[1]); $aResult[1]
EndFunc   ;==>_GDIPlus_AddPathBeziers

Func ImageColorToTransparent($hImage2, $iStartPosX = 0, $iStartPosY = 0, $GuiSizeX = Default, $GuiSizeY = Default, $iColor = Default)
    Local $hBitmap1, $Reslt, $width, $height, $stride, $format, $Scan0, $v_Buffer, $v_Value, $iIW, $iIH
    $iIW = _GDIPlus_ImageGetWidth($hImage2)
    $iIH = _GDIPlus_ImageGetHeight($hImage2)
    If $GuiSizeX = Default Or $GuiSizeX > $iIW - $iStartPosX Then $GuiSizeX = $iIW - $iStartPosX
    If $GuiSizeY = Default Or $GuiSizeY > $iIH - $iStartPosY Then $GuiSizeY = $iIH - $iStartPosY
    $hBitmap1 = _GDIPlus_BitmapCloneArea($hImage2, $iStartPosX, $iStartPosY, $GuiSizeX, $GuiSizeY, $GDIP_PXF32ARGB)
    If $iColor = Default Then $iColor = GDIPlus_BitmapGetPixel($hBitmap1, 1, 1) ; Transparent color
    ConsoleWrite($iColor & @CRLF)
    ProgressOn("Making a color Transparent", "The image is being processed.", "0 percent", -1, -1, 16)
    $Reslt = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $GuiSizeX, $GuiSizeY, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)
    $width = DllStructGetData($Reslt, "width")
    $height = DllStructGetData($Reslt, "height")
    $stride = DllStructGetData($Reslt, "stride")
    $format = DllStructGetData($Reslt, "format")
    $Scan0 = DllStructGetData($Reslt, "Scan0")
    For $i = 0 To $GuiSizeX - 1
        For $j = 0 To $GuiSizeY - 1
            $v_Buffer = DllStructCreate("dword", $Scan0 + ($j * $stride) + ($i * 4))
            $v_Value = DllStructGetData($v_Buffer, 1)
            If Hex($v_Value, 6) = Hex($iColor, 6) Then
                DllStructSetData($v_Buffer, 1, Hex($iColor, 6)) ; Sets Transparency here. Alpha Channel = 00, not written to.
            EndIf
        Next
        ProgressSet(Int(100 * $i / ($GuiSizeX)), Int(100 * $i / ($GuiSizeX)) & " percent")
    Next
    _GDIPlus_BitmapUnlockBits($hBitmap1, $Reslt)
    ProgressOff()
    Return $hBitmap1
EndFunc   ;==>ImageColorToTransparent

;The GetPixel method gets the color of a specified pixel in this bitmap.
Func GDIPlus_BitmapGetPixel($hBitmap, $iX, $iY)
    Local $tArgb, $pArgb, $aRET
    $tArgb = DllStructCreate("dword Argb")
    $pArgb = DllStructGetPtr($tArgb)
    $aRET = DllCall($ghGDIPDll, "int", "GdipBitmapGetPixel", "hwnd", $hBitmap, "int", $iX, "int", $iY, "ptr", $pArgb)
    Return "0x" & Hex(DllStructGetData($tArgb, "Argb"))
EndFunc   ;==>GDIPlus_BitmapGetPixel

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    ; Check, if the GUI with the Graphic should be repainted
    ; The sequencial order of these two commands is important.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)) ; , $RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc   ;==>MY_PAINT
Link to comment
Share on other sites

gesller, Greenhorn, ptrex. Thank-you for your positive response.

Further to my comment in post 4, the jigsaw one about a beveled edge without using ImageMagick. I found my AutoIt accessing ImageMagick script that still works.

So if you have ImageMagick installed, and,

if you have the JigSawCentrePiece.png still on your desktop from the post 4 jigsaw script, and,

you do not mind three more image files starting with JigSaw put on your desktop,

then try the following script.

The first image created has a bevel added.

The second adds thickness.

The third image has a shadow added. This was the mental picture I had when I made the comment in post 4.

This is a link to the ImageMagick site,

http://www.imagemagick.org/script/index.php

Dim $img
Dim $ret

; Initialize error handler
$oMyError = ObjEvent("AutoIt.Error","MyErrFunc")

$img = ObjCreate("ImageMagickObject.MagickImage.1")

    $ret = $img.Convert (@DesktopCommonDir & "\JigSawCentrePiece.png", _
            "(", "+clone", "-channel", "A", "-separate", "+channel", "-negate", _
            "-background", "black", "-virtual-pixel", "background", _
            "-blur", "0x2", "-shade", "120x21.78", "-contrast-stretch", "0%", _
            "+sigmoidal-contrast", "7x50%", "-fill", "grey50", "-colorize", "10%", _
            "+clone", "+swap", "-compose", "overlay", "-composite", ")", _
            "-compose", "In", "-composite", @DesktopCommonDir & "\jigsaw_bevel.png")
    ;ShellExecute(@DesktopCommonDir & "\jigsaw_bevel.png")
    
    $ret = $img.Convert (@DesktopCommonDir & "\jigsaw_bevel.png", _
            "(", "+clone", "-fill", "DarkSlateGrey", "-colorize", "100%", "-repage", "+0+1", ")", _
            "(", "+clone", "-repage", "+1+2 ", ")", "(", "+clone", "-repage", "+1+3", ")", _
            "(", "+clone", "-repage", "+2+4", ")", "(", "+clone", "-repage", "+2+5", ")", _
            "-background", "none", "-compose", "DstOver", "-flatten", _
            @DesktopCommonDir & "\jigsaw_thickness.png")
            
    $ret = $img.Convert (@DesktopCommonDir & "\jigsaw_thickness.png", _
            "(", "+clone", "-background", "Black", "-shadow", "50x3+4+4", ")", _
            "-background", "none", "-compose", "DstOver", "-flatten", _
            @DesktopCommonDir & "\jigsaw_shaddow.png")      
    ;ShellExecute(@DesktopCommonDir & "\jigsaw_shaddow.png")

For more information about ImageMagick, search the AutoIt forums.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

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