c.haslam Posted October 17, 2017 Posted October 17, 2017 (edited) UEZ has kindly provided me with code that rotates an image per a line: see here Because I want to trim a photograph after rotation, I need to crop the photo. I wrote code which calls _GDIPlus_GraphicsSetClipRect() to do this, but it places spurious stuff in the corners: see 2.jpg attached. I want only the trimmed photo to show. The original jpeg is also attached. The arguments to _GDIPlus_GraphicsSetClipRect() come from solving 2 simultaneous equations: if a and b are the width and height of the original photo, find x and y, the width and height of the rotated and cropped rectangle; a = x cos(ang) + y sin(ang) b = x sin(ang) + y cos(ang) My solution is: x = (b * sin(ang) - a*cos(ang)) / (sin(ang)^2 - (cos(ang)^2) y = (b * cos(ang) - a * sin(ang)) / (cos(ang)^2 - sin(ang)^2) To try to get a handle on the problem, I have temporarily added in several lines in Case $btn. In 2.jpg, you can see that the rectangle bounding the area to be retained is in the wrong place. The code is: expandcollapse popup#include <ButtonConstants.au3> #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> Opt('MustDeclareVars',1) Global Const $MK_SHIFT = 0x4 Global Const $MK_CONTROL = 0x8 Global Const $fPi = ACos(-1), $fPi2 = $fPi / 2, $fRad = 180 / $fPi GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL") GUIRegisterMsg($WM_PAINT,'WM_PAINT') Global $gX0=10,$gX1=580,$gY0,$gY1,$gForm1,$glblPic,$iLW,$iLH,$iW,$iH Global $ghCanvas,$ghImage,$ghPen,$gGraphicPic,$ghBitmap,$ghMatrix,$ghImageClone,$ghGfxClone Global Const $kDegToRads = 3.14159/180 main() Func main() $gForm1 = GUICreate("Form1", 623, 601, 192, 114) $iLW = 589 $iLH = 500 $glblPic = GUICtrlCreateLabel("", 8, 8, $iLW, $iLH) Local $btn = GUICtrlCreateButton("Rotate", 472, 560, 65, 25) GUISetState(@SW_SHOW) Local $oldY0,$oldY1,$fAngle _GDIPlus_Startup() $ghPen = _GDIPlus_PenCreate(0xFF999999,2) $ghImage = _GDIPlus_ImageLoadFromFile('H:\b\pergola.jpg') Local $h = GUICtrlGetHandle($glblPic) $gGraphicPic = _GDIPlus_GraphicsCreateFromHWND($h) $gY0 = 400 $gY1 = 400 $iW = _GDIPlus_ImageGetWidth($ghImage) $iH = _GDIPlus_ImageGetHeight($ghImage) $ghBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH) $ghCanvas = _GDIPlus_ImageGetGraphicsContext($ghBitmap) $ghMatrix = _GDIPlus_MatrixCreate() ; 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 ExitLoop Case $btn $ghImageClone=_GDIPlus_BitmapCreateFromScan0($iW, $iH) $ghGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImageClone) _GDIPlus_MatrixTranslate($ghMatrix, $iW/2, $iH/2) $gY1 = 300 ; temp Local $ang = -Angle($gY1-$gY0, $gX1-$gX0) _GDIPlus_MatrixRotate($ghMatrix, $ang) ;~ _GDIPlus_MatrixRotate($ghMatrix, -Angle($gY1-$gY0, $gX1-$gX0)) _GDIPlus_MatrixTranslate($ghMatrix, -$iW/2, -$iH/2) _GDIPlus_GraphicsSetTransform($ghGfxClone, $ghMatrix) _GDIPlus_GraphicsDrawImageRect($ghGfxClone,$ghImage,0,0,$iW,$iH) Local $angRads = $ang*$kDegToRads Local $sinAng = Sin($angRads) Local $cosAng = Cos($angRads) Local $wid = ($iLH*$sinAng-$iLW*$cosAng)/($sinAng^2-$cosAng^2) Local $left = ($iLW-$wid)/2 Local $ht = ($iLH*$cosAng-$iLW*$sinAng)/($cosAng^2-$sinAng^2) Local $top = ($iLH-$ht)/2 _GDIPlus_GraphicsDrawRect($ghGfxClone,$left,$top,$wid,$ht,$ghPen) ; temp _GDIPlus_GraphicsSetClipRect($ghGfxClone,$left,$top,$wid,$ht,0) _GDIPlus_GraphicsDispose($ghGfxClone) $ghGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImage) _GDIPlus_GraphicsClear($ghImage) _GDIPlus_GraphicsDrawImageRect($ghGfxClone,$ghImageClone,0,0,$iW,$iH) _GDIPlus_GraphicsDispose($ghGfxClone) _GDIPlus_ImageDispose($ghImageClone) $gy0 = 400 $gy1 = 400 Paint() _GDIPlus_ImageSaveToFile($ghImage,'H:\b\2.jpg') ; added - is rotated, with same size as original file EndSwitch EndIf WEnd ; Clean up resources _GDIPlus_MatrixDispose($ghMatrix) _GDIPlus_ImageDispose($ghCanvas) _GDIPlus_ImageDispose($ghImage) _GDIPlus_ImageDispose($ghBitmap) _GDIPlus_PenDispose($ghPen) _GDIPlus_GraphicsDispose($gGraphicPic) _GDIPlus_Shutdown() EndFunc Func WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam Local Const $kYmax=$iLH-1,$kDelta=2 Local $vec = GUIGetCursorInfo($gForm1) If $vec[4] = $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>3 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>3 Then $gY1 -= $kDelta If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta Else If $iDelta > 0 And $gY0>3 Then $gY0 -= $kDelta If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta If $iDelta > 0 And $gY1>3 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, $iLW, $iLH) _GDIPlus_GraphicsDrawLine($ghCanvas, $gX0, $gY0, $gX1, $gY1, $ghPen) _GDIPlus_GraphicsDrawImageRect($gGraphicPic, $ghBitmap, 0, 0, $iW, $iH) 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 I also don't understand how the rotated picture gets displayed. There are graphics objects, graphics contexts and PDI+ bitmaps. How are they related? Help would be much appreciated. Edited November 17, 2017 by c.haslam Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
SlackerAl Posted October 17, 2017 Posted October 17, 2017 There appears to be a useful discussion of this problem and a js solution here calculate-largest-rectangle-in-a-rotated-rectangle perhaps it is worth checking out? Problem solving step 1: Write a simple, self-contained, running, replicator of your problem.
c.haslam Posted October 17, 2017 Author Posted October 17, 2017 (edited) Thank you for the link. I have already studied that one carefully. It didn't help, perhaps because I don't know JS. I think my basic problem may be not understanding how GD+ works with graphics objects, graphics contexts and PDI+ bitmaps. MSDN hasn't helped either. Edited October 17, 2017 by c.haslam Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
UEZ Posted October 17, 2017 Posted October 17, 2017 You mean something like this here? expandcollapse popup#include <ButtonConstants.au3> #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> Opt('MustDeclareVars',1) Global Const $MK_SHIFT = 0x4 Global Const $MK_CONTROL = 0x8 Global Const $fPi = ACos(-1), $fPi2 = $fPi / 2, $fRad = 180 / $fPi GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL") GUIRegisterMsg($WM_PAINT,'WM_PAINT') Global $gX0,$gX1,$gY0,$gY1,$gForm1,$glblPic,$iW,$iH Global $ghCanvas,$ghImage,$ghPen,$gGraphicPic,$ghBitmap,$ghMatrix,$ghImageClone,$ghGfxClone,$ghImageCropped main() Func main() Local $oldY0,$oldY1,$fAngle _GDIPlus_Startup() $ghPen = _GDIPlus_PenCreate(0xFF000000,2) $ghImage = _GDIPlus_ImageLoadFromFile('pergola.jpg') $iW = _GDIPlus_ImageGetWidth($ghImage) $iH = _GDIPlus_ImageGetHeight($ghImage) $gX0=10 $gX1=$iW-10 $gForm1 = GUICreate("Form1", $iW + 16, $iH + 50) $glblPic = GUICtrlCreateLabel("", 8, 8, $iW, $iH) Local $btn = GUICtrlCreateButton("Rotate", $iW - 100, $iH + 20, 65, 25) GUISetState(@SW_SHOW) Local $h = GUICtrlGetHandle($glblPic) $gGraphicPic = _GDIPlus_GraphicsCreateFromHWND($h) $gY0 = $iH / 2 + 100 $gY1 = $iH / 2 - 90 $ghBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH) $ghCanvas = _GDIPlus_ImageGetGraphicsContext($ghBitmap) $ghMatrix = _GDIPlus_MatrixCreate() ; 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 ExitLoop Case $btn $ghImageClone=_GDIPlus_BitmapCreateFromScan0($iW, $iH) $ghGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImageClone) _GDIPlus_MatrixTranslate($ghMatrix, $iW/2, $iH/2) _GDIPlus_MatrixRotate($ghMatrix, -Angle($gY1-$gY0, $gX1-$gX0)) _GDIPlus_MatrixTranslate($ghMatrix, -$iW/2, -$iH/2) _GDIPlus_GraphicsSetTransform($ghGfxClone, $ghMatrix) _GDIPlus_GraphicsDrawImageRect($ghGfxClone,$ghImage,0,0,$iW,$iH) _GDIPlus_GraphicsDispose($ghGfxClone) $ghGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImage) _GDIPlus_GraphicsClear($ghGfxClone) _GDIPlus_GraphicsClear($ghImage) _GDIPlus_GraphicsDrawImageRect($ghGfxClone,$ghImageClone,0,0,$iW,$iH) _GDIPlus_GraphicsDispose($ghGfxClone) $gY0 = $iH / 2 $gY1 = $iH / 2 Paint() $ghImageCropped=_GDIPlus_BitmapCloneArea($ghImageClone,120,66,745,403) _GDIPlus_ImageDispose($ghImageClone) _GDIPlus_ImageSaveToFile($ghImageCropped, @ScriptDir & "\pergola_RnC.jpg") _GDIPlus_ImageDispose($ghImageCropped) ShellExecute(@ScriptDir & "\pergola_RnC.jpg") EndSwitch EndIf WEnd ; Clean up resources _GDIPlus_MatrixDispose($ghMatrix) _GDIPlus_ImageDispose($ghCanvas) _GDIPlus_ImageDispose($ghImage) _GDIPlus_ImageDispose($ghBitmap) _GDIPlus_PenDispose($ghPen) _GDIPlus_GraphicsDispose($gGraphicPic) _GDIPlus_Shutdown() EndFunc Func WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam Local Const $kYmax=$iH-1,$kDelta=2 Local $vec = GUIGetCursorInfo($gForm1) If $vec[4] = $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>3 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>3 Then $gY1 -= $kDelta If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta Else If $iDelta > 0 And $gY0>3 Then $gY0 -= $kDelta If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta If $iDelta > 0 And $gY1>3 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, $iW, $iH) _GDIPlus_GraphicsDrawLine($ghCanvas, $gX0, $gY0, $gX1, $gY1, $ghPen) _GDIPlus_GraphicsDrawImageRect($gGraphicPic, $ghBitmap, 0, 0, $iW, $iH) 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 $x 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 I need to think about an automatic crop solution... Danyfirex 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 October 17, 2017 Author Posted October 17, 2017 (edited) UEZ, thanks. Unfortunately, pergola.jpg shows full screen, because your code makes $lblPiC the size of the jpeg, which is 2557x1374. The Rotate button is way of-screen. I look forward to the result of your endeavors, I won't have time to visit the forum for a few days. Edited October 22, 2017 by c.haslam fixed typo Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
c.haslam Posted October 22, 2017 Author Posted October 22, 2017 (edited) UEZ, I have purposely rotated by much more than what happens in real life: in this sample, the camera was held about 10 degrees off level; in my experience, 3 degrees is as much off as I have seen. It does, however, show that I am looking at the problem wrongly geometrically and algebraically! I need to do some more head-scratching to figure out what is going on. My original idea was to improve on the way Irfanview de-skews a photo: it has the user enter the angle as a number; I would like to get a better result by the user rotating a line. Here is what Irfanview does with 10 degree rotation. Irfanview's result is too small to be useful -- another reason why I have undertaken this project! Neither is what I want to do. I have been trying to do the "change .. size' option, but I now realize that I need to do IV's "keep ... size" option, then crop to get rid of the 4 corner triangles, by cropping. Hope this makes sense. (Onlt the first 2 images in this post apply. I can't delete the third, erroneous, one.) Edited October 22, 2017 by c.haslam Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
UEZ Posted October 22, 2017 Posted October 22, 2017 I would do it this way: Create a large preview window of the image with a slider from -360 to 360 degrees which the user can use to rotate the image Have a horizontal movable line over the image to have an orientation Use mouse wheel to zoom the image A checkbox with the open to keep original image as background 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 October 24, 2017 Author Posted October 24, 2017 I don't see a need to rotate the image more than about 10 degrees. For the Photos I take, there is some feature that should be horizontal: in the case of the image I am testing with, it is the edge of the pool. More typically, the feature is near the bottom of the picture. I have been thinking about the image Irfanview produces when Keep the original image/canvas size is checked. I would be happy if a way can be found to replace the erroneous corner triangles with black (or the background colour AutoIt uses in a dialog box). Then the script would then show a crop rectangle on the image. This rectangle would initially have as its (left, bottom) the mid point of the hypotenuse of the lower left triangle, and as its (top, right) the mid point of the hypotenuse of the upper right triangle. (This is based on the image I used in Irfanview, i.e. landscape with clockwise rotation). The script would allow the user to change the size of the rectangle, by dragging the edges, constrained by the corner triangles. The user would then click on a Crop button to define the cropped image. Does this make sense? Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
UEZ Posted October 24, 2017 Posted October 24, 2017 I don't get it with the corner issue you have. When you rotate the image then you will get automatically the black triangle corners. Or do you mean after rotation to zoom in the image that you cannot see any black triangle corner? 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 October 26, 2017 Author Posted October 26, 2017 If you look at the second image in Post #1, at the top right corner, you can see lattice on an angle. and part of the top of the fence: in a triangle. This triangle should be solid black. I also see triangles in the other 3 corners. They too should be black. Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
UEZ Posted October 26, 2017 Posted October 26, 2017 The code in post#4 is exactly producing the image with the black corners! What you have to do is to remove the cropping (zoom in to avoid the black corners). 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 October 29, 2017 Author Posted October 29, 2017 It occurs to me that whether the corners are black or bits of the un-rotated image are irrelevant, because they will be cropped out. So the question is: how to crop the triangles? SlackerAl, in Post #2, gives a link to a thread on stackoverflow. The post in that thread posted Feb 8 '14 at 21:17 contains code that apparently crops, yielding maximum area: CropRotatedDimensionsForMaxArea[{w_, h_}, alpha_] := With[ {phi = Abs@Mod[alpha, Pi, -Pi/2]}, Which[ w == h, {w,h} Csc[phi + Pi/4]/Sqrt[2], w > h, If[ Cos[2 phi]^2 < 1 - (h/w)^2, h/2 {Csc[phi], Sec[phi]}, Sec[2 phi] {w Cos[phi] - h Sin[phi], h Cos[phi] - w Sin[phi]}], w < h, If[ Cos[2 phi]^2 < 1 - (w/h)^2, w/2 {Sec[phi], Csc[phi]}, Sec[2 phi] {w Cos[phi] - h Sin[phi], h Cos[phi] - w Sin[phi]}] ] ] I don't understand the code. Perhaps someone would help me by translating this into AutoIt code. Or perhaps other code in that thread would work. 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 14, 2017 Author Posted November 14, 2017 (edited) In Post 4, I see _GDIPlus_GraphicsClear($ghImage) but the Help says that the parameter should be a graphics object. $ghImage is an image object. Is this why the corner triangles are not black? I have made some progress on auto-cropping, but have not tested it yet. Edited November 14, 2017 by c.haslam Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
UEZ Posted November 14, 2017 Posted November 14, 2017 3 hours ago, c.haslam said: In Post 4, I see _GDIPlus_GraphicsClear($ghImage) but the Help says that the parameter should be a graphics object. $ghImage is an image object. Is this why the corner triangles are not black? I have made some progress on auto-cropping, but have not tested it yet. You are right, this line is obsolete and can be deleted. The line above (_GDIPlus_GraphicsClear($ghGfxClone)) clears the canvas so that the cornes get black. If you comment the line out you will see the difference. 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
SlackerAl Posted November 15, 2017 Posted November 15, 2017 On 10/29/2017 at 6:48 PM, c.haslam said: Post #2: I don't understand the code. Perhaps someone would help me by translating this into AutoIt code. Or perhaps other code in that thread would work. I'm sorry, but I do not have time to look at this for some time, perhaps someone else can help? If not I will try to get to it, but it may be a few weeks. Problem solving step 1: Write a simple, self-contained, running, replicator of your problem.
c.haslam Posted November 15, 2017 Author Posted November 15, 2017 SlackerAl, I am not sure, but I do think, that translating the code in Post #2 may no longer be needed. My current approach is: Determine the formulae for the corners of the rotated image Determine the equations for each of the sides of the rotated image Determine the points where the sides of the rotated image intercept the sides of the frame (un-rotated image) Crop the rotated image to be within horizontal and vertical lines drawn through these points, with the lines chosen to maximize the cropped image. This is the outline of the approach. The devil is in the details! I have this working on paper (with manually drawn diagram/graph). I am still battling which intercept points between sides of the frame and sides of the rotated image are the correct pairs. I think I know, but getting the signs in the equations right is taking time. I am making stupid errors! 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 17, 2017 Author Posted November 17, 2017 (edited) My code, based on UEZ's code, is below. It works! 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 $gX0=10,$gX1=580,$gY0,$gY1,$gForm1,$glblPic,$gCtlWid,$gCtlHt,$imgWid,$imgHt Global $ghCanvas,$ghImage,$ghPen,$gGraphicPic,$ghBitmap 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(0xFF999999,2) $ghImage = _GDIPlus_ImageLoadFromFile('H:\b\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) ; 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 Local $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_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 WEnd ; Clean up resources _GDIPlus_MatrixDispose($gMatrix) _GDIPlus_ImageDispose($ghCanvas) _GDIPlus_ImageDispose($ghImage) _GDIPlus_ImageDispose($ghBitmap) _GDIPlus_PenDispose($ghPen) _GDIPlus_GraphicsDispose($gGraphicPic) _GDIPlus_Shutdown() 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-1,$kDelta=2 Local $vec = GUIGetCursorInfo($gForm1) If $vec[4] = $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>3 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>3 Then $gY1 -= $kDelta If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta Else If $iDelta > 0 And $gY0>3 Then $gY0 -= $kDelta If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta If $iDelta > 0 And $gY1>3 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) _GDIPlus_GraphicsDrawLine($ghCanvas, $gX0, $gY0, $gX1, $gY1, $ghPen) _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 I am attaching my derivation of the formulas used for cropping. Thank you to all who have posted GDI+ stuff on the forum. I still do not fully understand how graphics objects / graphic contexts work, so helpful hints would be appreciated! Suggestions for improvements are most welcome. Deskew notes.pdf Edited November 26, 2017 by c.haslam Update Deskew notes.pdf Spoiler CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard
UEZ Posted November 17, 2017 Posted November 17, 2017 @c.haslam now I got your point with the edges - probably my fault because of lack of language knowledge. But I assumed already in post#11 what you want: On 10/26/2017 at 2:51 PM, UEZ said: What you have to do is to remove the cropping (zoom in to avoid the black corners). Anyhow, good work: 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
UEZ Posted November 17, 2017 Posted November 17, 2017 (edited) 12 hours ago, c.haslam said: Suggestions for improvements are most welcome. I wouldn't say it is an improvement rather another (brute-force) way to get the best crop area (the aspect ratio of the original image is kept!) for the image after rotation whereas the corners are black (0x00000000). expandcollapse popup#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> Opt('MustDeclareVars',1) Global Const $MK_SHIFT = 0x4 Global Const $MK_CONTROL = 0x8 Global Const $fPi = ACos(-1), $fPi2 = $fPi / 2, $fRad = 180 / $fPi GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL") GUIRegisterMsg($WM_PAINT,'WM_PAINT') Global $gX0,$gX1,$gY0,$gY1,$gForm1,$glblPic,$iW,$iH Global $ghCanvas,$ghImage,$ghPen,$gGraphicPic,$ghBitmap,$ghMatrix,$ghImageClone,$ghGfxClone,$ghImageCropped main() Func main() Local $oldY0,$oldY1,$fAngle,$aPos _GDIPlus_Startup() $ghPen = _GDIPlus_PenCreate(0xFFFF0000,2) $ghImage = _GDIPlus_ImageLoadFromFile('pergola.jpg') $iW = _GDIPlus_ImageGetWidth($ghImage) $iH = _GDIPlus_ImageGetHeight($ghImage) $gX0=10 $gX1=$iW-10 $gForm1 = GUICreate("Form1", $iW + 16, $iH + 50) $glblPic = GUICtrlCreateLabel("", 8, 8, $iW, $iH) Local $btn = GUICtrlCreateButton("Rotate", $iW - 100, $iH + 20, 65, 25) GUISetState(@SW_SHOW) Local $h = GUICtrlGetHandle($glblPic) $gGraphicPic = _GDIPlus_GraphicsCreateFromHWND($h) $gY0 = $iH / 2 + 100 $gY1 = $iH / 2 - 90 $ghBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH) $ghCanvas = _GDIPlus_ImageGetGraphicsContext($ghBitmap) $ghMatrix = _GDIPlus_MatrixCreate() ; 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 ExitLoop Case $btn $ghImageClone=_GDIPlus_BitmapCreateFromScan0($iW, $iH) $ghGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImageClone) _GDIPlus_MatrixTranslate($ghMatrix, $iW/2, $iH/2) _GDIPlus_MatrixRotate($ghMatrix, -Angle($gY1-$gY0, $gX1-$gX0)) _GDIPlus_MatrixTranslate($ghMatrix, -$iW/2, -$iH/2) _GDIPlus_GraphicsSetTransform($ghGfxClone, $ghMatrix) _GDIPlus_GraphicsDrawImageRect($ghGfxClone,$ghImage,0,0,$iW,$iH) _GDIPlus_GraphicsDispose($ghGfxClone) $ghGfxClone=_GDIPlus_ImageGetGraphicsContext($ghImage) _GDIPlus_GraphicsClear($ghGfxClone) _GDIPlus_GraphicsClear($ghImage) _GDIPlus_GraphicsDrawImageRect($ghGfxClone,$ghImageClone,0,0,$iW,$iH) _GDIPlus_GraphicsDispose($ghGfxClone) $gY0 = $iH / 2 $gY1 = $iH / 2 Paint() $aPos = GetBestCropArea($ghImageClone) $ghImageCropped=_GDIPlus_BitmapCloneArea($ghImageClone,$aPos[0],$aPos[1],$aPos[2],$aPos[3]) _GDIPlus_ImageDispose($ghImageClone) _GDIPlus_ImageSaveToFile($ghImageCropped, @ScriptDir & "\pergola_RnC.jpg") _GDIPlus_ImageDispose($ghImageCropped) ShellExecute(@ScriptDir & "\pergola_RnC.jpg") EndSwitch EndIf WEnd ; Clean up resources _GDIPlus_MatrixDispose($ghMatrix) _GDIPlus_ImageDispose($ghCanvas) _GDIPlus_ImageDispose($ghImage) _GDIPlus_ImageDispose($ghBitmap) _GDIPlus_PenDispose($ghPen) _GDIPlus_GraphicsDispose($gGraphicPic) _GDIPlus_Shutdown() EndFunc Func WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam Local Const $kYmax=$iH-1,$kDelta=2 Local $vec = GUIGetCursorInfo($gForm1) If $vec[4] = $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>3 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>3 Then $gY1 -= $kDelta If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta Else If $iDelta > 0 And $gY0>3 Then $gY0 -= $kDelta If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta If $iDelta > 0 And $gY1>3 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, $iW, $iH) _GDIPlus_GraphicsDrawLine($ghCanvas, $gX0, $gY0, $gX1, $gY1, $ghPen) _GDIPlus_GraphicsDrawImageRect($gGraphicPic, $ghBitmap, 0, 0, $iW, $iH) 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 $x 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 GetBestCropArea($hImage) ;not speed optimized! Local $iW = _GDIPlus_ImageGetWidth($hImage), $iH = _GDIPlus_ImageGetHeight($hImage), $fRatio = $iW / $iH, $fCenterX = $iW / 2, $fCenterY = $iH / 2 Local $fPosX, $fPosY, $fW, $fH, $iPixel1, $iPixel2 For $x = $iW To 0 Step -1 $fPosX = $fCenterX - $x / 2 $fPosY = $fCenterY - ($x / 2) / $fRatio $fW = $x $fH = $x / $fRatio $iPixel1 = _GDIPlus_BitmapGetPixel($hImage, $fPosX, $fPosY) $iPixel2 = _GDIPlus_BitmapGetPixel($hImage, $fPosX + $fW, $fPosY) If $iPixel1 And $iPixel2 Then ExitLoop Next If Not $x Then Return SetError(1, 0, 0) Local $aPos[4] = [$fPosX, $fPosY, $fW, $fH] Return $aPos EndFunc Edited November 17, 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 18, 2017 Author Posted November 18, 2017 Your approach is surprisingly performant, given that it has a for loop that is executed many times. 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. In order to run your code, I ran it on a 1024x768 version of pergola.jpg; otherwise on my 1920x1024 monitor, the Rotate button was off screen. I have revisited my code, improving the time it takes to do the cropping. While it was recreating the control, it now adds borders to the displayed version, the borders being the colour of the client-area background. What was taking about 130 msec snow takes about 36. Also, there is now no flicker. The script, with the new code, is below: 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 $gX0=10,$gX1=580,$gY0,$gY1,$gForm1,$glblPic,$gCtlWid,$gCtlHt,$imgWid,$imgHt Global $ghCanvas,$ghImage,$ghPen,$gGraphicPic,$ghBitmap 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(0xFF999999,2) $ghImage = _GDIPlus_ImageLoadFromFile('H:\b\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) ; 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 Local $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_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 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 WEnd ; Clean up resources _GDIPlus_MatrixDispose($gMatrix) _GDIPlus_ImageDispose($ghCanvas) _GDIPlus_ImageDispose($ghImage) _GDIPlus_ImageDispose($ghBitmap) _GDIPlus_PenDispose($ghPen) _GDIPlus_GraphicsDispose($gGraphicPic) _GDIPlus_Shutdown() 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-1,$kDelta=2 Local $vec = GUIGetCursorInfo($gForm1) If $vec[4] = $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>3 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>3 Then $gY1 -= $kDelta If $iDelta < 0 And $gY1<$kYmax Then $gY1 += $kDelta Else If $iDelta > 0 And $gY0>3 Then $gY0 -= $kDelta If $iDelta < 0 And $gY0<$kYmax Then $gY0 += $kDelta If $iDelta > 0 And $gY1>3 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) _GDIPlus_GraphicsDrawLine($ghCanvas, $gX0, $gY0, $gX1, $gY1, $ghPen) _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 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