AutoHotkey Community

It is currently May 27th, 2012, 2:25 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 21 posts ]  Go to page Previous  1, 2
Author Message
 Post subject:
PostPosted: March 4th, 2009, 3:48 pm 
Offline

Joined: March 4th, 2009, 3:27 pm
Posts: 25
Hi everyone,
I've enhanced a bit this code (thanks shimanov!):
- draws lines! (not dots nor squares ; uses Bresenham algorithm)
- left-click: draw
- right-click: erase
- no-click: nothing
- Escape : quits program
- F1: toggle colors (the 16 basic colors)
- F2: erases screen
- F3/F4: decreases/increases width of pen (default=4, but it draws an horizontal line, not a square nor a circle. I thought it would be faster)
[Edit:]
- saves the mouse moves to "painting.ahk". Launching this scripts opens MSPaint and redraws what was drawn!

[Edit v1.5:]
- Multiple displays support

Enjoy!

For the license, I wanted to put GPL 3, but this requires the acknowledgement of all the contributors...

Code:
; from:
; http://www.autohotkey.com/forum/viewtopic.php?p=253705#253705
; Shimanov, Metaxal, maximo3491
; If Shimanov agrees:
; GNU General Public License 3.0 or higher <http://www.gnu.org/licenses/gpl-3.0.txt>

; Version 1.5 - Metaxal 2010/06/05
;   - added multiple display support

color_names=0x000000,0xC0C0C0,0x808080,0xFFFFFF,0x800000,0xFF0000,0x800080,0xFF00FF,0x008000,0x00FF00,0x808000,0xFFFF00,0x000080,0x0000FF,0x008080,0x00FFFF
;Black,Silver,Gray,White,Maroon,Red,Purple,Fuchsia,Green,Lime,Olive,Yellow,Navy,Blue,Teal,Aqua
max_width = 20 ; max width of the brush
log_movement = 1 ; 0 for false, 1 for true

CoordMode, Mouse, Screen

Process, Exist
pid_this := ErrorLevel

hdc_screen := DllCall( "GetDC", "uint", 0 )

; Get the number of monitors:
SysGet, MonitorCount, MonitorCount

MonitorNum := 1 ; primary monitor

; if multiple displays:
if (MonitorCount > 1) {
    Gui, Add, Text,, Select the display:
    Gui, Add, UpDown, vMonitorNum Range1-%MonitorCount%, 1
    Gui, Add, Button, default, OK  ; The label ButtonOK (if it exists) will be run when the button is pressed.
    Gui, Show
    return  ; End of auto-execute section. The script is idle until the user does something.

}

ButtonOK:
Gui, Submit
Gui, Destroy
Sleep, 100 ; wait for the GUI to hide

SysGet, Screen, Monitor, %MonitorNum%
; -> creates the 4 variables ScreenLeft, ScreenTop, ScreenRight, ScreenBottom

ScreenWidth := ScreenRight - ScreenLeft
ScreenHeight := ScreenBottom - ScreenTop


hdc_buffer := DllCall( "CreateCompatibleDC", "uint", hdc_screen )
hbm_buffer := DllCall( "CreateCompatibleBitmap", "uint", hdc_screen, "int", ScreenWidth, "int", ScreenHeight )
DllCall( "SelectObject", "uint", hdc_buffer, "uint", hbm_buffer )

DllCall( "BitBlt", "uint", hdc_buffer, "int", 0, "int", 0, "int", ScreenWidth, "int", ScreenHeight, "uint", hdc_screen, "int", ScreenLeft, "int", ScreenTop, "uint", 0x00CC0020 )

; Create a (completely transparent) window with the size of the display
Gui, +AlwaysOnTop -Caption
Gui, Show, x%ScreenLeft% y%ScreenTop% w%ScreenWidth% h%ScreenHeight%

WinGet, hw_canvas, ID, ahk_class AutoHotkeyGUI ahk_pid %pid_this%

; Get the canvas of the created window
hdc_canvas := DllCall( "GetDC", "uint", hw_canvas )

; Begin by drawing the background in the canvas
DllCall( "BitBlt", "uint", hdc_canvas, "int", 0, "int", 0, "int", ScreenWidth, "int", ScreenHeight, "uint", hdc_buffer, "int", 0, "int", 0, "uint", 0x00CC0020 )

; not exactly because colors are reverse in SetPixel...
StringSplit colors, color_names, `,
color_index := 14
color := colors%color_index%

width := 4
x_last := 0
y_last := 0

SetBatchLines, -1

if log_movement
{
    log := "CoordMode, Mouse, Screen`n"
    log .= "SetMouseDelay 2`n"
    log .= "Run, MSPaint,,, pid_var`n"
    log .= "WinWait ahk_pid %pid_var%,, 3`n"
}

left_down := false
right_down := false

/*
http://msdn.microsoft.com/en-us/library/ms645616(VS.85).aspx
wParam:
*/
WM_MOUSEMOVE = 0x0200
/*
; numbers
MK_CONTROL  := 0x0008
MK_LBUTTON  := 0x0001
MK_MBUTTON  := 0x0010
MK_RBUTTON  := 0x0002
MK_SHIFT    := 0x0004
MK_XBUTTON1 := 0x0020
MK_XBUTTON2 := 0x0040
*/

OnMessage( WM_MOUSEMOVE, "HandleMessage" )
return

HandleMessage( p_w, p_l )
{
   global hdc_canvas, hdc_buffer, x_last, y_last, width, color, left_down, right_down, log, log_movement, ScreenLeft, ScreenTop

   x := (p_l & 0xFFFF)
   y := (p_l >> 16)

   lbutton := p_w & 0x0001 ; MK_LBUTTON
   rbutton := p_w & 0x0002 ; MK_RBUTTON

   if (lbutton) {
      if log_movement
        log .= "`nMouseMove " . x . ", " . y
      if not left_down {
         left_down := true
         if log_movement
            log .= "`nMouseClick, Left, ,,,, D"
      } else
         drawLine(x_last, y_last, x, y, color, width)
   } else if (rbutton) {
      if log_movement
        log .= "`nMouseMove " . x . ", " . y
      if not right_down {
         right_down := true
         if log_movement
            log .= "`nMouseClick, Right, ,,,, D"
      } else
         drawLine(x_last, y_last, x, y, "ERASE", width)
   } else {
      if (left_down) {
         left_down := false
         if log_movement
            log .= "`nMouseClick, Left, ,,,, U"
      }
      if (right_down) {
         right_down := false
         if log_movement
            log .= "`nMouseClick, Right, ,,,, U"
      }
   }
     
   x_last := x
   y_last := y
}


drawLine(x0, y0, x1, y1, color_ini=0, width=1)
{
   dx := x1 - x0
   dy := y1 - y0
   
   dxy := (Abs(dx) > Abs(dy) ? Abs(dx) : Abs(dy) )
   
   dx := dx / dxy
   dy := dy / dxy
   
   Loop %dxy%
   {
      x0 += dx
      y0 += dy
   
     drawCircle(Round(x0),round(y0), color_ini)
   }
}

drawCircle(x,y, color_ini) {
    global hdc_buffer, hdc_canvas, width, ScreenLeft, ScreenTop, ScreenWidth, ScreenHeight

    cRegion := DllCall( "gdi32.dll\CreateRoundRectRgn", "int", x-width , "int", y-width , "int", x+width , "int", y+width, "int", width*2, "int", width*2 )
    cBrush := DllCall("gdi32.dll\CreateSolidBrush", "uint", color_ini )


    if color_ini=ERASE
    {
        ; from http://msdn.microsoft.com/en-us/library/dd183437%28VS.85%29.aspx
        ; Select clipping region
        DllCall( "SelectClipRgn", "uint", hdc_canvas, "uint", cRegion )
     
        ; Transfer (draw) the bitmap into the clipped rectangle.
        DllCall( "BitBlt", "uint", hdc_canvas, "int", 0, "int", 0, "int", ScreenWidth, "int", ScreenHeight, "uint", hdc_buffer, "int", 0, "int", 0, "uint", 0x00CC0020 )
       
        ; Select the full region back
        DllCall( "SelectClipRgn", "uint", hdc_canvas, "uint", 0 )
    }
    else
        DllCall( "gdi32.dll\FillRgn" , "uint", hdc_canvas , "uint", cRegion , "uint", cBrush )

    DllCall("gdi32.dll\DeleteObject", "uint", cRegion)
    DllCall("gdi32.dll\DeleteObject", "uint", cBrush)
}

F1::
   color_index++
   if(color_index > 16)
      color_index := 1
   color := colors%color_index%
return
   

F2::
   DllCall( "BitBlt", "uint", hdc_canvas, "int", 0, "int", 0, "int", ScreenWidth, "int", ScreenHeight, "uint", hdc_buffer, "int", 0, "int", 0, "uint", 0x00CC0020 )
return

F3::
   if width > 1
      width--
return

F4::
   if width < %max_width%
      width++
return

Escape::
FileDelete, painting.ahk
if log_movement
   FileAppend, %log%, painting.ahk
ExitApp



Last edited by Metaxal on June 5th, 2010, 12:55 pm, edited 3 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 4th, 2009, 5:58 pm 
Offline

Joined: August 21st, 2006, 7:07 pm
Posts: 2925
Location: The Shell
That is genius!

I was wondering, the mouse can tracked so therefore is it reasonable to assume that there is a way to plot the lines as vectors? It would be great to be able to save this info as plot data.

Perhaps this could assist in implementing a save image feature (think of the applications)?

I tried getting a close up view on lines being drawn by using Magnifier but it goes grey once the script starts. Is there a screen grab happening at the start?

Great work on this :D!

_________________
Imageparadigm.shift:=(•_•)┌П┐RTFM||^.*∞


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 5th, 2009, 11:43 am 
Offline

Joined: March 4th, 2009, 3:27 pm
Posts: 25
I added a mouse tracker, thought this could probably have been done with AutoScriptWriter and others.
It creates an ahk script that redraws the whole thing into MSPaint.

As for image saving, this could be done, I think, by a DllCall, simply saving the Bitmap Section into a file.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: March 7th, 2009, 5:32 pm 
Offline

Joined: March 4th, 2009, 3:27 pm
Posts: 25
Continued on:
http://www.autohotkey.com/forum/viewtopic.php?p=254474


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 9th, 2010, 6:19 am 
Metaxal wrote:
uses Bresenham algorithm

...I still don't know what that means, but looking at the code, very quickly, it looks like it means you try to "figure out" how to draw a line, pixel by pixel, plz Google for the WinAPI function LineTo...that should be much easier than "Bresenham algorithm"...not sure how to handle a "line" erase, tho...in my code I have it drawing a circle & erasing a square, cuz I couldn't find a way to BitBlt/erase a circle...


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: February 9th, 2010, 9:42 am 
Offline

Joined: March 4th, 2009, 3:27 pm
Posts: 25
Drawing lines has been improved (still not using LineTo though).
Please see :
http://www.autohotkey.com/forum/viewtopic.php?p=254474


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 21 posts ]  Go to page Previous  1, 2

All times are UTC [ DST ]


Who is online

Users browsing this forum: Alpha Bravo, Google [Bot], LazyMan, rbrtryn and 23 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group