Jump to content
Sign in to follow this  
c.haslam

GDI+: Clipping fails after rotation

Recommended Posts

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:

#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.

pergola.jpg

2.jpg

Edited by c.haslam

Spoiler

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

 

Share this post


Link to post
Share on other sites

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 by c.haslam

Spoiler

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

 

Share this post


Link to post
Share on other sites

You mean something like this here?

#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...


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

UEZ, 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 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

 

Share this post


Link to post
Share on other sites

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!pergola IV change size.jpg

 

pergola IV change size.jpgpergola IV keep size.jpg

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.)

pergola IV keep size.jpg

Edited by c.haslam

Spoiler

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

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

 

Share this post


Link to post
Share on other sites

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 by c.haslam

Spoiler

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

 

Share this post


Link to post
Share on other sites
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!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

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

 

Share this post


Link to post
Share on other sites

My code, based on UEZ's code, is below. It works!

#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 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

 

Share this post


Link to post
Share on other sites

@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: :thumbsup:


Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
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).

#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 by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites

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:

#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

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By UEZ
      This project has been discontinued!
       
      Here a small tool I wrote to update my Sysinternal tools collection without the need to download always the whole package or visiting the site to check for updates. I know that there are several tools available (also some tools written in AutoIt) but here another one for the collection. It was good exercise for me to code it.
       
       
        
       
       
      Some files from the live web site cannot be downloaded although they are visible!
       
      Here the download link of the source code only: AutoIt Sysinternal Tools Synchronizer v0.99.6 build 2020-09-23 beta.7z  (1557 downloads previously)
      -=> Requires AutoIt version 3.3.13.20 or higher / tested on Win8.1 real machine and some VMs: Win7 / Vista / Win10
       
      Compiled exe only: @MediaFire
       
      Just select the Sysinternal Tools folder or create one and press the synchronize button to download the selected items. Click on AutoIt label (near to left upper corner) to open menu.
       
      Special thanks to LarsJ, Melba23 and mesale0077 for their help. 
       
      I've still some ideas to implement which are more gimmick related, so it is not finished yet...
      If you want to add your language please check out #Region Language. Thanks. 
       
      Please report any bug or if you have any suggestions.
       
      The language of the tool tip from each of the executable in the left list view were automatically created using Google translator and weren't checked for correctness.
       
      Br,
      UEZ
    • By Chimp
      2020/08/16 New Version
      I've made some changes and fixes to this function:
      I added the possibility to vary both the thickness of the selector and its color.
      to customize the appearance and behavior of the tool, you can change the values of some variables in the function listing. See comments on lines 140-170
      You can also vary the look of the border by setting a custom dash/space length pattern. Thanks to @UEZ for that. See here for reference.
      Hope it is free of bugs.
      (i don't know how to test it to see if it is also DPI aware??)
      Suggestions for improvements and bug reports are welcome.
      How to use this demo of use:
      hit Ctrl+PrintScreen to activate the tool LeftClick and drag on the borders of the tool to resize the area you can also Leftclick and drag within the area to move it around RightClick within the area to shot a screenshot of only the delimited area to the clipboard.
      in short "how to use the function" outside this demo in your programs:
      including the following 4 standard udf
      #include <Windowsconstants.au3>
      #include <WinAPISys.au3>
      #include <Misc.au3>
      #include <GDIPlus.au3>
      and pasting the _Crop function in your listing is all what you need, then: call the _Crop() function; the 'selector' appears around the mouse
      hovering  the mouse over any side or corner the cursor should change accordingly; LeftClick on the edges and drag to redim the area, also LeftClick within the area and drag to move the selection around. When you are done with the selection, RightClick within the area or also hit the ESC key,
      the 4 element 1D array is returned to the caller and the 'selector' disappears from the screen Thank you
      ... below original post ...
      A function that allows you to freely and visually select an area of the screen
      Yes I know, there are already some in the forum, however here is yet another cropping tool.
      I collected some snippets from the forum and merged in a simple and quick cropping tool implemented as a single standalone function.
      The _Crop() function simply returns a 4-element 1D array with the x-y coordinates of the upper left and the width and height of the selected area, respectively in the elements [0] [1] [2] [3]. So it's up to you to make good use of these parameters
      An example of use:
      Since Windows already has both a screenprint functionkey to copy the whole screen to the clipboard and the Alt-printscreen shortkut to copy only the active window to the clipboard, I'm goinmg to bind this _crop() function combined with the Control-printscreen hotkey to create a "partial" screenshot of the delimited area of the screen. The captured screenshot of that area is copied to the clipboard, so you can paste it wherever you want.
      How to use it:
      after running the script, use the Control+Printscreen keys to activate the crop tool that appears around the mouse position; then use the mouse to visually resize and move the area and when you have delimited the desired area click with the right mouse button inside the area to copy it to the clipboard.
      Suggestions, improvements and finally error reports are welcome
      Happy cropping
      #AutoIt3Wrapper_Res_HiDpi=y #include <Windowsconstants.au3> #include <WinAPISys.au3> #include <Misc.au3> #include <GDIPlus.au3> ; ---------------------- ; -- Demo start -------- ; ---------------------- #include <ScreenCapture.au3> ; needed only for this demo #include <Clipboard.au3> ; needed only for this demo Global $user32 = DllOpen("user32.dll") While 1 ; hit Control+Printscreen to call the _Crop Function If _IsPressed("11", $user32) And _IsPressed("2C", $user32) Then _example() ; 11 CTRL key + 2C PRINTSCREEN key ; hit Control + c to exit this script (can be castomized with other keys) If _IsPressed("11", $user32) And _IsPressed("43", $user32) Then ExitLoop ; 11 CTRL key + 43 C key Sleep(150) WEnd DllClose($user32) TrayTip("Crop demo", "End of the 'TSR' crop demo", 3, 1) ; (1) = Info icon Sleep(3000) Exit Func _example() $aRect = _Crop() ; mark the area If Not @extended Then ; if the ESC key was pressed within the _Crop function the @extended is set to 1 Local $hGui = GUICreate("", $aRect[2], $aRect[3], $aRect[0] - 1, $aRect[1] - 1, $WS_POPUPWINDOW) Local $idPic = GUICtrlCreatePic('', 0, 0, $aRect[2], $aRect[3]) Local $hBmp = _ScreenCapture_Capture('', $aRect[0], $aRect[1], $aRect[0] + $aRect[2] - 1, $aRect[1] + $aRect[3] - 1, False) Local $iMidX = $aRect[0] + $aRect[2] / 2 Local $iMidY = $aRect[1] + $aRect[3] / 2 ; snippet by UEZ ; https://www.autoitscript.com/forum/topic/129333-screen-capture-to-clipboard/?do=findComment&comment=898287 Local $bResult = _ClipBoard_Open(0) + _ClipBoard_Empty() + Not _ClipBoard_SetDataEx($hBmp, $CF_BITMAP) _ClipBoard_Close() If $bResult = 2 Then ToolTip("the area was copied to the clipboard", $iMidX, $iMidY, 'Info', 1, 6) Else ToolTip("Something went wrong", $iMidX, $iMidY, 'Error', 3, 6) EndIf ; snippet by Malkey ; https://www.autoitscript.com/forum/topic/191425-capturing-image-without-saving/?do=findComment&comment=1373088 Local $STM_SETIMAGE = 0x0172 GUICtrlSendMsg($idPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hBmp) _WinAPI_DeleteObject($hBmp) GUISetState() DllCall("User32.dll", "int", "AnimateWindow", "hwnd", $hGui, "int", 750, "long", "0x00050002") ; Right-Left GUIDelete($hGui) Sleep(250) ToolTip('') EndIf EndFunc ;==>_example ; ---------------------- ; -- Demo end ---------- ; ---------------------- ; #FUNCTION# ==================================================================================================================== ; Name ..........: _Crop ; Description ...: A function that allows you to freely and visually select an area of the screen ; Syntax ........: _Crop([$i_X = Default[, $i_Y = Default[, $i_W = Default[, $i_H = Default[, $iMinW = -1[, $iMaxW = -1[, ; $iMinH = -1[, $iMaxH = -1]]]]]]]]) ; ; - To resize the area click the left mouse button and drag on any of the moving colored edges of the tool. ; You can also LeftClick within the selected area and drag to move the whole selection. ; ; - To terminate the selection operation RightClick within the selected area. ; ; You can alse terminate the selection operation by hitting the ESC key; ; in that case the @extended macro will be setted to true ; ; Parameters ....: All parameters are optional: ; $i_X - [optional] an integer value. Default is MouseGetPos(0) - 50. ; The upper left X coordinate where you want the cropping tool to appear ; ; $i_Y - [optional] an integer value. Default is MouseGetPos(1) - 50. ; The upper left Y coordinate where you want the cropping tool to appear ; ; $i_W - [optional] an integer value. Default is 100. ; The initial width of the selection area ; ; $i_H - [optional] an integer value. Default is 100. ; The initial height of the selection area ; ; $iMinW - [optional] an integer value. Default is 1 (minimum allowed is 1). ; The minimum selectable width ; ; $iMaxW - [optional] an integer value. Default is -1 (no limit). ; The maximum selectable width ; ; $iMinH - [optional] an integer value. Default is 1 (minimum allowed is 1). ; The minimum selectable height ; ; $iMaxH - [optional] an integer value. Default is -1 (no limit). ; The maximum selectable height ; ; Return values .: - A 4 element 1D array where: ; element [0] the upperLeft X coordinate of the selected area ; element [1] the upperLeft Y coordinate of the selected area ; element [2] the width of the selected area ; element [3] the height of the selected area ; ; @extended is set to True if you exit from the _crop() function by pressing the ESC key ; ; Author ........: Chimp (Gianni Addiego) ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== ; Func _Crop($i_X = MouseGetPos(0) - 50, $i_Y = MouseGetPos(1) - 50, $i_W = 100, $i_H = 100, $iMinW = -1, $iMaxW = -1, $iMinH = -1, $iMaxH = -1) Func _Crop($i_X = Default, $i_Y = Default, $i_W = Default, $i_H = Default, $iMinW = 1, $iMaxW = -1, $iMinH = 1, $iMaxH = -1) _GDIPlus_Startup() If ($i_X = '') Or ($i_X = Default) Then $i_X = MouseGetPos(0) - 50 If ($i_Y = '') Or ($i_Y = Default) Then $i_Y = MouseGetPos(1) - 50 If ($i_W = '') Or ($i_W = Default) Then $i_W = 100 If ($i_H = '') Or ($i_H = Default) Then $i_H = 100 If ($iMinW < 1) Or ($iMinW = Default) Then $iMinW = 1 If ($iMaxW < 1) Or ($iMaxW = Default) Then $iMaxW = 65535 If ($iMinH < 1) Or ($iMinH = Default) Then $iMinH = 1 If ($iMaxH < 1) Or ($iMaxH = Default) Then $iMaxH = 65535 ; used local variables Local $hGUI2, $hGUI3, $aWinPos2, $aPrevPos2[4], $aClientSize Local $iX, $iY, $iW, $iH Local Enum $x, $y Local $iOuterTolerance, $iBorder, $iInnerTolerance Local $hGraphic, $hPen, $AlphaKey = 0xFF000000, $RectColor, $RectBgColor Local $hDLL = DllOpen("user32.dll") Local $fOffset, $iDelay, $iTimerID = TimerInit() Local $iCursorID, $iBorderID, $aMousePointer, $iSide, $iTopBot, $iInner, $iRightEdge, $iBottomEdge, $iMouseOffsetX, $iMouseOffsetY Local $bEscape ; ================================================================================== ; Set the appearance and behaviour of the tool ; ================================================================================== $iBorder = 2 ; the width of the colored border (minimum 1) ; since with a very thin border it is difficult to click on it to drag it ; it is possible to set an external courtesy area authorized to click on the border ; even if the mouse is not exactly on it (it can also be set to 0 to disable it) $iOuterTolerance = 4 ; 'courtesy' external area allowed to click on the border ; same as above but for the inside of the edge $iInnerTolerance = 3 ; 'courtesy' internal area allowed to click on the border $RectColor = 0xFFFF0000 ; The color of the colored moving edge $RectBgColor = 0xFFFFFF00 ; The Background color of the colored moving edge $iDelay = 50 ; this value determines the rotation speed of the moving colored border. The lower it is, the faster it is ; here the pattern of the moving edge can be customized ; Thanks to @UEZ for this snippet. See Here for reference: https://www.autoitscript.com/forum/topic/185769-moving-dash-rectangle/?do=findComment&comment=1343856 Local $iCount = 4, $tArray = DllStructCreate("float;float;float;float") DllStructSetData($tArray, 1, 2) ; dash length DllStructSetData($tArray, 2, 4) ; space length DllStructSetData($tArray, 3, 2) ; dash length DllStructSetData($tArray, 4, 4) ; space length ; Important!: also set the below variable as the sum of all the above dash/space values ; ========== Local $iDotsDashesTotLen = 2 + 4 + 2 + 4 ; <--- adapt this variable to the above values ; ================================================================================== ; Create a transparent window where to draw the moving colored edge effect using the $iBorder variable ; X and Y coordinates refers to where will be placed the client crop area (not the draggable outer colored border) $hGUI2 = GUICreate('', $i_W + $iBorder * 2, $i_H + $iBorder * 2, $i_X - $iBorder, $i_Y - $iBorder, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST)) ; make sure $AlphaKey color is different from both $RectColor and $RectBgColor While ($AlphaKey = $RectColor) Or ($AlphaKey = $RectBgColor) $AlphaKey += 1 WEnd GUISetBkColor($AlphaKey, $hGUI2) _WinAPI_SetLayeredWindowAttributes($hGUI2, $AlphaKey, 0, $LWA_COLORKEY) ; Create a transparent window wider than the main one to allow the custom mouse cursor to be displayed even beyond the colored border (Tolerance) ; also, since this window is not "passthrough", it prevents mouse clicks from passing underneath. $hGUI3 = GUICreate('', $i_W + $iBorder * 2 + $iOuterTolerance * 2, $i_H + $iBorder * 2 + $iOuterTolerance * 2, $i_X - $iBorder - $iOuterTolerance, $i_Y - $iBorder - $iOuterTolerance, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST)) WinSetTrans($hGUI3, "", 1) WinSetOnTop($hGUI3, "", $WINDOWS_ONTOP) GUISetState(@SW_SHOW, $hGUI2) GUISetState(@SW_SHOW, $hGUI3) $hPen = _GDIPlus_PenCreate($RectColor, $iBorder * 2) ; why * 2 ?? _GDIPlus_PenSetColor($hPen, $RectColor) $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI2) Do $iSide = 0 $iTopBot = 0 $iInner = 0 $bEscape = False $aMousePointer = GUIGetCursorInfo($hGUI2) ; zero based $aWinPos2 = WinGetPos($hGUI2) $aClientSize = WinGetClientSize($hGUI2) ; ----------------------- ; check pointer position ; -------------------------------------------------------------------------------------------------------------------------------------------------------- If _ ; Pointer is on the left border (($aMousePointer[$x] >= -$iOuterTolerance) And ($aMousePointer[$x] < ($iBorder + $iInnerTolerance))) And _ (($aMousePointer[$y] >= -$iOuterTolerance) And ($aMousePointer[$y] < ($aClientSize[1] + $iOuterTolerance))) Then $iSide = 1 If _ ; Pointer is on the right border (($aMousePointer[$x] >= ($aClientSize[0] - $iBorder - $iInnerTolerance)) And ($aMousePointer[$x] < ($aClientSize[0] + $iOuterTolerance))) And _ (($aMousePointer[$y] >= -$iOuterTolerance) And ($aMousePointer[$y] < ($aClientSize[1] + $iOuterTolerance))) Then $iSide = 2 If _ ; Pointer is on the top border (($aMousePointer[$y] >= -$iOuterTolerance) And ($aMousePointer[$y] < ($iBorder + $iInnerTolerance))) And _ (($aMousePointer[$x] >= -$iOuterTolerance) And ($aMousePointer[$x] < ($aClientSize[0] + $iOuterTolerance))) Then $iTopBot = 3 If _ ; Pointer is on the bottom border (($aMousePointer[$y] >= ($aClientSize[1] - $iBorder - $iInnerTolerance)) And ($aMousePointer[$y] < $aClientSize[1] + $iOuterTolerance)) And _ (($aMousePointer[$x] >= -$iOuterTolerance) And ($aMousePointer[$x] < ($aClientSize[0] + $iOuterTolerance))) Then $iTopBot = 6 If _ ; Pointer is within the client area (($aMousePointer[$x] >= ($iBorder + $iInnerTolerance)) And $aMousePointer[$x] < ($aClientSize[0] - $iBorder - $iInnerTolerance)) And _ (($aMousePointer[$y] >= ($iBorder + $iInnerTolerance)) And $aMousePointer[$y] < ($aClientSize[1] - $iBorder - $iInnerTolerance)) Then $iInner = 9 ; -------------------------------------------------------------------------------------------------------------------------------------------------------- $iBorderID = $iSide + $iTopBot + $iInner ; ; SetCursor ; --------- $iCursorID = 0 Switch $iBorderID Case 0 $iCursorID = 2 ; ARROW Case 1, 2 ; 1 left ; 2 right $iCursorID = 13 ; SIZEWE Case 3, 6 ; 3 top ; 6 bottom $iCursorID = 11 ; SIZENS Case 5, 7 ; 5 TopRight ; 7 BottomLeft $iCursorID = 10 ; SIZENESW Case 4, 8 ; 4 TopLeft ; 8 BottomRight $iCursorID = 12 ; SIZENWSE Case 9 ; 9 Inside $iCursorID = 0 ; HAND - or SIZEALL (9) EndSwitch GUISetCursor($iCursorID, 1) ; ------------------------------------------------------- ; If LeftClick on the tool then Drag or redimm selector ; ------------------------------------------------------- If _IsPressed("1", $hDLL) And $iBorderID And (WinActive($hGUI2) Or WinActive($hGUI3)) Then ; Left clicked $aWinPos2 = WinGetPos($hGUI2) Switch $iBorderID Case 0 Case 1 ; Pointer is on the left border $iMouseOffsetX = $aWinPos2[0] - MouseGetPos(0) $iRightEdge = $aWinPos2[0] + WinGetClientSize($hGUI2)[0] Case 2 ; Pointer is on the right border $iMouseOffsetX = $aWinPos2[0] + $aWinPos2[2] - MouseGetPos(0) Case 3 ; Pointer is on the top border $iMouseOffsetY = $aWinPos2[1] - MouseGetPos(1) $iBottomEdge = $aWinPos2[1] + $aWinPos2[3] Case 4 ; Pointer is on the top-left corner $iMouseOffsetY = $aWinPos2[1] - MouseGetPos(1) $iMouseOffsetX = $aWinPos2[0] - MouseGetPos(0) $iRightEdge = $aWinPos2[0] + WinGetClientSize($hGUI2)[0] $iBottomEdge = $aWinPos2[1] + $aWinPos2[3] Case 5 ; Pointer is on the top-right corner $iMouseOffsetX = $aWinPos2[0] + $aWinPos2[2] - MouseGetPos(0) $iMouseOffsetY = $aWinPos2[1] - MouseGetPos(1) $iBottomEdge = $aWinPos2[1] + $aWinPos2[3] Case 6 ; Pointer is on the bottom border $iMouseOffsetY = $aWinPos2[1] + $aWinPos2[3] - MouseGetPos(1) Case 7 ; Pointer is on the bottom-left $iMouseOffsetY = $aWinPos2[1] + $aWinPos2[3] - MouseGetPos(1) $iMouseOffsetX = $aWinPos2[0] - MouseGetPos(0) $iRightEdge = $aWinPos2[0] + WinGetClientSize($hGUI2)[0] Case 8 ; Pointer is on the bottom-right $iMouseOffsetY = $aWinPos2[1] + $aWinPos2[3] - MouseGetPos(1) $iMouseOffsetX = $aWinPos2[0] + $aWinPos2[2] - MouseGetPos(0) Case 9 $iMouseOffsetY = $aWinPos2[1] - MouseGetPos(1) $iMouseOffsetX = $aWinPos2[0] - MouseGetPos(0) EndSwitch Do $iX = Default $iY = Default $iW = Default $iH = Default Switch $iBorderID Case 1 ; Pointer is on the left border $iX = MouseGetPos(0) + $iMouseOffsetX $iW = $iRightEdge - MouseGetPos(0) + -$iMouseOffsetX Case 2 ; Pointer is on the right border $iW = (MouseGetPos(0) - $aWinPos2[0]) + $iMouseOffsetX Case 3 ; Pointer is on the top border $iY = MouseGetPos(1) + $iMouseOffsetY $iH = $iBottomEdge - MouseGetPos(1) + -$iMouseOffsetY Case 4 ; Pointer is on the top-left corner $iX = MouseGetPos(0) + $iMouseOffsetX $iY = MouseGetPos(1) + $iMouseOffsetY $iW = $iRightEdge - MouseGetPos(0) + -$iMouseOffsetX $iH = $iBottomEdge - MouseGetPos(1) + -$iMouseOffsetY Case 5 ; Pointer is on the top-right corner $iY = MouseGetPos(1) + $iMouseOffsetY $iW = (MouseGetPos(0) - $aWinPos2[0]) + $iMouseOffsetX $iH = $iBottomEdge - MouseGetPos(1) + -$iMouseOffsetY Case 6 ; Pointer is on the bottom border $iH = (MouseGetPos(1) - $aWinPos2[1]) + $iMouseOffsetY Case 7 ; Pointer is on the bottom-left corner $iX = MouseGetPos(0) + $iMouseOffsetX $iW = $iRightEdge - MouseGetPos(0) + -$iMouseOffsetX $iH = (MouseGetPos(1) - $aWinPos2[1]) + $iMouseOffsetY Case 8 ; Pointer is on the bottom-right corner $iW = (MouseGetPos(0) - $aWinPos2[0]) + $iMouseOffsetX $iH = (MouseGetPos(1) - $aWinPos2[1]) + $iMouseOffsetY Case 9 ; Pointer is inside the client area $iX = MouseGetPos(0) + $iMouseOffsetX $iY = MouseGetPos(1) + $iMouseOffsetY EndSwitch If $iW > ($iMaxW + $iBorder * 2) Then $iW = $iMaxW + $iBorder * 2 $iX = Default EndIf If $iW < ($iMinW + $iBorder * 2) Then $iW = $iMinW + $iBorder * 2 $iX = Default EndIf If $iH > ($iMaxH + $iBorder * 2) Then $iH = $iMaxH + $iBorder * 2 $iY = Default EndIf If $iH < ($iMinH + $iBorder * 2) Then $iH = $iMinH + $iBorder * 2 $iY = Default EndIf WinMove($hGUI2, '', $iX, $iY, $iW, $iH) GUISetCursor($iCursorID, 1) $aWinPos2 = WinGetPos($hGUI2) $aClientSize = WinGetClientSize($hGUI2) ; If GUI2 moved or resized then redraw the colored border and reposition also GUI3 If $aPrevPos2[0] <> $aWinPos2[0] Or $aPrevPos2[1] <> $aWinPos2[1] Or $aPrevPos2[2] <> $aWinPos2[2] Or $aPrevPos2[3] <> $aWinPos2[3] Then ; store new position/size $aPrevPos2[0] = $aWinPos2[0] $aPrevPos2[1] = $aWinPos2[1] $aPrevPos2[2] = $aWinPos2[2] $aPrevPos2[3] = $aWinPos2[3] _GDIPlus_GraphicsDispose($hGraphic) WinMove($hGUI3, '', $aWinPos2[0] - $iOuterTolerance, $aWinPos2[1] - $iOuterTolerance, $aWinPos2[2] + $iOuterTolerance * 2, $aWinPos2[3] + $iOuterTolerance * 2) $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGUI2) _GDIPlus_GraphicsClear($hGraphic, $AlphaKey) ; erase rect _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLESOLID) _GDIPlus_PenSetColor($hPen, $RectBgColor) _GDIPlus_GraphicsDrawRect($hGraphic, 0, 0, $aWinPos2[2], $aWinPos2[3], $hPen) ; _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDOT) DllCall($__g_hGDIPDll, "int", "GdipSetPenDashArray", "handle", $hPen, "struct*", $tArray, "long", $iCount) _GDIPlus_PenSetColor($hPen, $RectColor) _GDIPlus_GraphicsDrawRect($hGraphic, 0, 0, $aWinPos2[2], $aWinPos2[3], $hPen) ; draw again rect EndIf If TimerDiff($iTimerID) > $iDelay Then $fOffset = Mod($fOffset + .5, $iDotsDashesTotLen) ; this is the key for the animated dotted line ;-) by UEZ ; https://www.autoitscript.com/forum/topic/185769-moving-dash-rectangle/?do=findComment&comment=1343851 DllCall($__g_hGDIPDll, "int", "GdipSetPenDashOffset", "handle", $hPen, "float", $fOffset) _GDIPlus_GraphicsClear($hGraphic, $AlphaKey) ; erase rect _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLESOLID) _GDIPlus_PenSetColor($hPen, $RectBgColor) _GDIPlus_GraphicsDrawRect($hGraphic, 0, 0, $aWinPos2[2], $aWinPos2[3], $hPen) ; _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDOT) DllCall($__g_hGDIPDll, "int", "GdipSetPenDashArray", "handle", $hPen, "struct*", $tArray, "long", $iCount) _GDIPlus_PenSetColor($hPen, $RectColor) _GDIPlus_GraphicsDrawRect($hGraphic, 0, 0, $aWinPos2[2], $aWinPos2[3], $hPen) ; draw again rect $iTimerID = TimerInit() EndIf Until Not _IsPressed("1", $hDLL) ; Right click released EndIf If TimerDiff($iTimerID) > $iDelay Then $fOffset = Mod($fOffset + .5, $iDotsDashesTotLen) DllCall($__g_hGDIPDll, "int", "GdipSetPenDashOffset", "handle", $hPen, "float", $fOffset) ; this is the key for the animated dotted line ;-) by UEZ _GDIPlus_GraphicsClear($hGraphic, $AlphaKey) ; erase rect _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLESOLID) _GDIPlus_PenSetColor($hPen, $RectBgColor) _GDIPlus_GraphicsDrawRect($hGraphic, 0, 0, $aWinPos2[2], $aWinPos2[3], $hPen) ; _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDOT) DllCall($__g_hGDIPDll, "int", "GdipSetPenDashArray", "handle", $hPen, "struct*", $tArray, "long", $iCount) _GDIPlus_PenSetColor($hPen, $RectColor) _GDIPlus_GraphicsDrawRect($hGraphic, 0, 0, $aWinPos2[2], $aWinPos2[3], $hPen) ; draw again rect $iTimerID = TimerInit() EndIf If _IsPressed('1B', $hDLL) Then $bEscape = True ; 1B ESC key Until ((_IsPressed('2', $hDLL) Or $bEscape) And (WinActive($hGUI2) Or WinActive($hGUI3))) ; RightClick means I'm done with selection Do; neutralize the RightClick persistency Until Not _IsPressed('2', $hDLL) Local $aGotRect[4] = [ _ $aWinPos2[0] + $iBorder, _ ; ....... UpperLeft X of window's client area $aWinPos2[1] + $iBorder, _ ; ....... UpperLeft Y of window's client area $aWinPos2[2] - $iBorder * 2, _ ; ... Width of window's client area $aWinPos2[3] - $iBorder * 2 _ ; .... Height of window's client area ] _GDIPlus_PenDispose($hPen) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() DllClose($hDLL) $tArray = 0 GUIDelete($hGUI3) GUIDelete($hGUI2) Return SetError(0, $bEscape, $aGotRect) EndFunc ;==>_Crop  
    • By UEZ
      Here another example to mark the desktop to get the marked region for capturing. This example is not perfect and not very fast (room for improvements).
      ;Coded by UEZ build 2020-08-07 beta ;Code cleanup up mLipok ; ;Short instruction: mark area on your desktop and press return key to capture. #include <APISysConstants.au3> #include <Array.au3> ;#include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <ScreenCapture.au3> #include <WinAPIGdi.au3> #include <WinAPISysWin.au3> #include <WindowsConstants.au3> ; enum _PROCESS_DPI_AWARENESS -> https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx Global Enum $DPI_AWARENESS_INVALID = -1, $PROCESS_DPI_UNAWARE = 0, $PROCESS_SYSTEM_DPI_AWARE, $PROCESS_PER_MONITOR_DPI_AWARE ;https://docs.microsoft.com/en-us/windows/desktop/hidpi/dpi-awareness-context Global Enum $Context_UnawareGdiScaled = -5, $Context_PerMonitorAwareV2, $Context_PerMonitorAware, $Context_SystemAware, $Context_Unaware _WinAPI_SetProcessDpiAwarenessContext($Context_PerMonitorAware) Global $__g_hGUI_MarkArea, $__g_hGUI_Bg, $__g_iLabel_TL, $__g_iLabel_TM, $__g_iLabel_TR, $__g_iLabel_LM, $__g_iLabel_RM, $__g_iLabel_BL, $__g_iLabel_BM, _ $__g_iLabel_BR, $__g_iOldCursor, $__g_iW, $__g_iH, $__g_iColor_ResizeDots = 0xFFFFFF, $__g_iBorder = 4, $__g_bSelectionDone = False Global $aRect = _GDIPlus_MarkScreenRegionAnimated() Global $hImage_Capture = _ScreenCapture_Capture(@TempDir & "\Test.png", $aRect[0], $aRect[1], $aRect[0] + $aRect[2] - 1, $aRect[1] + $aRect[3] - 1, False) ShellExecute(@TempDir & "\Test.png") ;_ArrayDisplay($aRect, "Marked area coordinates") Func _GDIPlus_MarkScreenRegionAnimated($bAnim = True) _GDIPlus_Startup() Local Const $hFullScreen = WinGetHandle("[TITLE:Program Manager;CLASS:Progman]") Local Const $aFullScreen = WinGetPos($hFullScreen) $__g_hGUI_Bg = GUICreate("", $aFullScreen[2], $aFullScreen[3], $aFullScreen[0], $aFullScreen[1], BitOR($WS_CLIPCHILDREN, $WS_POPUP), $WS_EX_TOPMOST) ;to avoid cursor flickering and for proper control read WinSetTrans($__g_hGUI_Bg, "", 0x01) $__g_hGUI_MarkArea = GUICreate("", 1, 1, -1, -1, $bAnim ? $WS_POPUP : BitOR($WS_POPUP, $WS_BORDER), BitOR($WS_EX_TOPMOST, $WS_EX_LAYERED), $__g_hGUI_Bg) GUISetBkColor(0xABCDEF, $__g_hGUI_MarkArea) If Not $bAnim Then $__g_iColor_ResizeDots = 0xFF0000 $__g_iLabel_TL = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top left GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_TM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_TR = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;top right GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_LM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;left mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_RM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;right mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BL = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom left GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BM = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom mid GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) $__g_iLabel_BR = GUICtrlCreateLabel("", 0, 0, $__g_iBorder, $__g_iBorder) ;bottom right GUICtrlSetResizing(-1, $GUI_DOCKSIZE) GUICtrlSetBkColor(-1, $__g_iColor_ResizeDots) GUISetState(@SW_SHOWNA, $__g_hGUI_Bg) GUISetState(@SW_SHOW, $__g_hGUI_MarkArea) $__g_iOldCursor = MouseGetCursor() GUISetCursor(3, 1, $__g_hGUI_Bg) GUISetCursor(3, 1, $__g_hGUI_MarkArea) _WinAPI_SetLayeredWindowAttributes($__g_hGUI_MarkArea, 0xABCDEF, 0xF0) Local $aMPos, $aPrevMPos[2] = [MouseGetPos(0) + 1, MouseGetPos(1) + 1], $iID, $aCI, $iX, $iY, $aOldWinPos, $aOldMPos, $bMoved Local $aGUIStartPos, $iKey_Exit = GUICtrlCreateButton("", $aFullScreen[0] - 10, $aFullScreen[1] - 10, 1, 1), $aAccelKeys[1][2] = [["{ENTER}", $iKey_Exit]] GUISetAccelerators($aAccelKeys, $__g_hGUI_Bg) GUISetAccelerators($aAccelKeys, $__g_hGUI_MarkArea) #forceref $bMoved Do Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $iKey_Exit If $bAnim Then GUIRegisterMsg($WM_TIMER, "") DllCall("user32.dll", "bool", "KillTimer", "hwnd", $__g_hGUI_MarkArea, "uint_ptr", $iID) GUIRegisterMsg($WM_ERASEBKGND, "") EndIf _GDIPlus_Shutdown() Local $aResult = WinGetPos($__g_hGUI_MarkArea) $aResult[2] = WinGetClientSize($__g_hGUI_MarkArea)[0] $aResult[3] = WinGetClientSize($__g_hGUI_MarkArea)[1] GUIDelete($__g_hGUI_MarkArea) GUIDelete($__g_hGUI_Bg) If Not $__g_bSelectionDone Then $aResult = 0 Return $aResult EndSwitch $aMPos = MouseGetPos() If ($aMPos[0] <> $aPrevMPos[0] Or $aMPos[1] <> $aPrevMPos[1]) And (Not $__g_bSelectionDone) Then WinMove($__g_hGUI_MarkArea, "", $aMPos[0], $aMPos[1]) $aPrevMPos = $aMPos EndIf $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) If $aCI[2] And (Not $__g_bSelectionDone) Then $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If $bAnim Then GUIRegisterMsg($WM_ERASEBKGND, "WM_ERASEBKGND") GUIRegisterMsg($WM_TIMER, "PlayBorderAnim") $iID = DllCall("User32.dll", "uint_ptr", "SetTimer", "hwnd", $__g_hGUI_MarkArea, "uint_ptr", 1, "uint", 50, "ptr", 0)[0] EndIf While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) $aMPos = MouseGetPos() $__g_iW = Abs($aMPos[0] - $aGUIStartPos[0]) + 1 $__g_iH = Abs($aMPos[1] - $aGUIStartPos[1]) + 1 If $aMPos[0] < $aGUIStartPos[0] Then $iX = $aMPos[0] Else $iX = $aGUIStartPos[0] EndIf If $aMPos[1] < $aGUIStartPos[1] Then $iY = $aMPos[1] Else $iY = $aGUIStartPos[1] EndIf WinMove($__g_hGUI_MarkArea, "", $iX, $iY, $__g_iW, $__g_iH) UpdateCtrlPos($bAnim) WEnd $__g_bSelectionDone = True GUISetCursor(3, 1, $__g_hGUI_MarkArea) ElseIf $aCI[3] And $__g_bSelectionDone Then $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If _WinAPI_PtInRectEx(MouseGetPos(0), MouseGetPos(1), $aGUIStartPos[0], $aGUIStartPos[1], $aGUIStartPos[0] + $aGUIStartPos[2], $aGUIStartPos[1] + $aGUIStartPos[3]) Then $aMPos = MouseGetPos() $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) While $aCI[3] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aGUIStartPos[0] - ($aMPos[0] - MouseGetPos(0)), $aGUIStartPos[1] - ($aMPos[1] - MouseGetPos(1)), $__g_iW, $__g_iH) GUISetCursor(0, 1, $__g_hGUI_Bg) GUISetCursor(0, 1, $__g_hGUI_MarkArea) WEnd GUISetCursor(3, 1, $__g_hGUI_Bg) GUISetCursor(3, 1, $__g_hGUI_MarkArea) EndIf EndIf If $__g_bSelectionDone Then $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) If @error Then ContinueLoop Switch $aCI[4] Case $__g_iLabel_TL GUISetCursor(12, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), MouseGetPos(1), $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BR GUISetCursor(12, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_TR GUISetCursor(10, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], MouseGetPos(1), $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BL GUISetCursor(10, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), $aOldWinPos[1], $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_LM GUISetCursor(13, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", MouseGetPos(0), $aOldWinPos[1], $aOldWinPos[2] + ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3]) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_RM GUISetCursor(13, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2] - ($aOldMPos[0] - MouseGetPos(0)), $aOldWinPos[3]) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_TM GUISetCursor(11, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], MouseGetPos(1), $aOldWinPos[2], $aOldWinPos[3] + ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case $__g_iLabel_BM GUISetCursor(11, 1, $__g_hGUI_MarkArea) If $aCI[2] Then $aOldWinPos = WinGetPos($__g_hGUI_MarkArea) $aOldMPos = MouseGetPos() While $aCI[2] * Sleep(10) $aCI = GUIGetCursorInfo($__g_hGUI_MarkArea) WinMove($__g_hGUI_MarkArea, "", $aOldWinPos[0], $aOldWinPos[1], $aOldWinPos[2], $aOldWinPos[3] - ($aOldMPos[1] - MouseGetPos(1))) WEnd UpdateCtrlPos($bAnim) EndIf Case Else GUISetCursor(3, 1, $__g_hGUI_MarkArea) EndSwitch EndIf Until False EndFunc ;==>_GDIPlus_MarkScreenRegionAnimated Func UpdateCtrlPos($bAnim = True) Local Const $aGUIStartPos = WinGetPos($__g_hGUI_MarkArea) If $__g_bSelectionDone And $bAnim Then GUIRegisterMsg($WM_TIMER, "") $__g_iW = $aGUIStartPos[2] $__g_iH = $aGUIStartPos[3] ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TL, 0, 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TM, ($__g_iW - $__g_iBorder) / 2, 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_TR, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), 0, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_LM, 0, ($__g_iH - $__g_iBorder) / 2, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_RM, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), ($__g_iH - $__g_iBorder) / 2, $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BL, 0, ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BM, ($__g_iW - $__g_iBorder) / 2, ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) ControlMove($__g_hGUI_MarkArea, "", $__g_iLabel_BR, ($__g_iW - $__g_iBorder - $__g_iBorder / 2), ($__g_iH - $__g_iBorder - $__g_iBorder / 2), $__g_iBorder, $__g_iBorder) If $__g_bSelectionDone And $bAnim Then GUIRegisterMsg($WM_TIMER, "PlayBorderAnim") EndFunc ;==>UpdateCtrlPos Func PlayBorderAnim() Local $aWinPos = WinGetClientSize($__g_hGUI_MarkArea), $iW = $aWinPos[0], $iH = $aWinPos[1] Local Static $fOffset = 0 Local Const $iSize = $__g_iBorder / 2 Local Const $hDC = _WinAPI_GetDC($__g_hGUI_MarkArea) Local Const $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH) Local Const $hDC_backbuffer = _WinAPI_CreateCompatibleDC($hDC) Local Const $DC_obj = _WinAPI_SelectObject($hDC_backbuffer, $hHBitmap) Local Const $hCanvas = _GDIPlus_GraphicsCreateFromHDC($hDC_backbuffer) Local Const $hPen = _GDIPlus_PenCreate(0xFF0178D7, $iSize), $hPen2 = _GDIPlus_PenCreate(0xFFFFFFFF, $iSize), _ $hBrush = _GDIPlus_BrushCreateSolid(0xFF000000 + $__g_iColor_ResizeDots), $hPen3 = _GDIPlus_PenCreate(0xFF000000) _GDIPlus_PenSetDashStyle($hPen, $GDIP_DASHSTYLEDASHDOT) _GDIPlus_GraphicsClear($hCanvas, 0xFFABCDEF) ;for faster performance direct dll calls DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen2, "float", 1 + $iSize, "float", 1 + $iSize, "float", $iW - 2 * $iSize - 2, "float", $iH - 2 * $iSize - 2) DllCall($__g_hGDIPDll, "int", "GdipSetPenDashOffset", "handle", $hPen, "float", $fOffset) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen, "float", 1 + $iSize, "float", 1 + $iSize, "float", $iW - 2 * $iSize - 2, "float", $iH - 2 * $iSize - 2) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) / 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) / 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", 0, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) / 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", 0, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", 0, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) / 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) / 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) DllCall($__g_hGDIPDll, "int", "GdipDrawRectangle", "handle", $hCanvas, "handle", $hPen3, "float", ($iW - $__g_iBorder) - 2, "float", ($iH - $__g_iBorder) - 2, "float", $__g_iBorder + 1, "float", $__g_iBorder + 1) _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hDC_backbuffer, 0, 0, $SRCCOPY) $fOffset += 0.5 _GDIPlus_GraphicsDispose($hCanvas) _WinAPI_SelectObject($hDC_backbuffer, $DC_obj) _WinAPI_DeleteDC($hDC_backbuffer) _WinAPI_DeleteObject($hHBitmap) _WinAPI_ReleaseDC($__g_hGUI_MarkArea, $hDC) _GDIPlus_PenDispose($hPen) _GDIPlus_PenDispose($hPen2) _GDIPlus_PenDispose($hPen3) _GDIPlus_BrushDispose($hBrush) EndFunc ;==>PlayBorderAnim Func WM_ERASEBKGND($hWnd, $iMsgm, $wParam, $lParam) ;suppress repainting to avoid flickering but causes some other side effects #forceref $iMsgm, $wParam, $lParam, $hWnd Local Const $hBrush = _WinAPI_CreateSolidBrush(0xEFCDAB) ;BGR format ;~ _WinAPI_RedrawWindow($__g_hGUI_MarkArea, 0, 0, BitOR($RDW_NOERASE, $RDW_NOCHILDREN, $RDW_NOFRAME, $RDW_VALIDATE)) _WinAPI_SetClassLongEx($__g_hGUI_MarkArea, $GCL_HBRBACKGROUND, $hBrush) _WinAPI_DeleteObject($hBrush) Return 0 EndFunc ;==>WM_ERASEBKGND ;https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setprocessdpiawarenesscontext Func _WinAPI_SetProcessDpiAwarenessContext($DPIAwareContext = $Context_PerMonitorAware, $hGUI = 0, $iMode = 3) ;https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setprocessdpiawarenesscontext $DPIAwareContext = ($DPIAwareContext < -5) ? -5 : ($DPIAwareContext > -1) ? -1 : $DPIAwareContext $iMode = ($iMode < 1) ? 1 : ($iMode > 3) ? 3 : $iMode Switch $iMode Case 1 Local $hDC = _WinAPI_GetDC($hGUI) Local $aResult1 = DllCall("user32.dll", "ptr", "GetDpiFromDpiAwarenessContext", "ptr", $hDC) If @error Or Not IsArray($aResult1) Then Return SetError(11, 0, 0) _WinAPI_ReleaseDC(0, $hDC) Local $aResult = DllCall("user32.dll", "Bool", "SetProcessDpiAwarenessContext", "int", $aResult1[0] + $DPIAwareContext) If @error Or Not IsArray($aResult) Then Return SetError(12, 0, 0) Case 2 ;~ If Not $hGUI Then $hGUI = WinGetHandle(AutoItWinGetTitle()) Local $aResult2 = DllCall("user32.dll", "int", "GetWindowDpiAwarenessContext", "ptr", $hGUI) If @error Or Not IsArray($aResult2) Then Return SetError(21, 0, 0) Local $aResult = DllCall("user32.dll", "Bool", "SetProcessDpiAwarenessContext", "int", $aResult2[0] + $DPIAwareContext) If @error Or Not IsArray($aResult) Then Return SetError(22, 0, 0) Case 3 Local $aResult31 = DllCall("user32.dll", "ptr", "GetThreadDpiAwarenessContext") If @error Or Not IsArray($aResult31) Then Return SetError(31, 0, 0) Local $aResult32 = DllCall("user32.dll", "ptr", "GetAwarenessFromDpiAwarenessContext", "ptr", $aResult31[0]) If @error Or Not IsArray($aResult32) Then Return SetError(32, 0, 0) Local $aResult = DllCall("user32.dll", "Bool", "SetThreadDpiAwarenessContext", "int", $aResult32[0] + $DPIAwareContext) If @error Or Not IsArray($aResult) Then Return SetError(33, 0, 0) EndSwitch Return 1 EndFunc ;==>_WinAPI_SetProcessDpiAwarenessContext  
      Just press the lmb and move your mouse. When lmb is released you can adjust the size of the window by dragging the white rectangle to any direction. Rmb will move the marked area.
      Press ESC to get the coordinates of the marked region.
      If you have any improvements, please post it here.
       
      Tested on Win10 x64 only.
       
    • By ripdad
      This is a project that I have been working on for several months off and on.
      It's a simple "What You Hear" MP3 @ 320Kbps and WAV audio recorder.
      Features:
      - LoudMax, a Gain Controller and Look-Ahead Limiter
      - Auto Shut-Off after one minute of silence
      - Side-by-Side Simulated LED Meter
      - Running Time Counter
      It started off being a large project, but I eventually stripped it down to its
      bare essentials because I came to realize that it would be very difficult to
      deal with every sound card and every way a PC is set up for audio. It would
      have been a nightmare that I was not willing to go through.
      This project contains the most up-to-date BASS.dll v.2.4.15.0 - December 17, 2019.
      All BASS Dll's are 32bit. Those and the needed UDF's are included in the zip file.
      I will try to explain how it works in the next post.

      Download:
      BASS VST Recorder v1.1.zip
       
×
×
  • Create New...