Jump to content
Sign in to follow this  
Zoldex

Crop an image in a window

Recommended Posts

Zoldex

This is my attempt on loading and let the user select only a portion of an image.

I found some samples by Melba23 and UEZ and tried to glue things together.

I think I've almost done it but still have some problems:

  • Resizing and displaying image is not always proportional (just try the script with different resolution images, expecially big ones)

  • The rectangle selection to crop is wrong: it actually selects a different region of the screen

  • Function _GUICtrlStatic_SetImage does not work. Temporarily fixed using _WinAPI_DeleteObject instead...
Any hint would be greatly appreciated!

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#Include <ScreenCapture.au3>
#Include <Misc.au3>
#include <StaticConstants.au3>
Global $iX1, $iY1, $iX2, $iY2, $aPos, $sMsg, $sBMP_Path
Global Const $IMAGE_BITMAP = 0 ; Needed for GUICtrlSendMsg.
Global Const $STM_SETIMAGE = 0x0172 ; Needed for GUICtrlSendMsg.

Local $GUIimg_title,$GUIwidth,$GUIheight,$GUILeft,$GUITop

Local $filename = FileOpenDialog("Select image", @ScriptDir, "Image (*.jpg;*.bmp)", 3)
$GUIimg_title = $filename

_GDIPlus_Startup()

Local $imagefromfile = _GDIPlus_ImageLoadFromFile($filename) ;Create an image object based on a file [OK] **NOTA PER LA ROTAZIONE VEDI HELP FILE!**
Local $GUIwidth = _GDIPlus_ImageGetWidth ($imagefromfile)
Local $GUIheight = _GDIPlus_ImageGetHeight ($imagefromfile)

;try to create a smaller window if the pictures is bigger than Desktop
If $GUIwidth > @DesktopWidth Then
$GUIwidth = @DesktopWidth - 6
EndIf
If $GUIheight > @DesktopHeight Then
$GUIheight = @DesktopHeight - 73 ; rought attempt to show the window bar...
EndIf
$GUILeft = (@DesktopWidth - $GUIwidth) / 2
$GUITop = (@DesktopHeight - $GUIheight) / 2

$hBitmap_resized = _GDIPlus_ScaleImage($imagefromfile, $GUIwidth, $GUIheight); attempts to scale the image but it not always proportional..

_GDIPlus_ImageDispose($imagefromfile)

; Display image
$hBitmap_GUI = GUICreate($GUIimg_title & " [" & $GUIwidth & "x" & $GUIheight & "]", $GUIwidth, $GUIheight,$GUILeft,$GUITop)
$hPic = GUICtrlCreatePic("", 0, 0, $GUIwidth, $GUIheight)
GUISetState()

Local $hHBitmap_resized = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap_resized); creates an handle
_WinAPI_DeleteObject(GUICtrlSendMsg($hPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap_resized)) ; Updates the GUI - It works instead of _GDIPlus_ImageDispose($hHBitmap_resized) [OK]
_WinAPI_DeleteObject($hHBitmap_resized)


;~ _GUICtrlStatic_SetImage($hPic, $hBitmap_resized); does not seems to work... using _WinAPI_DeleteObject above







_GDIPlus_Shutdown()

; Create GUI
;~ Local $GUITop =
$hMain_GUI = GUICreate("Select a function", 480, 50)

$hRect_Button = GUICtrlCreateButton("Crop", 10, 10, 80, 30)
$hRot_90_plus_Button = GUICtrlCreateButton("+90°", 95, 10, 50, 30)
$hRot_90_minus_Button = GUICtrlCreateButton("-90°", 150, 10, 50, 30)
$hOK_Button = GUICtrlCreateButton("OK", 305, 10, 50, 30)
$hCancel_Button = GUICtrlCreateButton("Cancel", 360, 10, 80, 30)

GUISetState()

While 1

Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE, $hCancel_Button
FileDelete(@ScriptDir & "Rect.bmp")
Exit
Case $hRect_Button
GUISetState(@SW_HIDE, $hMain_GUI)
Mark_Rect($GUIwidth,$GUIheight,$GUILeft,$GUITop);selects wrong area!!
; Capture selected area
$sBMP_Path = @ScriptDir & "Rect.bmp"
;~ _ScreenCapture_Capture($sBMP_Path, $iX1, $iY1, $iX2, $iY2, False)
_ScreenCapture_CaptureWnd($sBMP_Path, $hBitmap_GUI,$iX1, $iY1, $iX2, $iY2, False)
GUISetState(@SW_SHOW, $hMain_GUI)
GUIDelete($hBitmap_GUI)
; Display image
$hBitmap_GUI = GUICreate("Selected Rectangle", $iX2 - $iX1 + 1, $iY2 - $iY1 + 1, 100, 100)
$hPic = GUICtrlCreatePic(@ScriptDir & "Rect.bmp", 0, 0, $iX2 - $iX1 + 1, $iY2 - $iY1 + 1)
GUISetState()
case $hRot_90_plus_Button
; Rotate +90
case $hRot_90_minus_Button
;Rotate -90
case $hOK_Button
;should return the resulting picture object
EndSwitch

WEnd

; -------------

Func Mark_Rect($width = @DesktopWidth, $height = @DesktopHeight, $Left = 0, $Top = 0);Made by Melba23 - Arguments added by me

Local $aMouse_Pos, $hMask, $hMaster_Mask, $iTemp
Local $UserDLL = DllOpen("user32.dll")

Global $hRectangle_GUI = GUICreate("", $width, $height, $Left, $Top, $WS_POPUP, $WS_EX_TOOLWINDOW + $WS_EX_TOPMOST);create fading
_GUICreateInvRect($hRectangle_GUI, 0, 0, 1, 1)
GUISetBkColor(0)
WinSetTrans($hRectangle_GUI, "", 95)
GUISetState(@SW_SHOW, $hRectangle_GUI)
GUISetCursor(3, 1, $hRectangle_GUI)

; Wait until mouse button pressed
While Not _IsPressed("01", $UserDLL)
Sleep(10)
WEnd

; Get first mouse position
$aMouse_Pos = MouseGetPos()
$iX1 = $aMouse_Pos[0]
$iY1 = $aMouse_Pos[1]

; Draw rectangle while mouse button pressed
While _IsPressed("01", $UserDLL)

$aMouse_Pos = MouseGetPos()

; Set in correct order if required
If $aMouse_Pos[0] < $iX1 Then
$iX_Pos = $aMouse_Pos[0]
$iWidth = $iX1 - $aMouse_Pos[0]
Else
$iX_Pos = $iX1
$iWidth = $aMouse_Pos[0] - $iX1
EndIf
If $aMouse_Pos[1] < $iY1 Then
$iY_Pos = $aMouse_Pos[1]
$iHeight = $iY1 - $aMouse_Pos[1]
Else
$iY_Pos = $iY1
$iHeight = $aMouse_Pos[1] - $iY1
EndIf

_GUICreateInvRect($hRectangle_GUI, $iX_Pos, $iY_Pos, $iWidth, $iHeight)

Sleep(10)

WEnd

; Get second mouse position
$iX2 = $aMouse_Pos[0]
$iY2 = $aMouse_Pos[1]

; Set in correct order if required
If $iX2 < $iX1 Then
$iTemp = $iX1
$iX1 = $iX2
$iX2 = $iTemp
EndIf
If $iY2 < $iY1 Then
$iTemp = $iY1
$iY1 = $iY2
$iY2 = $iTemp
EndIf

GUIDelete($hRectangle_GUI)
DllClose($UserDLL)

EndFunc ;==>Mark_Rect

Func _GUICreateInvRect($hWnd, $iX, $iY, $iW, $iH)

$hMask_1 = _WinAPI_CreateRectRgn(0, 0, @DesktopWidth, $iY)
$hMask_2 = _WinAPI_CreateRectRgn(0, 0, $iX, @DesktopHeight)
$hMask_3 = _WinAPI_CreateRectRgn($iX + $iW, 0, @DesktopWidth, @DesktopHeight)
$hMask_4 = _WinAPI_CreateRectRgn(0, $iY + $iH, @DesktopWidth, @DesktopHeight)

_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_2, 2)
_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_3, 2)
_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_4, 2)

_WinAPI_DeleteObject($hMask_2)
_WinAPI_DeleteObject($hMask_3)
_WinAPI_DeleteObject($hMask_4)

_WinAPI_SetWindowRgn($hWnd, $hMask_1, 1)

EndFunc








Func _GDIPlus_ScaleImage($hImage, $iW, $iH, $iInterpolationMode = 7) ;coded by UEZ 2012
Local $hBitmap = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iW, "int", $iH, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0)
If @error Then Return SetError(3, 0, 0)
$hBitmap = $hBitmap[6]
Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap)
DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "handle", $hBmpCtxt, "int", $iInterpolationMode)
_GDIPlus_GraphicsDrawImageRect($hBmpCtxt, $hImage, 0, 0, $iW, $iH)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_GraphicsDispose($hBmpCtxt)
Return $hBitmap
EndFunc




Func _GUICtrlStatic_SetImage($iCtrlId, $hBitmap)
Local Const $STM_SETIMAGE = 0x0172
Local Const $IMAGE_BITMAP = 0
Local Const $SS_BITMAP = 0xE
Local Const $GWL_STYLE = -16

If IsHWnd($iCtrlId) Then
If WinGetProcess($iCtrlId) <> @AutoItPID Then Return SetError(1,0,0)
Else
$iCtrlId = GUICtrlGetHandle($iCtrlId)
If Not $iCtrlId Then Return SetError(2,0,0)
EndIf
; set SS_BITMAP style to control
Local $oldStyle = DllCall("user32.dll", "long", "GetWindowLong", "hwnd", $iCtrlId, "int", $GWL_STYLE)
If @error Then Return SetError(3, 0, 0)
DllCall("user32.dll", "long", "SetWindowLong", "hwnd", $iCtrlId, "int", $GWL_STYLE, "long", BitOR($oldStyle[0], $SS_BITMAP))
If @error Then Return SetError(4, 0, 0)
Local $oldBmp = DllCall("user32.dll", "handle", "SendMessageW", "hwnd", $iCtrlId, "int", $STM_SETIMAGE, "wparam", $IMAGE_BITMAP, "handle", $hBitmap)
If @error Then Return SetError(5, 0, 0)
If $oldBmp[0] Then _WinAPI_DeleteObject($oldBmp[0])
Return 1
EndFunc

Share this post


Link to post
Share on other sites
PhoenixXL

use

_WinAPI_GetSystemMetrics

to get the TitleBar and the Border dimensions


My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites
PhoenixXL

Its better to Use only one GUI to carry out your Functions

If you use more than one then take care that you use GuiGetMsg(1)

orelse it will cause problems !!


My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites
PhoenixXL

This draws the right rectangle

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <ScreenCapture.au3>
#include <Misc.au3>
#include <StaticConstants.au3>
Global $iX1, $iY1, $iX2, $iY2, $aPos, $sMsg, $sBMP_Path
Global Const $IMAGE_BITMAP = 0 ; Needed for GUICtrlSendMsg.
Global Const $STM_SETIMAGE = 0x0172 ; Needed for GUICtrlSendMsg.

Global Const $sysHeight = _WinAPI_GetSystemMetrics(4)
Global Const $sysWidth = _WinAPI_GetSystemMetrics(7)
Global Const $sysdHeifht = _WinAPI_GetSystemMetrics(8)

Local $GUIimg_title, $GUIwidth, $GUIheight, $GUILeft, $GUITop

Local $filename = FileOpenDialog("Select image", @ScriptDir, "Image (*.jpg;*.bmp)", 3)
If @error Then Exit 1
$GUIimg_title = $filename

_GDIPlus_Startup()

Local $imagefromfile = _GDIPlus_ImageLoadFromFile($filename) ;Create an image object based on a file [OK] **NOTA PER LA ROTAZIONE VEDI HELP FILE!**
Local $GUIwidth = _GDIPlus_ImageGetWidth($imagefromfile)
Local $GUIheight = _GDIPlus_ImageGetHeight($imagefromfile)

;try to create a smaller window if the pictures is bigger than Desktop
If $GUIwidth > @DesktopWidth Then
$GUIwidth = @DesktopWidth - 6
EndIf
If $GUIheight > @DesktopHeight Then
$GUIheight = @DesktopHeight - 73 ; rought attempt to show the window bar...
EndIf

$GUILeft = (@DesktopWidth - $GUIwidth) / 2
$GUITop = (@DesktopHeight - $GUIheight) / 2

$hBitmap_resized = _GDIPlus_ScaleImage($imagefromfile, $GUIwidth, $GUIheight); attempts to scale the image but it not always proportional..

_GDIPlus_ImageDispose($imagefromfile)

; Display image
$hBitmap_GUI = GUICreate($GUIimg_title & " [" & $GUIwidth & "x" & $GUIheight & "]", $GUIwidth + 50, $GUIheight + 50 + 100, $GUILeft, $GUITop)
$hPic = GUICtrlCreatePic("", 25, 25 + 100, $GUIwidth, $GUIheight)
GUISetState()

Local $hHBitmap_resized = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap_resized); creates an handle
_WinAPI_DeleteObject(GUICtrlSendMsg($hPic, $STM_SETIMAGE, $IMAGE_BITMAP, $hHBitmap_resized)) ; Updates the GUI - It works instead of _GDIPlus_ImageDispose($hHBitmap_resized) [OK]
_WinAPI_DeleteObject($hHBitmap_resized)

_GDIPlus_Shutdown()


$hRect_Button = GUICtrlCreateButton("Crop", 25, 25, 80, 30)
$hRot_90_plus_Button = GUICtrlCreateButton("+90°", 145, 25, 50, 30)
$hRot_90_minus_Button = GUICtrlCreateButton("-90°", 245, 25, 50, 30)

GUISetState()

While 1

Switch GUIGetMsg()
Case -3
;
Case $hRect_Button
$pPos = WinGetPos($hBitmap_GUI)
Mark_Rect($GUIwidth, $GUIheight, $pPos[0] + 25 + $sysWidth, $pPos[1] + 125 + $sysHeight + $sysdHeifht);selects wrong area!!
GUISwitch($hBitmap_GUI)
EndSwitch

WEnd

; -------------

Func Mark_Rect($width = @DesktopWidth, $height = @DesktopHeight, $Left = 0, $Top = 0);Made by Melba23 - Arguments added by me

Local $aMouse_Pos, $hMask, $hMaster_Mask, $iTemp
Local $UserDLL = DllOpen("user32.dll")

Global $hRectangle_GUI = GUICreate("", $width, $height, $Left, $Top, $WS_POPUP, $WS_EX_TOOLWINDOW + $WS_EX_TOPMOST);create fading
_GUICreateInvRect($hRectangle_GUI, 0, 0, 1, 1)
GUISetBkColor(0)
WinSetTrans($hRectangle_GUI, "", 95)
GUISetState(@SW_SHOW, $hRectangle_GUI)
GUISetCursor(3, 1, $hRectangle_GUI)

; Wait until mouse button pressed
While Not _IsPressed("01", $UserDLL)
Sleep(10)
WEnd

; Get first mouse position
$aMouse_Pos = MouseGetPos()
$iX1 = $aMouse_Pos[0]
$iY1 = $aMouse_Pos[1]

; Draw rectangle while mouse button pressed
While _IsPressed("01", $UserDLL)

$aMouse_Pos = MouseGetPos()

; Set in correct order if required
If $aMouse_Pos[0] < $iX1 Then
$iX_Pos = $aMouse_Pos[0]
$iWidth = $iX1 - $aMouse_Pos[0]
Else
$iX_Pos = $iX1
$iWidth = $aMouse_Pos[0] - $iX1
EndIf
If $aMouse_Pos[1] < $iY1 Then
$iY_Pos = $aMouse_Pos[1]
$iHeight = $iY1 - $aMouse_Pos[1]
Else
$iY_Pos = $iY1
$iHeight = $aMouse_Pos[1] - $iY1
EndIf

_GUICreateInvRect($hRectangle_GUI, $iX_Pos, $iY_Pos, $iWidth, $iHeight)

Sleep(10)

WEnd

; Get second mouse position
$iX2 = $aMouse_Pos[0]
$iY2 = $aMouse_Pos[1]

; Set in correct order if required
If $iX2 < $iX1 Then
$iTemp = $iX1
$iX1 = $iX2
$iX2 = $iTemp
EndIf
If $iY2 < $iY1 Then
$iTemp = $iY1
$iY1 = $iY2
$iY2 = $iTemp
EndIf

GUIDelete($hRectangle_GUI)
DllClose($UserDLL)

EndFunc   ;==>Mark_Rect

Func _GUICreateInvRect($hWnd, $iX, $iY, $iW, $iH)

$hMask_1 = _WinAPI_CreateRectRgn(0, 0, @DesktopWidth, $iY)
$hMask_2 = _WinAPI_CreateRectRgn(0, 0, $iX, @DesktopHeight)
$hMask_3 = _WinAPI_CreateRectRgn($iX + $iW, 0, @DesktopWidth, @DesktopHeight)
$hMask_4 = _WinAPI_CreateRectRgn(0, $iY + $iH, @DesktopWidth, @DesktopHeight)

_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_2, 2)
_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_3, 2)
_WinAPI_CombineRgn($hMask_1, $hMask_1, $hMask_4, 2)

_WinAPI_DeleteObject($hMask_2)
_WinAPI_DeleteObject($hMask_3)
_WinAPI_DeleteObject($hMask_4)

_WinAPI_SetWindowRgn($hWnd, $hMask_1, 1)

EndFunc   ;==>_GUICreateInvRect

Func _GDIPlus_ScaleImage($hImage, $iW, $iH, $iInterpolationMode = 7) ;coded by UEZ 2012
Local $hBitmap = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iW, "int", $iH, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0)
If @error Then Return SetError(3, 0, 0)
$hBitmap = $hBitmap[6]
Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap)
DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "handle", $hBmpCtxt, "int", $iInterpolationMode)
_GDIPlus_GraphicsDrawImageRect($hBmpCtxt, $hImage, 0, 0, $iW, $iH)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_GraphicsDispose($hBmpCtxt)
Return $hBitmap
EndFunc   ;==>_GDIPlus_ScaleImage

Edited by PhoenixXL

My code:

PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.

Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners.

MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. 

Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.

Share this post


Link to post
Share on other sites
Zoldex

This draws the right rectangle

Yes, it does.

But the crop function does not...

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  

  • Similar Content

    • Xandy
      By Xandy
      MapIt is a tile world editor.  MapIt was built around the concept of reversing Dragon Warrior map images.  MapIt can take image input and produce a tile and world array.
      MapIt features Unity style dragable labels that adjust property values.

      MapParser is a C++ project that scans images for unique tiles.  MapParser is very fast.  Due to hard drive failure, many bugs were restored b/c I had to rewind many years.  Frustrated with the design, I wrote a new version from the ground up.  This New Version:  AutoIt Front-end, command line controls, and shared with the world; so that I can't lose it again.
      You can toggle the C++ MapParser off to see the difference in speeds between the MapParser CPP verse AutoIt function.  Function is named Scan_Tiles() in AutoIt.  You can also chose to download without MapParser.exe.
      At the moment Scanning a image resets the arrays, but you can add tiles after scanning.
      Images can be added as tiles without scan image at all.  Then configure settings to give your world parameters and manually fill the world data with tile indexes.
      Using the settings you can change tile size after a scan.  Example: you wanted to replace a map with different sized tiles.
      Changing and replacing tile / world data is easy.  B/c tile world editor.

      Hotkeys, I use CTRL+R in image above to signal replace tile action and I use "G" to Get the tile under mouse.
      Hotkeys are not saved to disk and thus are set to default between sessions.
      I might draw the world to pre-rendered surfaces and use them as multi-layer someday.  I do that in my AutoIt, DragonWarrior Remake but I could spend forever unsure what features are important for this.  The DW_Remake has a method of replacing a tile with a tile on two layers.  So you could replace a tree on the first layer with a grass, and a tree in the second layer.  This is all getting very confusing.
      I attempted to write the good code.  If something could be better, please advise.
      Fifth release.  Enjoy.
      For download, videos, and example of created world file data; please visit the MapIt webpage: http://songersoft.com/programming/mapit/mapit_about.phtml
      Special thanks: @AdmiralAlkex, @Melba23, @MrCreatoR
      Main AutoIt source file: Will not run without other Includes and SDL DLLs.
      Last Update: 5/26/2018 3:45 PM EST
      REMOVED CODE BLOCK:  I was informed the this page loaded very slowly, one solution so far has been to remove the 2k lines in the code block.
      When I recieve more feedback from the User I may reduce image size or remove images.
      Next Version Added: $eSETTING_TILE_LAST_PATH I have the weekend, I want to write world layers with aBoard surfaces.  
    • lenclstr746
      By lenclstr746
      HELLO GUYS
      I'm a work on a background see and click bot project 
      I can complete it if your help me
      (using imagesearch , gdi+ and  fastfind)
    • dadalt95
      By dadalt95
      I would like to know if it's possible to pass an image recognition (captcha) system.
       
      What are the ways to achieve this?
      Just the references or links is enough for me by now.
       
      Thanks by now!
       
      Thanks!
    • c.haslam
      By c.haslam
      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.


    • fatpig
      By fatpig
      Dear AutoIT Community.
      I am currently working on a program that will display lots of images in a scroll down GUI.
      I create the GUI based on the number of images, which works fine.
      But all images I place using GuiCtrlCreatePic above a threshold of around 32000 pixels (cant say exactly) are placed at negative locations and finally will reach 0 again
      and will then populate on top of the images placed there before.
      For $i = 1 To $Images[0] ; Get picture dimensions $hImage = _GDIPlus_ImageLoadFromFile($ImgRep & $Images[$i]) $iX = _GDIPlus_ImageGetWidth($hImage) $iY = _GDIPlus_ImageGetHeight($hImage) _GDIPlus_ImageDispose($hImage) ; Resize & place images in GUI $Pic[$i] = GUICtrlCreatePic($ImgRep & $Images[$i], $Spacer, Round($yPos, 0), $MaxImgWidth, $MaxImgWidth * ($iY / $iX)) $yPos = $yPos + $MaxImgWidth * ($iY / $iX) + $Spacer $log = $log & "|" & $yPos $currentlut = $Images[1] Next I have found a limit at 32767 pixels for some GUI elements when googling around.
      Can someone tell me how to circumvent that?
      thanks!
      cheers
      Felix
×