Jump to content

GDI+: Clipping fails after rotation


 Share

Recommended Posts

20 minutes ago, c.haslam said:

It appears to me that it will fail if, in traversing the image, it simultaneously encounters two black pixels before reaching a corner triangle. I realize that this is unlikely.

Yes, it was just a proof of concept version. What I would do is to create a bitmap with a rectangle (different color of course) which will be also rotated and check for the color. This will work also for images with transparent parts.

Of course your math solution is much cooler!  B)

 

Well done!

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

41 minutes ago, Earthshine said:

linear algebra isn't the algebra you learn in 8th grade... lol

I got me a GED and that proves I can read and write. To me 1+1+1+1+1+1 is as linear as algebra gets. Then again, is an uneducated guess. :) 

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

I have decided to, at least, add the ability to move the line vertically with the mouse. I have searched this website (using Google) and have looked at example scripts in the Help. I found the example for_GDIPlus_MatrixGetElements() and copied the code for WM_LBUTTONDOWN() and WM_MOUSEMOVE() from there, and modified it slightly to meet my needs, but I can't get it to work.

Help will be greatly appreciated.

I am looking at 2 ways of moving the line vertically:

  1.  Moving the mouse up and down with the left button depressed when the cursor is in the picture moves the line
  2. Dragging the line up and down with the mouse

I would prefer the code to do case 2, but a solution for case 1 would be sufficient, at least for the immediate future.

 

 

Spoiler

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

 

Link to comment
Share on other sites

Try something like this here.

#include <ButtonConstants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
Opt('MustDeclareVars',1)

GUIRegisterMsg($WM_PAINT,'WM_PAINT')

Global $gX0=10,$gX1=880,$gY0,$gY1,$gForm1,$glblPic,$gCtlWid,$gCtlHt,$imgWid,$imgHt
Global $ghCanvas,$ghImage,$ghPen,$ghPen2,$gGraphicPic,$ghMatrix,$ghBitmap,$ghPathLine,$ghPathRectL,$ghPathRectR,$aCursor

main()

Func main()
$gCtlWid = 893
$gCtlHt = 480
$gForm1 = GUICreate("Form1", $gCtlWid+50, 601, 192, 114)
$glblPic = GUICtrlCreateLabel("", 8, 8, $gCtlWid, $gCtlHt)
Local $btnRotate = GUICtrlCreateButton("Rotate", 472, 560, 65, 25)
Local $btnExit = GUICtrlCreateButton("Exit",600,560)
GUISetState(@SW_SHOW)

    Local $oldY0,$oldY1

    _GDIPlus_Startup()

    $ghPen = _GDIPlus_PenCreate(0xFFA04040,3)
    $ghPen2 = _GDIPlus_PenCreate(0xFF00FF00,4)
    $ghImage = _GDIPlus_ImageLoadFromFile('pergola.jpg')
    Local $hnd = GUICtrlGetHandle($glblPic)
    $gGraphicPic = _GDIPlus_GraphicsCreateFromHWND($hnd)
    $gY0 = 400
    $gY1 = 400
    $imgWid = _GDIPlus_ImageGetWidth($ghImage)
    $imgHt = _GDIPlus_ImageGetHeight($ghImage)
    $ghBitmap = _GDIPlus_BitmapCreateFromScan0($imgWid, $imgHt)
    $ghCanvas = _GDIPlus_ImageGetGraphicsContext($ghBitmap)
    $ghPathLine = _GDIPlus_PathCreate()
    $ghPathRectL = _GDIPlus_PathCreate()
    $ghPathRectR = _GDIPlus_PathCreate()
    _GDIPlus_PathAddLine($ghPathLine, $gX0, $gY0, $gX1, $gY1)
    _GDIPlus_PathAddRectangle($ghPathRectL, $gX0 - 5, $gY0 - 5, 12, 12)
    _GDIPlus_PathAddRectangle($ghPathRectR, $gX1 - 7, $gY1 - 5, 12, 12)
    Local $b = True
    ; Loop until the user exits.
    While True
        If $gY0<>$oldY0 Or $gY1<>$oldY1 Then
            Paint()
            $oldY0 = $gY0
            $oldY1 = $gY1
        Else
            Switch GUIGetMsg()
                Case $GUI_EVENT_CLOSE,$btnExit
                    ExitLoop
                Case $btnRotate
                    Local $hImageClone=_GDIPlus_BitmapCreateFromScan0($imgWid, $imgHt)
                    Local $hGfxClone=_GDIPlus_ImageGetGraphicsContext($hImageClone)
                    ; rotate about centre
                    $ghMatrix = _GDIPlus_MatrixCreate()
                    _GDIPlus_MatrixTranslate($ghMatrix, $imgWid/2, $imgHt/2)
                    Local $deg = Angle($gY1-$gY0, $gX1-$gX0)
                    _GDIPlus_MatrixRotate($ghMatrix, -$deg)
                    _GDIPlus_MatrixTranslate($ghMatrix, -$imgWid/2, -$imgHt/2)
                    _GDIPlus_GraphicsSetTransform($hGfxClone, $ghMatrix)

                    _GDIPlus_GraphicsDrawImageRect($hGfxClone,$ghImage,0,0,$imgWid,$imgHt)
                    _GDIPlus_GraphicsDispose($hGfxClone)

                    $hGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImage)
                    _GDIPlus_GraphicsClear($hGfxClone)
                    ; See deskew notes document
                    Local $ang = Abs($deg*3.14159/180)
                    Local $nsrcX = ($imgHt/2 - $imgWid/2*sin($ang) - $imgHt/2*cos($ang))*tan($ang) _
                        - $imgWid/2*cos($ang) + $imgHt/2*sin($ang) + $imgWid/2
                    Local $nsrcY = ($imgWid/2 + $imgWid/2*Cos($ang) - $imgHt/2*Sin($ang))*Tan($ang) _
                        - $imgWid/2*Sin($ang) - $imgHt/2*Cos($ang) + $imgHt/2
                    Local $nSrcWidth = $imgWid - 2*$nSrcX
                    Local $nSrcHeight = $imgHt - 2*$nSrcY
                    ; crop
                    _GDIPlus_GraphicsDrawImageRectRect($hGfxClone,$hImageClone, _
                        $nSrcX,$nSrcY,$nSrcWidth,$nSrcHeight,0,0,$nSrcWidth,$nSrcHeight)

                    GUICtrlDelete($glblPic)
                    _GDIPlus_GraphicsDispose($gGraphicPic)
                    $glblPic = GUICtrlCreateLabel("", 8, 8, $gCtlWid*$nSrcWidth/$imgWid,$gCtlHt*$nSrcHeight/$imgHt)
                    Local $hnd = GUICtrlGetHandle($glblPic)
                    $gGraphicPic = _GDIPlus_GraphicsCreateFromHWND($hnd)
                    _GDIPlus_ImageDispose($hImageClone)
                    $gy0 = 400
                    $gy1 = 400
                    Paint()
                    Local $hImageClone2 = _GDIPlus_BitmapCloneArea($ghImage,0,0,$nSrcWidth,$nSrcHeight)
                    _GDIPlus_ImageSaveToFile($hImageClone2,'H:\b\1.jpg')
                    _GDIPlus_ImageDispose($hImageClone2)
           EndSwitch
        EndIf
        $aCursor = GUIGetCursorInfo($gForm1)
        If _GDIPlus_PathIsOutlineVisiblePoint($ghPathLine, $aCursor[0], $aCursor[1] - 8) Then
            _GDIPlus_PenSetColor($ghPen, 0xFFF08080)
            While $aCursor[2]
                _GDIPlus_PathReset($ghPathLine)
                _GDIPlus_PathReset($ghPathRectL)
                _GDIPlus_PathReset($ghPathRectR)
                $aCursor = GUIGetCursorInfo($gForm1)
                $gY0 = $aCursor[1] - 8
                $gY1 = $aCursor[1] - 8
                _GDIPlus_PathAddLine($ghPathLine, $gX0, $gY0, $gX1, $gY1)
                _GDIPlus_PathAddRectangle($ghPathRectL, $gX0 - 5, $gY0 - 5, 12, 12)
                _GDIPlus_PathAddRectangle($ghPathRectR, $gX1 - 7, $gY1 - 5, 12, 12)
                Paint()
                Sleep(10)
            WEnd
            Paint()
            $b = False
        ElseIf _GDIPlus_PathIsOutlineVisiblePoint($ghPathRectL, $aCursor[0], $aCursor[1] - 8) Then
            _GDIPlus_PenSetColor($ghPen2, 0xFF80FF80)
            While $aCursor[2]
                _GDIPlus_PathReset($ghPathLine)
                _GDIPlus_PathReset($ghPathRectL)
                _GDIPlus_PathReset($ghPathRectR)
                $aCursor = GUIGetCursorInfo($gForm1)
                $gY0 = $aCursor[1] - 8
                $gX0 = $aCursor[0] - 8
                _GDIPlus_PathAddLine($ghPathLine, $gX0, $gY0, $gX1, $gY1)
                _GDIPlus_PathAddRectangle($ghPathRectL, $gX0 - 5, $gY0 - 5, 12, 12)
                _GDIPlus_PathAddRectangle($ghPathRectR, $gX1 - 7, $gY1 - 5, 12, 12)
                Paint()
                Sleep(10)
            WEnd
            Paint()
            $b = False
        ElseIf _GDIPlus_PathIsOutlineVisiblePoint($ghPathRectR, $aCursor[0], $aCursor[1] - 8) Then
            _GDIPlus_PenSetColor($ghPen2, 0xFF80FF80)
            While $aCursor[2]
                _GDIPlus_PathReset($ghPathLine)
                _GDIPlus_PathReset($ghPathRectL)
                _GDIPlus_PathReset($ghPathRectR)
                $aCursor = GUIGetCursorInfo($gForm1)
                $gX1 = $aCursor[0] - 8
                $gY1 = $aCursor[1] - 8
                _GDIPlus_PathAddLine($ghPathLine, $gX0, $gY0, $gX1, $gY1)
                _GDIPlus_PathAddRectangle($ghPathRectL, $gX0 - 5, $gY0 - 5, 12, 12)
                _GDIPlus_PathAddRectangle($ghPathRectR, $gX1 - 7, $gY1 - 5, 12, 12)
                Paint()
                Sleep(10)
            WEnd
            Paint()
            $b = False
        Else
            If Not $B Then
                _GDIPlus_PenSetColor($ghPen, 0xFFA04040)
                _GDIPlus_PenSetColor($ghPen2, 0xFF00FF00)
                Paint()
                $b = True
            EndIf
        EndIf
    WEnd

    ; Clean up resources
    _GDIPlus_PathDispose($ghPathLine)
    _GDIPlus_PathDispose($ghPathRectL)
    _GDIPlus_PathDispose($ghPathRectR)
    _GDIPlus_MatrixDispose($ghMatrix)
    _GDIPlus_ImageDispose($ghCanvas)
    _GDIPlus_ImageDispose($ghImage)
    _GDIPlus_ImageDispose($ghBitmap)
    _GDIPlus_PenDispose($ghPen)
    _GDIPlus_PenDispose($ghPen2)
    _GDIPlus_GraphicsDispose($gGraphicPic)
    _GDIPlus_Shutdown()
EndFunc

Func Paint()
    _GDIPlus_GraphicsDrawImageRect($ghCanvas, $ghImage, 0,0, $gCtlWid, $gCtlHt)
    _GDIPlus_GraphicsDrawPath($ghCanvas, $ghPathLine, $ghPen)
    _GDIPlus_GraphicsDrawPath($ghCanvas, $ghPathRectL, $ghPen2)
    _GDIPlus_GraphicsDrawPath($ghCanvas, $ghPathRectR, $ghPen2)
    _GDIPlus_GraphicsDrawImageRect($gGraphicPic, $ghBitmap, 0, 0, $imgWid, $imgHt)
EndFunc

Func WM_PAINT()
    _WinAPI_RedrawWindow($gForm1, 0, 0, $RDW_UPDATENOW)
    Paint()
    _WinAPI_RedrawWindow($gForm1, 0, 0, $RDW_VALIDATE)
EndFunc

Func Angle($y, $x) ;return value is in degree
    Local Const $fPi = ACos(-1), $fPi2 = ACos(-1) / 2, $fRad = 180 / $fPi
    Switch True
        Case ($x > 0)
            Return ATan($y / $x) * $fRad
        Case ($x < 0 And $y >= 0)
            Return ATan($y / $x + $fPi) * $fRad
        Case ($x < 0 And $y < 0)
            Return ATan($y / $x - $fPi) * $fRad
        Case ($x = 0 And $y > 0)
            Return $fPi2 * $fRad
        Case ($x = 0 And $y < 0)
            Return -$fPi2 * $fRad
        Case ($x = 0 And $y = 0)
            Return 0
    EndSwitch
EndFunc

You can move the line and the rectangle by hovering the mouse over it and pressing the lmb. The logic behind moving line / corners is not the best choice but might give you an idea.

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

I was trying to get WM_LBUTTONDOWN and WM_MOUSEMOVE to work. They do not fire in the label, probably because it is a static control. I also tried a picture control, and an edit control. WM_LBUTTONDOWN and WM_MOUSEMOVE don't work in any of these controls.

Both WM_LBUTTONDOWN and WM_MOUSEMOVE work in the form, outside the control.

 

Spoiler

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

 

Link to comment
Share on other sites

An earlier version of the script, based on UEZ's example, called _GDIPlus_PathIsOutlineVisiblePoint() to determine when the user mouse-downs on the line (or on an end of the line). The problem with this method was that extreme precision was required when downing the mouse; selecting the line (or ends of it) failed if the mouse wasn't exactly on the line. This was alleviated by placing a marker on each end of the line, large enough for the user to click in.

I decided to take different approach. I surrounded the line with an invisible polygon (a "fence"), inserted this figure into a Path, and called _GDIPlus_PathIsVisiblePoint() to do the determination of when the user had clicked near the line. The pen for this Path is transparent, so to the user there appears to be only a line (without the polygon). Per the Help, this function works on filled figures.

My code follows:

#include <ButtonConstants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
Opt('MustDeclareVars',1)

GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL")
GUIRegisterMsg($WM_PAINT,'WM_PAINT')

Global Const $gkOffsetFence=6
Global $gX0,$gX1,$gY0,$gY1,$gForm1,$glblPic,$gCtlWid,$gCtlHt,$imgWid,$imgHt
Global $ghCanvas,$ghImage,$ghPen,$gGraphicPic,$ghBitmap
Global $ghPathFence,$ghBrushFence,$ghPenFence

main()

Func main()
    _GDIPlus_Startup()
    $ghImage = _GDIPlus_ImageLoadFromFile('H:\b\pergola.jpg')
    $imgWid = _GDIPlus_ImageGetWidth($ghImage)
    $imgHt = _GDIPlus_ImageGetHeight($ghImage)
; Size GUI per image size
    If $imgWid<=@DesktopWidth-16 Then
        If $imgHt<=@DesktopHeight-150 Then  ; wid small, ht small
            $gCtlWid = $imgWid
            $gCtlHt = $imgHt
        Else                                ; wid small, ht big
            $gCtlHt = @DesktopHeight-150
            $gCtlWid = $gCtlHt*$imgWid/$imgHt
        EndIf
    Else
        If $imgHt<=@DesktopHeight-150 Then  ; wid big, ht small
            $gCtlWid = @DesktopWidth-16
            $gCtlHt = $gCtlWid*$imgHt/$imgWid
        Else                                ; wid big, ht big
            $gCtlWid = Min(@DesktopWidth-16,$imgWid)
            $gCtlHt = $gCtlWid*$imgHt/$imgWid
            If $gCtlHt>@DesktopHeight-150 Then
                $gCtlHt = @DesktopHeight-150
                $gCtlWid = $gCtlHt*$imgwid/$imgHt
            EndIf
        EndIf
    EndIf

    $gForm1 = GUICreate("Form1", $gCtlWid+16, $gCtlHt+70)
    $glblPic = GUICtrlCreateLabel("", 8, 8, $gCtlWid, $gCtlHt)
    GUICtrlCreateLabel('Move an end of the line by dragging the end',8,8+$gCtlHt+5)
    GUICtrlCreateLabel('Move the whole line by dragging it or with the mouse wheel',8,8+$gCtlHt+22)
    GUICtrlCreateLabel('Rotate the line with Shift + mouse wheel',8,8+$gCtlHt+39)
    Local $btnRotate = GUICtrlCreateButton("Rotate", $gCtlWid/2-40, 8+$gCtlHt+20, 65, 25)
    Local $btnExit = GUICtrlCreateButton("  Exit  ",$gCtlWid/2+40, 8+$gCtlHt+20)
    GUISetState(@SW_SHOW)

    Local $oldY0,$oldY1

    $ghPen = _GDIPlus_PenCreate(0xFFFF0000,2)   ; red
    Local $hnd = GUICtrlGetHandle($glblPic)
    $gGraphicPic = _GDIPlus_GraphicsCreateFromHWND($hnd)
    $gX0 = 10
    $gX1 = $gCtlWid - 10
    $gY0 = $gCtlHt*3/4
    $gY1 = $gY0
    $ghBitmap = _GDIPlus_BitmapCreateFromScan0($imgWid, $imgHt)
    $ghCanvas = _GDIPlus_ImageGetGraphicsContext($ghBitmap)

    $ghPenFence = _GDIPlus_PenCreate(0x000000FF)    ; transparent
    $ghPathFence = _GDIPlus_PathCreate()
    $ghBrushFence = _GDIPlus_BrushCreateSolid(0xFF0000FF)
    SetFence()
    Local $gMatrix

    While True
        If $gY0<>$oldY0 Or $gY1<>$oldY1 Then
            _GDIPlus_PathReset($ghPathFence)
            SetFence()
            Paint()
            $oldY0 = $gY0
            $oldY1 = $gY1
        Else
            Switch GUIGetMsg()
                Case $GUI_EVENT_CLOSE,$btnExit
                    ExitLoop
                Case $btnRotate
                    Local $hImageClone=_GDIPlus_BitmapCreateFromScan0($imgWid, $imgHt)
                    Local $hGfxClone=_GDIPlus_ImageGetGraphicsContext($hImageClone)
                    ; rotate about centre
                    $gMatrix = _GDIPlus_MatrixCreate()
                    _GDIPlus_MatrixTranslate($gMatrix, $imgWid/2, $imgHt/2)
                    Local $deg = Angle($gY1-$gY0, $gX1-$gX0)
                    _GDIPlus_MatrixRotate($gMatrix, -$deg)
                    _GDIPlus_MatrixTranslate($gMatrix, -$imgWid/2, -$imgHt/2)
                    _GDIPlus_GraphicsSetTransform($hGfxClone, $gMatrix)
                    _GDIPlus_MatrixDispose($gMatrix)

                    _GDIPlus_GraphicsDrawImageRect($hGfxClone,$ghImage,0,0,$imgWid,$imgHt)
                    _GDIPlus_GraphicsDispose($hGfxClone)
                    $hGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImage)
                    ; See deskew notes document
                    Local $ang = Abs($deg*3.14159/180)
                    Local $cos = cos($ang), $sin = sin($ang), $tan = tan($ang)
                    Local $w2cos = $imgWid/2*$cos, $w2sin =  $imgWid/2*$sin
                    Local $h2cos = $imgHt/2*$cos, $h2sin = $imgHt/2*$sin
                    Local $nsrcX = ($imgHt/2 - $w2sin - $h2cos)*$tan - $w2cos + $h2sin + $imgWid/2
                    Local $nsrcY = ($imgWid/2 + $w2cos - $h2sin)*$tan - $w2sin - $h2cos + $imgHt/2

                    Local $nSrcWidth = $imgWid - 2*$nSrcX
                    Local $nSrcHeight = $imgHt - 2*$nSrcY
                    ; crop to screen, centering within control
                    _GDIPlus_GraphicsClear($hGfxClone,0xFFD4D0C8)   ; client area background colour
                    Local $nDstX = ($imgWid-$nSrcWidth)/2
                    Local $nDstY = ($imgHt-$nSrcHeight)/2
                    ; draw a portion of image object $hImageClone on the image that $hGfxClone points to
                    _GDIPlus_GraphicsDrawImageRectRect($hGfxClone,$hImageClone, _
                        $nSrcX,$nSrcY,$nSrcWidth,$nSrcHeight,$nDstX,$nDstY,$nSrcWidth,$nSrcHeight)
                    _GDIPlus_ImageDispose($hImageClone)
;~                  $gy0 = 400
;~                  $gy1 = 400
                    _GDIPlus_PathDispose($ghPathFence)
                    $ghPathFence = 0
                    Paint()
                    Local $hImageClone2 = _GDIPlus_BitmapCloneArea($ghImage,$nsrcX,$nsrcY,$nSrcWidth,$nSrcHeight)
                    _GDIPlus_ImageSaveToFile($hImageClone2,'H:\b\1.jpg')
                    _GDIPlus_ImageDispose($hImageClone2)
                    ShellExecute('H:\b\1.jpg')
           EndSwitch
        EndIf
        Local $cursVec = GUIGetCursorInfo($gForm1)
        If _GDIPlus_PathIsVisiblePoint($ghPathFence,$cursVec[0]-8,$cursVec[1]-8) And $cursVec[2]=1 Then
            Local $x = $cursVec[0]-8     ; rel to control
            ; Formula for line
            Local $y = ($gy1-$gy0)/($gx1-$gx0)*($x-$gx0) + $gy0 + 8
            Opt('MouseCoordMode',2)     ; rel to client area
            MouseMove($x+8,$y)          ; move mouse to on the line, if not already there
            $cursVec[1] = $y
            Local $nuy0,$nuy1
            While $cursVec[2]=1 And $cursVec[4]=$glblPic    ; while primary button down
                $cursVec = GUIGetCursorInfo($gForm1)
                If $x<=$gx0+$gkOffsetFence Then
                    $nuY0 = $cursVec[1]-8
                    $nuy1 = $gy1
                ElseIf $x>=$gx1-$gkOffsetFence Then
                    $nuy0 = $gy0
                    $nuy1 = $cursVec[1]-8
                Else
                    Local $delta = $cursVec[1] -  $y
                    $nuy0 = $gy0 + $delta
                    $nuy1 = $gy1 + $delta
                    $y = $cursVec[1]
                EndIf
; Keep line and polygon within picture
                If $nuy0>$gkOffsetFence And $nuy0<$gCtlHt-$gkOffsetFence Then
                    $gy0 = $nuy0
                EndIf
                If $nuy1>$gkOffsetFence And $nuy1<$gCtlHt-$gkOffsetFence Then
                    $gy1 = $nuy1
                EndIf

               _GDIPlus_PathReset($ghPathFence)
                SetFence()
                Paint()
                Sleep(10)
            WEnd
        EndIf
    WEnd

    ; Clean up resources
    _GDIPlus_ImageDispose($ghCanvas)
    _GDIPlus_ImageDispose($ghImage)
    _GDIPlus_ImageDispose($ghBitmap)
    _GDIPlus_PenDispose($ghPen)
    _GDIPlus_GraphicsDispose($gGraphicPic)
    If $ghPathFence<>0 Then
        _GDIPlus_PathDispose($ghPathFence)
    EndIf
    _GDIPlus_Shutdown()
EndFunc

Func SetFence()
    Local $polyAr[5]
;       top-left, top-right, bot-right, bot-left
    Local $polyAr = [[4,0], _
        [$gx0-$gkOffsetFence,$gy0-$gkOffsetFence], _
        [$gx1+$gkOffsetFence,$gy1-$gkOffsetFence], _
        [$gx1+$gkOffsetFence,$gy1+$gkOffsetFence], _
        [$gx0-$gkOffsetFence,$gy0+$gkOffsetFence]]
    _GDIPlus_PathAddPolygon($ghPathFence,$polyAr)
    _GDIPlus_GraphicsFillPath($ghCanvas,$ghPathFence,$ghBrushFence)
EndFunc

Func WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam, $lParam
    Local Const $MK_SHIFT=0x4,$MK_CONTROL= 0x8
    Local Const $kYmax=$gCtlHt-$gkOffsetFence,$kDelta=2

    Local $vec = GUIGetCursorInfo($gForm1)
    If $vec[4]=$glblPic Then
        Local $iDelta = BitShift($wParam, 16)   ; positive = up
        Local $iKeys = _WinAPI_LoWord($wParam)
        If BitAND($iKeys,$MK_CONTROL)=$MK_CONTROL Then
            If BitAND($iKeys,$MK_SHIFT)=$MK_SHIFT Then
                ; do nothing
            Else
                If $iDelta > 0 And $gY0>$gkOffsetFence Then $gY0 -= $kDelta
                If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta
            EndIf
        Else
            If BitAND($iKeys,$MK_SHIFT)=$MK_SHIFT Then
                If $iDelta > 0 And $gY1>$gkOffsetFence Then $gY1 -= $kDelta
                If $iDelta < 0  And $gY1<$kYmax Then $gY1 += $kDelta
            Else
                If $iDelta > 0 And $gY0>$gkOffsetFence Then $gY0 -= $kDelta
                If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta
                If $iDelta > 0 And $gY1>$gkOffsetFence Then $gY1 -= $kDelta
                If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta
            EndIf
        EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOUSEWHEEL

Func Paint()
    _GDIPlus_GraphicsClear($ghCanvas,0)
    _GDIPlus_GraphicsDrawImageRect($ghCanvas, $ghImage, 0,0, $gCtlWid, $gCtlHt)
    If $ghPathFence<>0 Then
        _GDIPlus_GraphicsDrawPath($ghCanvas,$ghPathFence,$ghPenFence)
        _GDIPlus_GraphicsDrawLine($ghCanvas, $gX0, $gY0, $gX1, $gY1, $ghPen)
    EndIf
    _GDIPlus_GraphicsDrawImageRect($gGraphicPic, $ghBitmap, 0, 0, $imgWid, $imgHt)
EndFunc

Func WM_PAINT()
    _WinAPI_RedrawWindow($gForm1, 0, 0, $RDW_UPDATENOW)
    Paint()
    _WinAPI_RedrawWindow($gForm1, 0, 0, $RDW_VALIDATE)
EndFunc

Func Angle($y, $x) ;return value is in degrees
    Local Const $fPi = ACos(-1), $fPi2 = ACos(-1) / 2, $fRad = 180 / $fPi
    Switch True
        Case ($x > 0)
            Return ATan($y / $x) * $fRad
        Case ($x < 0 And $y >= 0)
            Return ATan($y / $x + $fPi) * $fRad
        Case ($x < 0 And $y < 0)
            Return ATan($y / $x - $fPi) * $fRad
        Case ($x = 0 And $y > 0)
            Return $fPi2 * $fRad
        Case ($x = 0 And $y < 0)
            Return -$fPi2 * $fRad
        Case ($x = 0 And $y = 0)
            Return 0
    EndSwitch
EndFunc

Func Min($a,$b)
    If $a<$b Then
        Return $a
    Else
        Return $b
    EndIf
EndFunc

This has been tested. Deskew notes.pdf (in Post 17) has been updated.

Edited by c.haslam
fixed small bug in code
Spoiler

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

 

Link to comment
Share on other sites

I need to save the cropped file to the original file specification. This is failing. The code below is one of my attempts. In this one, MsgBox() shows that FileDelete() is failing.

#include <ButtonConstants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
Opt('MustDeclareVars',1)

GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL")
GUIRegisterMsg($WM_PAINT,'WM_PAINT')

Global Const $gkOffsetFence=6
Global $gX0,$gX1,$gY0,$gY1,$gForm1,$glblPic,$gCtlWid,$gCtlHt,$imgWid,$imgHt
Global $ghCanvas,$ghImage,$ghPenLine,$gGraphicPic,$ghBitmap
Global $ghPathFence,$ghBrushFence,$ghPenFence

main()

Func main()
    _GDIPlus_Startup()
    Local $filspc ='H:\b\pergola - Copy.jpg'
    $ghImage = _GDIPlus_ImageLoadFromFile($filspc)
    $imgWid = _GDIPlus_ImageGetWidth($ghImage)
    $imgHt = _GDIPlus_ImageGetHeight($ghImage)
; Size GUI per image size
    If $imgWid<=@DesktopWidth-16 Then
        If $imgHt<=@DesktopHeight-150 Then  ; wid small, ht small
            $gCtlWid = $imgWid
            $gCtlHt = $imgHt
        Else                                ; wid small, ht big
            $gCtlHt = @DesktopHeight-150
            $gCtlWid = $gCtlHt*$imgWid/$imgHt
        EndIf
    Else
        If $imgHt<=@DesktopHeight-150 Then  ; wid big, ht small
            $gCtlWid = @DesktopWidth-16
            $gCtlHt = $gCtlWid*$imgHt/$imgWid
        Else                                ; wid big, ht big
            $gCtlWid = Min(@DesktopWidth-16,$imgWid)
            $gCtlHt = $gCtlWid*$imgHt/$imgWid
            If $gCtlHt>@DesktopHeight-150 Then
                $gCtlHt = @DesktopHeight-150
                $gCtlWid = $gCtlHt*$imgwid/$imgHt
            EndIf
        EndIf
    EndIf

    Local $widFrm = Max(8+282+30+49+15+41+15+57+8,8+$gCtlWid+8)
    $gForm1 = GUICreate("Deskew", $widFrm, $gCtlHt+70)
    Local $leftPic
    If $widFrm>$gCtlWid+16 Then
        $leftPic = ($widFrm-$gCtlWid)/2
    Else
        $leftPic = 8
    EndIf
    $glblPic = GUICtrlCreateLabel("", $leftPic, 8, $gCtlWid, $gCtlHt)
    GUICtrlCreateLabel('Move an end of the line by dragging the end',8,8+$gCtlHt+5)
    GUICtrlCreateLabel('Move the whole line by dragging it or with the mouse wheel',8,8+$gCtlHt+22,282)
    GUICtrlCreateLabel('Rotate the line with Shift + mouse wheel',8,8+$gCtlHt+39)
    Local $btnRotate = GUICtrlCreateButton("Rotate", $widFrm-8-57-15-41-15-49, 8+$gCtlHt+20, 49, 25)
    Local $btnOK = GUICtrlCreateButton("OK", $widFrm-8-57-15-41, 8+$gCtlHt+20, 41, 25)
    GUICtrlSetState(-1,$GUI_DISABLE)
    Local $btnCancel = GUICtrlCreateButton("Cancel", $widFrm-8-57, 8+$gCtlHt+20, 57, 25)
    GUISetState(@SW_SHOW)

    Local $oldY0,$oldY1

    $ghPenLine = _GDIPlus_PenCreate(0xFFFF0000,2)   ; red
    Local $hnd = GUICtrlGetHandle($glblPic)
    $gGraphicPic = _GDIPlus_GraphicsCreateFromHWND($hnd)
    $gX0 = 10
    $gX1 = $gCtlWid - 10
    $gY0 = $gCtlHt*3/4
    $gY1 = $gY0
    $ghBitmap = _GDIPlus_BitmapCreateFromScan0($imgWid, $imgHt)
    $ghCanvas = _GDIPlus_ImageGetGraphicsContext($ghBitmap)

    $ghPenFence = _GDIPlus_PenCreate(0x000000FF)    ; transparent
    $ghPathFence = _GDIPlus_PathCreate()
    $ghBrushFence = _GDIPlus_BrushCreateSolid(0xFF0000FF)

    While True
        If $gY0<>$oldY0 Or $gY1<>$oldY1 Then
            _GDIPlus_PathReset($ghPathFence)
            SetFence()
            Paint()
            $oldY0 = $gY0
            $oldY1 = $gY1
        Else
            Switch GUIGetMsg()
                Case $GUI_EVENT_CLOSE,$btnCancel
                    ExitLoop
                Case $btnRotate
                    Local $hImageClone=_GDIPlus_BitmapCreateFromScan0($imgWid, $imgHt)
                    Local $hGfxClone=_GDIPlus_ImageGetGraphicsContext($hImageClone)

                    ; rotate about centre
                    Local $matrix = _GDIPlus_MatrixCreate()
                    _GDIPlus_MatrixTranslate($matrix, $imgWid/2, $imgHt/2)
                    Local $deg = Angle($gY1-$gY0, $gX1-$gX0)
                    _GDIPlus_MatrixRotate($matrix, -$deg)
                    _GDIPlus_MatrixTranslate($matrix, -$imgWid/2, -$imgHt/2)
                    _GDIPlus_GraphicsSetTransform($hGfxClone, $matrix)
                    _GDIPlus_MatrixDispose($matrix)

                    _GDIPlus_GraphicsDrawImageRect($hGfxClone,$ghImage,0,0,$imgWid,$imgHt)
                    _GDIPlus_GraphicsDispose($hGfxClone)
                    $hGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImage)
                    ; See deskew notes document
                    Local $ang = Abs($deg*3.14159/180)
                    Local $cos = cos($ang), $sin = sin($ang), $tan = tan($ang)
                    Local $w2cos = $imgWid/2*$cos, $w2sin =  $imgWid/2*$sin
                    Local $h2cos = $imgHt/2*$cos, $h2sin = $imgHt/2*$sin
                    Local $nsrcX = ($imgHt/2 - $w2sin - $h2cos)*$tan - $w2cos + $h2sin + $imgWid/2
                    Local $nsrcY = ($imgWid/2 + $w2cos - $h2sin)*$tan - $w2sin - $h2cos + $imgHt/2

                    Local $nSrcWidth = $imgWid - 2*$nSrcX
                    Local $nSrcHeight = $imgHt - 2*$nSrcY
                    ; crop to screen, centering within control
                    _GDIPlus_GraphicsClear($hGfxClone,0xFFD4D0C8)   ; client area background colour
                    Local $nDstX = ($imgWid-$nSrcWidth)/2
                    Local $nDstY = ($imgHt-$nSrcHeight)/2
                    ; draw a portion of image object $hImageClone on the image that $hGfxClone points to
                    _GDIPlus_GraphicsDrawImageRectRect($hGfxClone,$hImageClone, _
                        $nSrcX,$nSrcY,$nSrcWidth,$nSrcHeight,$nDstX,$nDstY,$nSrcWidth,$nSrcHeight)
                    _GDIPlus_ImageDispose($hImageClone)
                    _GDIPlus_PathDispose($ghPathFence)
                    $ghPathFence = 0
                    Paint()
                    Local $hImageClone2 = _GDIPlus_BitmapCloneArea($ghImage,$nsrcX,$nsrcY,$nSrcWidth,$nSrcHeight)
                    MsgBox(0,'filedelete',FileDelete($filspc))
                    _GDIPlus_ImageSaveToFile($hImageClone2,$filspc)
                    _GDIPlus_ImageDispose($hImageClone2)
                    ShellExecute($filspc)
                    GUICtrlSetState($btnRotate,$GUI_DISABLE)
                    GUICtrlSetState($btnOK,$GUI_ENABLE)
           EndSwitch
        EndIf
        Local $cursVec = GUIGetCursorInfo($gForm1)
        ; if left mouse button is down and inside fence
        If $cursVec[2]=1 And _GDIPlus_PathIsVisiblePoint($ghPathFence,$cursVec[0]-$leftPic,$cursVec[1]-8) Then
            Local $x = $cursVec[0]-$leftPic  ; rel to control
            ; Formula for line
            Local $y = ($gy1-$gy0)/($gx1-$gx0)*($x-$gx0) + $gy0 + 8
            Opt('MouseCoordMode',2)     ; rel to client area
            MouseMove($x+$leftPic,$y)           ; move mouse to on the line, if not already there
            $cursVec[1] = $y
            Local $nuy0,$nuy1
            While $cursVec[2]=1 And $cursVec[4]=$glblPic    ; while primary button down
                $cursVec = GUIGetCursorInfo($gForm1)
                If $x<=$gx0+2*$gkOffsetFence Then
                    $nuY0 = $cursVec[1]-8
                    $nuy1 = $gy1
                ElseIf $x>=$gx1-2*$gkOffsetFence Then
                    $nuy0 = $gy0
                    $nuy1 = $cursVec[1]-8
                Else
                    Local $delta = $cursVec[1] -  $y
                    $nuy0 = $gy0 + $delta
                    $nuy1 = $gy1 + $delta
                    $y = $cursVec[1]
                EndIf
                ; Keep line and polygon within picture
                If $nuy0>$gkOffsetFence And $nuy0<$gCtlHt-$gkOffsetFence Then
                    $gy0 = $nuy0
                EndIf
                If $nuy1>$gkOffsetFence And $nuy1<$gCtlHt-$gkOffsetFence Then
                    $gy1 = $nuy1
                EndIf

               _GDIPlus_PathReset($ghPathFence)
                SetFence()
                Paint()
                Sleep(10)
            WEnd
        EndIf
    WEnd

    ; Clean up resources
    _GDIPlus_ImageDispose($ghCanvas)
    _GDIPlus_ImageDispose($ghImage)
    _GDIPlus_ImageDispose($ghBitmap)
    _GDIPlus_PenDispose($ghPenLine)
    _GDIPlus_GraphicsDispose($gGraphicPic)
    If $ghPathFence<>0 Then
        _GDIPlus_PathDispose($ghPathFence)
    EndIf
    _GDIPlus_Shutdown()
EndFunc

Func SetFence()
    Local $polyAr[5]
;       top-left, top-right, bot-right, bot-left
    Local $polyAr = [[4,0], _
        [$gx0-$gkOffsetFence,$gy0-$gkOffsetFence], _
        [$gx1+$gkOffsetFence,$gy1-$gkOffsetFence], _
        [$gx1+$gkOffsetFence,$gy1+$gkOffsetFence], _
        [$gx0-$gkOffsetFence,$gy0+$gkOffsetFence]]
    _GDIPlus_PathAddPolygon($ghPathFence,$polyAr)
    _GDIPlus_GraphicsFillPath($ghCanvas,$ghPathFence,$ghBrushFence)
EndFunc

Func WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam, $lParam
    Local Const $MK_SHIFT=0x4,$MK_CONTROL= 0x8
    Local Const $kYmax=$gCtlHt-$gkOffsetFence,$kDelta=2

    Local $vec = GUIGetCursorInfo($gForm1)
    If $vec[4]=$glblPic Then
        Local $iDelta = BitShift($wParam, 16)   ; positive = up
        Local $iKeys = _WinAPI_LoWord($wParam)
        If BitAND($iKeys,$MK_CONTROL)=$MK_CONTROL Then
            If BitAND($iKeys,$MK_SHIFT)=$MK_SHIFT Then
                ; do nothing
            Else
                If $iDelta > 0 And $gY0>$gkOffsetFence Then $gY0 -= $kDelta
                If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta
            EndIf
        Else
            If BitAND($iKeys,$MK_SHIFT)=$MK_SHIFT Then
                If $iDelta > 0 And $gY1>$gkOffsetFence Then $gY1 -= $kDelta
                If $iDelta < 0  And $gY1<$kYmax Then $gY1 += $kDelta
            Else
                If $iDelta > 0 And $gY0>$gkOffsetFence Then $gY0 -= $kDelta
                If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta
                If $iDelta > 0 And $gY1>$gkOffsetFence Then $gY1 -= $kDelta
                If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta
            EndIf
        EndIf
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_MOUSEWHEEL

Func Paint()
    _GDIPlus_GraphicsClear($ghCanvas,0)
    _GDIPlus_GraphicsDrawImageRect($ghCanvas, $ghImage, 0,0, $gCtlWid, $gCtlHt)
    If $ghPathFence<>0 Then
        _GDIPlus_GraphicsDrawPath($ghCanvas,$ghPathFence,$ghPenFence)
        _GDIPlus_GraphicsDrawLine($ghCanvas, $gX0, $gY0, $gX1, $gY1, $ghPenLine)
    EndIf
    _GDIPlus_GraphicsDrawImageRect($gGraphicPic, $ghBitmap, 0, 0, $imgWid, $imgHt)
EndFunc

Func WM_PAINT()
    _WinAPI_RedrawWindow($gForm1, 0, 0, $RDW_UPDATENOW)
    Paint()
    _WinAPI_RedrawWindow($gForm1, 0, 0, $RDW_VALIDATE)
EndFunc

Func Angle($y, $x) ;return value is in degrees
    Local Const $fPi = ACos(-1), $fPi2 = ACos(-1) / 2, $fRad = 180 / $fPi
    Switch True
        Case ($x > 0)
            Return ATan($y / $x) * $fRad
        Case ($x < 0 And $y >= 0)
            Return ATan($y / $x + $fPi) * $fRad
        Case ($x < 0 And $y < 0)
            Return ATan($y / $x - $fPi) * $fRad
        Case ($x = 0 And $y > 0)
            Return $fPi2 * $fRad
        Case ($x = 0 And $y < 0)
            Return -$fPi2 * $fRad
        Case ($x = 0 And $y = 0)
            Return 0
    EndSwitch
EndFunc

Func Min($a,$b)
    If $a<$b Then
        Return $a
    Else
        Return $b
    EndIf
EndFunc

Func Max($a,$b)
    If $a>$b Then
        Return $a
    Else
        Return $b
    EndIf
EndFunc

I even tried renaming to a temporary file name, shutting down GDI+, then moving the temporary file to the real file.

It seems that AutoIt has an exclusive hold on the file, and only releases the hold when the script finishes.

Any clues?

Spoiler

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

 

Link to comment
Share on other sites

The problem is that the file is locked by the load process. You have to release the handles first before you can overwrite it:

...
                    Local $hImageClone2 = _GDIPlus_BitmapCloneArea($ghImage,$nsrcX,$nsrcY,$nSrcWidth,$nSrcHeight)
                    _GDIPlus_GraphicsDispose($hGfxClone)
                    _GDIPlus_ImageDispose($ghImage)
                    MsgBox(0,'filedelete',FileDelete($filspc))
                    _GDIPlus_ImageSaveToFile($hImageClone2,$filspc)
                    _GDIPlus_ImageDispose($hImageClone2)
                    ShellExecute($filspc)
                    $ghImage = _GDIPlus_ImageLoadFromFile($filspc)
                    $hGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImage)
...

It will save your rotated image BUT your have to create the handles again otherwise CRASH.

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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

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

×
×
  • Create New...