UEZ Posted November 18, 2017 Posted November 18, 2017 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! 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
c.haslam Posted November 19, 2017 Author Posted November 19, 2017 It is about 50 years since I last did linear algebra. Earthshine 1 Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
Earthshine Posted November 19, 2017 Posted November 19, 2017 30 some years for me My resources are limited. You must ask the right questions
argumentum Posted November 19, 2017 Posted November 19, 2017 17 hours ago, c.haslam said: linear algebra ...algebra, what is "algebra" ????? =P Earthshine 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Earthshine Posted November 20, 2017 Posted November 20, 2017 linear algebra isn't the algebra you learn in 8th grade... lol argumentum 1 My resources are limited. You must ask the right questions
argumentum Posted November 20, 2017 Posted November 20, 2017 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. Earthshine 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
c.haslam Posted November 22, 2017 Author Posted November 22, 2017 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: Moving the mouse up and down with the left button depressed when the cursor is in the picture moves the line 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
UEZ Posted November 22, 2017 Posted November 22, 2017 (edited) Try something like this here. expandcollapse popup#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 November 22, 2017 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
c.haslam Posted November 23, 2017 Author Posted November 23, 2017 Thanks. I will play with it. Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
c.haslam Posted November 23, 2017 Author Posted November 23, 2017 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
c.haslam Posted November 26, 2017 Author Posted November 26, 2017 (edited) 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: expandcollapse popup#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 November 27, 2017 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
c.haslam Posted November 28, 2017 Author Posted November 28, 2017 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. expandcollapse popup#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
UEZ Posted November 28, 2017 Posted November 28, 2017 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. Earthshine 1 Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
c.haslam Posted November 28, 2017 Author Posted November 28, 2017 Thank you. Your solution works. I would never have guessed! Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now