I had tried something similar with detecting and sending clicks to MS Paint, but it didn't work very well, so in effect I ended up creating the basis of a bitmap editor in order to achieve this.
If anyone has built a bitmap editor in AutoHotkey it would be nice to know. It would not necessarily be so difficult to achieve this, although certain features could be trickier to implement.
I have a few queries:
- which is the better approach for constant screen updating: STM_SETIMAGE or UpdateLayeredWindow?
- could the script be modified to show a standard GUI window, with other controls ... is it possible to draw on top of some/all of a window/control (I had some trouble trying to achieve this, I'm not familiar with WS_EX_LAYERED or layered windows)
- anything to smoothen/quicken the drawing of pixels when the mouse is held down (e.g. MS Paint (Windows XP) is very responsive)
Code: Select all
;kaleidoscope/brush mirrors by jeeswg
;this script could also form the basis of a bitmap editor
;based on Gdip.Tutorial.12-Pixelate.a.bitmap.using.machine.code.ahk
;requires Gdip.ahk or Gdip_All.ahk
#SingleInstance, Force
#NoEnv
SetBatchLines, -1
ListLines, Off
;settings:
vDoKaleidoscope := 1 ;similar to Brush Mirrors (MacPaint)
vColFgd := 0xff008080 ;teal
vColBgd := 0xffffff00 ;yellow
;colour list:
;Progress/SplashImage
;https://autohotkey.com/docs/commands/Progress.htm
pToken := Gdip_Startup()
OnExit, Exit
Gui, 1: -Caption +E0x80000 +LastFound +OwnDialogs +Owner +HwndhWnd1
Gui, 1: Show, NA
GroupAdd, WinGroupGui, % "ahk_id " hWnd1
vImgW := 600, vImgH := 600
;increase width/height if not multiples of 8 (each 'pixel' is 8x8)
Mod(vImgW, 8) && vImgW := vImgW - Mod(vImgW, 8) + 8
Mod(vImgH, 8) && vImgH := vImgH - Mod(vImgH, 8) + 8
;increase width/height if not multiples of 32 (each 'pixel' is 8x8, and there are 4 quadrants, 8*4=32)
Mod(vImgW, 32) && vImgW := vImgW - Mod(vImgW, 32) + 32
Mod(vImgH, 32) && vImgH := vImgH - Mod(vImgH, 32) + 32
pBitmap := Gdip_CreateBitmap(vImgW, vImgH)
hbm := CreateDIBSection(vImgW, vImgH), hdc := CreateCompatibleDC(), obm := SelectObject(hdc, hbm)
G := Gdip_GraphicsFromHDC(hdc)
pBrush := pBrushFgd := Gdip_BrushCreateSolid(vColFgd)
pBrushBgd := Gdip_BrushCreateSolid(vColBgd)
vColIsFgd := 1
Gdip_FillRectangle(G, pBrushBgd, vX, vY, vImgW, vImgH)
;OnMessage(0x201, "WM_LBUTTONDOWN")
UpdateLayeredWindow(hWnd1, hdc, (A_ScreenWidth-vImgW)//2, (A_ScreenHeight-vImgH)//2, vImgW, vImgH)
return
;==================================================
#IfWinActive, ahk_group WinGroupGui
q:: ;draw a pixel
~LButton:: ;draw a pixel
Loop
{
if (A_Index > 1)
&& (!GetKeyState("LButton", "P") || InStr(A_ThisHotkey, "q"))
break
MouseGetPos, vX, vY, hWnd2
if (vX = vXLast) && (vY = vYLast)
continue
vXLast := vX, vYLast := vY
if !(hWnd1 = hWnd2)
return
vX := vX - Mod(vX, 8) + 4, vY := vY - Mod(vY, 8) + 4
Gdip_FillRectangle(G, pBrush, vX-4, vY-4, 8, 8)
if vDoKaleidoscope
{
vX2 := vImgW - vX, vY2 := vImgH - vY
Gdip_FillRectangle(G, pBrush, vX-4, vY2-4, 8, 8)
Gdip_FillRectangle(G, pBrush, vX2-4, vY-4, 8, 8)
Gdip_FillRectangle(G, pBrush, vX2-4, vY2-4, 8, 8)
}
UpdateLayeredWindow(hWnd1, hdc, (A_ScreenWidth-vImgW)//2, (A_ScreenHeight-vImgH)//2, vImgW, vImgH)
}
return
;==================================================
w:: ;save current image to file
vPath = %A_Desktop%\z %A_Now%.png
pBitmap2 := Gdip_CreateBitmapFromHBITMAP(hbm)
Gdip_SaveBitmapToFile(pBitmap2, vPath, 100)
Gdip_DisposeImage(pBitmap2)
return
;==================================================
e:: ;set paintbrush colour to foreground/background colour
vColIsFgd := !vColIsFgd
pBrush := vColIsFgd ? pBrushFgd : pBrushBgd
MsgBox, % "colour is " (vColIsFgd ? "foreground" : "background")
return
;==================================================
WM_LBUTTONDOWN()
{
PostMessage, 0xA1, 2 ;WM_NCLBUTTONDOWN := 0xA1
}
;==================================================
Esc::
Exit:
Gdip_DisposeImage(pBitmap)
SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
Gdip_DeleteGraphics(G)
Gdip_DeleteBrush(pBrushFgd), Gdip_DeleteBrush(pBrushBgd)
Gdip_Shutdown(pToken)
ExitApp
return