Jump to content

Selecting and cropping pic on GUI


Recommended Posts

I got a start with http://www.autoitscript.com/forum/index.php?showtopic=111185&st=0

But I've gone a bit outside the scope so I decided to open a new thread.

So you know where I'm going with this, I'm trying to:

1) Create a GUI that can load an image from the clipboard.

2) Allow the user to select of area of that graphic to crop.

3) Save the cropped image as a PNG or JPG

Question 1

I modified the script above and successfully created a window that I can use to make my selection.

But the exit button and "X" won't respond so I can't close the window.

Along with any other control I'd create.

Question 2

And I can't restrict the selection to the window i created.

I tried this in the func, but it caused the window to flash

;ElseIf Not WinActive($hCross_GUI) Then ; Window flashes if this statement is active
  ; GUIDelete($hRectangle_GUI)
  ; DllClose($UserDLL)
  ; Return 0
  EndIf

Question 3

Does anyone know how I can load an image in the clipboard into a GUI?

Image is generated by printscreen button.

Thanks,

Kenny

#cs ----------------------------------------------------------------------------
AutoIt Version: 3.3.6.1
Author:         Kenneth P. Morrissey

Script Function:
Create selection rectangle within an AutoIT window.
#ce ----------------------------------------------------------------------------

; Credit: Malkey for the basic GDI code
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#Include <Misc.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
Global $iTolerance = 30, $iX1, $iY1, $iX2, $iY2, $fType = ""

HotKeySet("{F3}", "ExitNow")

; Create transparent GUI with Cross cursor
$hCross_GUI = GUICreate("Test", 400, 400, -1, -1, "", $WS_EX_TOPMOST)
GUISetState(@SW_SHOW, $hCross_GUI)
GUISetCursor(3, 1, $hCross_GUI)
$button = GUICtrlCreateButton("exit",10,10, 100)

;Loop waiting for Mark_Rect() to confirm coords withing GUI window.
While 1
$msg = GUIGetMsg()
Switch $msg
  Case $GUI_EVENT_CLOSE
   Exit
  Case $button
   Exit
EndSwitch
$Return = Mark_Rect()
If $Return Then MsgBox(262144, "", $iX1 & @CR & $iY1 & @CR & $iX2 & @CR & $iY2)
Sleep(10)
WEnd

Func ExitNow()
Exit
EndFunc

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

    Global $hRectangle_GUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW + $WS_EX_TOPMOST)
    GUISetBkColor(0x000000)

    ; 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)
  $WinPos = WinGetPos($hCross_GUI)
  $WinPos[2] = $WinPos[0] + $WinPos[2]
  $WinPos[1] = $WinPos[1] + 70
  $WinPos[3] = $WinPos[1] + $WinPos[3]
        $aMouse_Pos = MouseGetPos()

  If $aMouse_Pos[0] < $WinPos[0] OR $aMouse_Pos[1] > $WinPos[3] Then
   GUIDelete($hRectangle_GUI)
   DllClose($UserDLL)
   Return 0
  ElseIf $aMouse_Pos[1] < $WinPos[1] OR $aMouse_Pos[1] > $WinPos[3] Then
   GUIDelete($hRectangle_GUI)
   DllClose($UserDLL)
   Return 0
  ;ElseIf Not WinActive($hCross_GUI) Then ; Window flashes if this statement is active
  ; GUIDelete($hRectangle_GUI)
  ; DllClose($UserDLL)
  ; Return 0
  EndIf

        $hMaster_Mask = _WinAPI_CreateRectRgn(0, 0, 0, 0)
        $hMask = _WinAPI_CreateRectRgn($iX1,  $aMouse_Pos[1], $aMouse_Pos[0],  $aMouse_Pos[1] + 1) ; Bottom of rectangle
        _WinAPI_CombineRgn($hMaster_Mask, $hMask, $hMaster_Mask, 2)
        _WinAPI_DeleteObject($hMask)
        $hMask = _WinAPI_CreateRectRgn($iX1, $iY1, $iX1 + 1, $aMouse_Pos[1]) ; Left of rectangle
        _WinAPI_CombineRgn($hMaster_Mask, $hMask, $hMaster_Mask, 2)
        _WinAPI_DeleteObject($hMask)
        $hMask = _WinAPI_CreateRectRgn($iX1 + 1, $iY1 + 1, $aMouse_Pos[0], $iY1) ; Top of rectangle
        _WinAPI_CombineRgn($hMaster_Mask, $hMask, $hMaster_Mask, 2)
        _WinAPI_DeleteObject($hMask)
        $hMask = _WinAPI_CreateRectRgn($aMouse_Pos[0], $iY1, $aMouse_Pos[0] + 1,  $aMouse_Pos[1]) ; Right of rectangle
        _WinAPI_CombineRgn($hMaster_Mask, $hMask, $hMaster_Mask, 2)
        _WinAPI_DeleteObject($hMask)
        ; Set overall region
        _WinAPI_SetWindowRgn($hRectangle_GUI, $hMaster_Mask)

        If WinGetState($hRectangle_GUI) < 15 Then GUISetState()
        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)

If $iX1 = $iX2 OR $iY1 = $iY2 Then Return 0

Return 1
EndFunc   ;==>Mark_Rect
Edited by ken82m

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

oh and the reason I'm doing this is I'm running some stupid new program.

And it screws with every screen shot app out there including AU3's functions.

The only thing that gives me a screenshot right now is the actual "PRINTSCREEN" button on my keyboard.

I'm trying to come up with something like one of my screen shot apps instead of dealing with paint or photoshop or whatever.

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

This works on my XP.

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
#include <ClipBoard.au3>
#include <Misc.au3>
; http://www.autoitscript.com/forum/index.php?showtopic=114679&view=findpost&p=801509
Opt("MouseCoordMode", 2) ;1=absolute, 0=relative, 2=client
HotKeySet("{F3}", "_SaveRect")

Global $hGui, $hGraphicGUI, $hBMPBuff, $aSP, $aMP, $GuiSizeX = 800, $GuiSizeY = 600
Local $hBMP, $hImage, $hGraphic
Local $x = 0, $y = 0, $w = @DesktopWidth, $h = @DesktopHeight ; Prnt Scrn size

Send("{PRINTSCREEN}") ; Screen
;Send("!{PRINTSCREEN}") ; window

$hGui = GUICreate("Press[F3] to save red rectangle area.", $GuiSizeX, $GuiSizeY)
GUISetState()

; Open the clipboard
If Not _ClipBoard_Open(0) Then _WinAPI_ShowError("_ClipBoard_Open failed")
$hBMP = _ClipBoard_GetDataEx($CF_BITMAP)

_GDIPlus_Startup()
$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)

;Graphics here

;_GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFE8)
$hPen = _GDIPlus_PenCreate(0xFFFF0000, 1)
_GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hImage, $x, $y, $w, $h, 0, 0, $GuiSizeX, $GuiSizeY)

;End of graphics

GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            _GDIPlus_PenDispose($hPen)
            _GDIPlus_ImageDispose($hImage)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_GraphicsDispose($hGraphicGUI)
            _GDIPlus_BitmapDispose($hBMPBuff)
            _GDIPlus_Shutdown()
            _ClipBoard_Close()
            Exit
    EndSwitch
    If _IsPressed("01") Then
        $aSP = MouseGetPos() ;mouse Start Position
        Do
            $aMP = MouseGetPos()
            _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFE8)
            _GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hImage, $x, $y, $w, $h, 0, 0, $GuiSizeX, $GuiSizeY)
            _GDIPlus_GraphicsDrawRect($hGraphic, $aSP[0], $aSP[1], $aMP[0] - $aSP[0], $aMP[1] - $aSP[1], $hPen)
            _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
            Sleep(10)
        Until Not _IsPressed("01")
    EndIf
WEnd


Func _SaveRect()
    Local $ScaleX = @DesktopWidth / $GuiSizeX, $ScaleY = @DesktopHeight / $GuiSizeY
    Local $hClone = _GDIPlus_BitmapCloneArea($hImage, $aSP[0] * $ScaleX, $aSP[1] * $ScaleY, ($aMP[0] - $aSP[0]) * $ScaleX, ($aMP[1] - $aSP[1]) * $ScaleY, $GDIP_PXF32ARGB)
    _GDIPlus_ImageSaveToFile($hClone, @DesktopDir & "\Imagetst.tif") ;$sNewName)
    _GDIPlus_BitmapDispose($hClone)
    ShellExecute(@DesktopDir & "\Imagetst.tif")
EndFunc ;==>_SaveRect

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW))
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    Return $GUI_RUNDEFMSG
EndFunc ;==>MY_PAINT

Edit: Added _GDIPlus_PenDispose($hPen). :20 May 2010 - 01:29 PM

Edit: Deleted _WinAPI_DeleteObject($hBMP) altogether. Clipboard controls the handle returned from _ClipBoard_GetDataEx().

Changed all remaining _WinAPI_DeleteObject() to _GDIPlus_BitmapDispose ().

Edited by Malkey
Link to comment
Share on other sites

That's working greate thanks!

I made a few changes so it would keep running in the background letting me take more screenshots.

#include <ClipBoard.au3>
#include <_FileSaveDialog.au3>
#include <GDIPlus.au3>
#include <GuiConstants.au3>
#include <Misc.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

; [url="http://www.autoitscript.com/forum/index.php?showtopic=114679&view=findpost&p=801509"]http://www.autoitscript.com/forum/index.php?showtopic=114679&view=findpost&p=801509[/url]
Opt("MouseCoordMode", 2) ;1=absolute, 0=relative, 2=client
HotKeySet("{F3}", "_SaveRect")
HotKeySet("{F9}", "_Exit")

Global $hGui, $hGraphicGUI, $hBMPBuff, $aSP, $aMP, $GuiSizeX = @DesktopWidth-50, $GuiSizeY = @DesktopHeight-50, $hImageHeight = 0, $hImageHeight = 0
Local $hBMP, $hImage, $hGraphic, $w, $h
Local $x = 0, $y = 0, $w = @DesktopWidth, $h = @DesktopHeight ; Prnt Scrn size

;Kenny Test============================
HotKeySet("{PRINTSCREEN}", "_PrtScr")
HotKeySet("!{PRINTSCREEN}", "_AltPrtScr")

While 1
 Sleep(100)
WEnd

Func _PrtScr()
 HotKeySet("{PRINTSCREEN}")
 Send("{PRINTSCREEN}")
 HotKeySet("{PRINTSCREEN}", "_PrtScr")
 _EditShot()
EndFunc ;==> _PrtScr

Func _AltPrtScr()
 HotKeySet("!{PRINTSCREEN}")
 Send("!{PRINTSCREEN}")
 HotKeySet("!{PRINTSCREEN}", "_AltPrtScr")
 _EditShot()
EndFunc ;==> _AltPrtScr

Func _Exit()
 Exit
EndFunc ;==> _Exit
;Kenny Test==============================

Func _EditShot()
$hGui = GUICreate("Press[F3] to save red rectangle area.", $GuiSizeX, $GuiSizeY, -1, -1, $WS_MAXIMIZE)
$filemenu = GUICtrlCreateMenu("&File")
$SaveBtn = GUICtrlCreateMenuItem("Save Image", $filemenu)
GUICtrlCreateMenuItem("", $filemenu, 2)   ; create a separator line
$CloseBtn = GUICtrlCreateMenuItem("Close Window", $filemenu)
GUISetState()

; Open the clipboard
If Not _ClipBoard_Open(0) Then _WinAPI_ShowError("_ClipBoard_Open failed")
$hBMP = _ClipBoard_GetDataEx($CF_BITMAP)

_GDIPlus_Startup()
$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
MsgBox(0,"",$hImageHeight & @Cr & $hImageWidth)
;Graphics here

;_GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFE8)
$hPen = _GDIPlus_PenCreate(0xFFFF0000, 1)
_GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hImage, $x, $y, $w, $h, 0, 0, $GuiSizeX, $GuiSizeY)

;End of graphics

GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            _GDIPlus_PenDispose($hPen)
            _GDIPlus_ImageDispose($hImage)
            _WinAPI_DeleteObject($hBMP)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_GraphicsDispose($hGraphicGUI)
            _WinAPI_DeleteObject($hBMPBuff)
            _GDIPlus_Shutdown()
            _ClipBoard_Close()
   GUIDelete($hGui)
            Return;Exit
  Case $CloseBtn
            _GDIPlus_PenDispose($hPen)
            _GDIPlus_ImageDispose($hImage)
            _WinAPI_DeleteObject($hBMP)
            _GDIPlus_GraphicsDispose($hGraphic)
            _GDIPlus_GraphicsDispose($hGraphicGUI)
            _WinAPI_DeleteObject($hBMPBuff)
            _GDIPlus_Shutdown()
            _ClipBoard_Close()
   GUIDelete($hGui)
            Return;Exit
  Case $SaveBtn
   _SaveRect()
    EndSwitch
    If _IsPressed("01") Then
        $aSP = MouseGetPos() ;mouse Start Position
        Do
            $aMP = MouseGetPos()
            _GDIPlus_GraphicsClear($hGraphic, 0xFFE8FFE8)
            _GDIPlus_GraphicsDrawImageRectRect($hGraphic, $hImage, $x, $y, $w, $h, 0, 0, $GuiSizeX, $GuiSizeY)
            _GDIPlus_GraphicsDrawRect($hGraphic, $aSP[0], $aSP[1], $aMP[0] - $aSP[0], $aMP[1] - $aSP[1], $hPen)
            _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
            Sleep(10)
        Until Not _IsPressed("01")
    EndIf
WEnd
EndFunc ;==>_EditShot


Func _SaveRect()
 $sFilter = "PNG image (*.png)|*.png|JPEG image (*.jpg)|*.jpg|TIF image (*.tif)|*.tif|Bitmap image (*.bmp)|*.bmp|GIF image (*.gif)|*.gif"
 ;$SaveFile = _FileSaveDialog("Save As", @DesktopDir, $sFilter, 16+2, "", 1, $hGui)
 $SaveFile = FileSaveDialog("Save As", @DesktopDir, $sFilter, 16+2, "", $hGui)
 FileDelete($SaveFile)

 Local $ScaleX = @DesktopWidth / $GuiSizeX, $ScaleY = @DesktopHeight / $GuiSizeY
    Local $hClone = _GDIPlus_BitmapCloneArea($hImage, $aSP[0] * $ScaleX, $aSP[1] * $ScaleY, ($aMP[0] - $aSP[0]) * $ScaleX, ($aMP[1] - $aSP[1]) * $ScaleY, $GDIP_PXF32ARGB)
 ;_GDIPlus_ImageSaveToFile($hClone, $SaveFile)
    If Not _GDIPlus_ImageSaveToFile($hClone, $SaveFile) Then
  MsgBox(0, "Save File", "An error occured saving the image")
 Else
  ShellExecute($SaveFile)
 EndIf
    _WinAPI_DeleteObject($hClone)
EndFunc ;==>_SaveRect

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW))
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    Return $GUI_RUNDEFMSG
EndFunc ;==>MY_PAINT

I only have one problem, if I hit the save button without selecting anything it blows up.

I tried pulling the dimensions from the clipboard.

Then I could just play with $aSP/$aMP so that the coords cover the entire image.

$hImageHeight = _GDIPlus_ImageGetHeight($hImage)
$hImageWidth = _GDIPlus_ImageGetWidth($hImage)

But those functions always return a number larger that the actual image.

For example, the windows Calculator:

The image is actually 144x240

But $hImageWidth/Height return 230x324

And is it possible to refresh the screen?

When I make a selection, to just show the cropped image?

Thanks,

Kenny

 "I believe that when we leave a place, part of it goes with us and part of us remains... Go anywhere, when it is quiet, and just listen.. After a while, you will hear the echoes of all our conversations, every thought and word we've exchanged.... Long after we are gone our voices will linger in these walls for as long as this place remains."

Link to comment
Share on other sites

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...