Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

ScreenMagnifier


  • Please log in to reply
104 replies to this topic
Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
It's time this great topic got a bump. Furthermore, I've added a link to it from the script showcase. Holomind, if you'd like to edit the wording below, feel free to send me a revised version:

Screen Magnifier -- by Holomind: This screen magnifier has the several advantages over the one included with the operating system, including: Customizable refresh interval and zoom level (including shrink/de-magnify); antialiasing to provide nicer output; and it is open-source (as a result, there are several variations to choose from, or you can tweak the script yourself).



Timothy
  • Guests
  • Last active:
  • Joined: --
What's the code for copying transparent windows and tooltips?

holomind
  • Members
  • 341 posts
  • Last active: Aug 23 2015 03:27 PM
  • Joined: 11 Mar 2006
i guess its not easy to copy transparent windows with bitblt.
i think transparent windows are rendered by hardware and are a kind of overlay like accellerated video. it would be possible to capture this windows with directx or opengl which can access the "pixels" in the overlay.

ivanw
  • Members
  • 13 posts
  • Last active: Aug 23 2011 01:32 PM
  • Joined: 26 Dec 2006
As I am rather satisfied with what I could do based on information from this thread, I thought it would be fair to share a somewhat newer version.

I have a Microsoft Mouse which activates the intelliPoint magnifier. This one is really nice as it is part of the MS driver. I recently acquired the MX "best mouse ever" from Logitech and I miss this tool I’ve come to depend on.

In an attempt to make something as close as possible, I could find the best part of what I needed to know about AutoHotkey to do something I am rather happy with... Here it is:

Features:
Has no frame, just a thin border
Follows mouse - unless you hit the spacebar to stick it in place
Scalable - scrollwheel
Resizable - shift scrollwheel

; Autohotkey script "Screen Magnifier"
;=================================================================================
#SingleInstance ignore
Process, Priority, , High
OnExit handle_exit
hotkey, Space,  toggle_follow
hotkey, Escape, GuiClose
hotkey, F18,    GuiClose
; Init variables
  follow    := 1
  ZOOMFX    := 1.189207115
  zoom      := 2
  antialias := 1
  delay     := 10

  whMax     := 400
  wh        := 200
  whMin     := 100

  wwMax     := 800
  ww        := 480
  wwMin     := 200


  mx        := 0
  my        := 0
  mxp       := mx
  myp       := my
  wwD       := 0
  whD       := 0


; Init zoom window

  MouseGetPos, mx, my

  Gui, +AlwaysOnTop  +Owner -Resize -ToolWindow +E0x00000020
  Gui, Show, NoActivate W%ww% H%wh% X-1000 Y-1000, MagWindow ; start offscreen

  WinSet, Transparent  , 254, MagWindow
  Gui, -Caption
  Gui, +Border

  WinGet, PrintSourceID, id
  hdd_frame := DllCall("GetDC", UInt, PrintSourceID)

  WinGet, PrintScreenID,  id, MagWindow
  hdc_frame := DllCall("GetDC", UInt, PrintScreenID)
  if(antialias != 0)
      DllCall("gdi32.dll\SetStretchBltMode", "uint", hdc_frame, "int", 4*antialias)


Gosub, Repaint
return
;=================================================================================
; Input events

WheelUp::       ; zoom in
  if zoom < 4
      zoom *= %ZOOMFX%
return

WheelDown::     ; zoom out
  if zoom > %ZOOMFX%
      zoom /= %ZOOMFX%
return


+WheelDown::    ; larger
  wwD =  32
  whD =  32
  Gosub, Repaint
return

+WheelUp::      ; smaller
  wwD = -32
  whD = -32
  Gosub, Repaint
return

;=================================================================================
; toggle_follow
toggle_follow:
    follow := 1 - follow
return

; Repaint
Repaint:
    CoordMode,   Mouse, Screen
    MouseGetPos, mx, my
    WinGetPos,   wx, wy, ww, wh, MagWindow

    if(wwD != 0)
    {
       ww  += wwD
       wh  += whD
       wwD = 0
       whD = 0
    }

    if(mx != mxp) OR (my !- myp)
    {
        DllCall( "gdi32.dll\StretchBlt"
                , UInt, hdc_frame
                , Int , 2                       ; nXOriginDest
                , Int , 2                       ; nYOriginDest
                , Int , ww-6                    ; nWidthDest
                , Int , wh-6                    ; nHeightDest
                , UInt, hdd_frame               ; hdcSrc
                , Int , mx - (ww / 2 / zoom)    ; nXOriginSrc 
                , Int , my - (wh / 2 / zoom)    ; nYOriginSrc 
                , Int , ww / zoom               ; nWidthSrc 
                , Int , wh / zoom               ; nHeightSrc 
                , UInt, 0xCC0020)               ; dwRop (raster operation)

       if(follow == 1)
           WinMove, MagWindow, ,mx-ww/2, my-wh/2, %ww%, %wh%

        mxp = mx
        myp = my
    }

    SetTimer, Repaint , %delay%
return

; GuiClose handle_exit
GuiClose:
handle_exit:
   DllCall("gdi32.dll\DeleteDC"    , UInt,hdc_frame )
   DllCall("gdi32.dll\DeleteDC"    , UInt,hdd_frame )
Process, Priority, , Normal
ExitApp

;=================================================================================


I must add that something is missing here: This script must be started from outside as it only has a an exit point (Escape or F18).

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Very nice! Works perfectly.
If you want to add features:
- I'd like to change the vertical and horizontal size of the magnifier window, independently.
- I'd like to be able to anchor the magnified area, too, such that it does not follow the mouse. (If I play Internet Chess, the time display is too small. It would be nice to be able to show it 4 times magnified in the top center part of the screen, updated real time.)

ivanw
  • Members
  • 13 posts
  • Last active: Aug 23 2011 01:32 PM
  • Joined: 26 Dec 2006
1. Resizing is a nice feature of the MS IntelliPoint version and it should be possible to make it work in this one with AutoHkey.
The expansion is based on dragging the mouse pointer away from the center of the magnification rectangle to expand in both width and/or height.

2. About being able to fix the center of the magnification area, you only have to allow disarming the mx, my sensing in the RePaint function after selection.

May be I'll make those improvements but, as of right now, I miss a good motivation to do so... tomorrow maybe :wink:

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I get empty box!

But I see the goal, and I always wanted that ms mouse just cuz of that....
You should create separate topic for this.
Posted Image

ivanw
  • Members
  • 13 posts
  • Last active: Aug 23 2011 01:32 PM
  • Joined: 26 Dec 2006
majkinetor, I wanted to give credits to people who gave some of their time and effort in this topic.

I've opened a follow up from here with some back-links: ScreenMagnifier - IntelliPoint clone?

Now I don't now what can give you an empty box... As I am an emigrant from the Unix community, my contribution relies 100% on AutoHotkeys as Windows low level calls are concerned... Hopefully, someone will help in the new dedicated thread...

-ivan

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
well, it is probably some trivial thing...

If I find time I will look into it.

Thx for concern.
Posted Image

testzugang
  • Members
  • 2 posts
  • Last active: Jun 14 2007 08:15 PM
  • Joined: 07 Jun 2007
Hi,

really great stuff here :)

I tried to change the source to have three small magnifiers (which magnify the pixel under itself) at the same time. But it doesn't work properly... Maybe there are syntax errors (I'm quite new to ahk...) but I think it's another problem.
I hope somebody can give me a hint...

Process, Priority, , High
OnExit handle_exit
hotkey, Escape, GuiClose

nrW = 3		;number of windows

ZOOMFX    := 1.189207115
zoom      := 2
delay 	  := 100
mx        := 0
my        := 0


Loop %nrW%
{
    ;MsgBox This window will be displayed three times.

;fenster%a_index% = %a_index%
;MsgBox fenster%a_index%


labelW = f%a_index%
ind = %a_index%
wx := ind
wx *= 100
ww := 100

gui %a_index%: +Label%labelW% +AlwaysOnTop -Resize -ToolWindow +E0x00000020


lw = gui %a_index%	;current gui

gui %a_index%: +LastFound
WinSet, Transparent  , 254

gui %a_index%: -Caption +Border


gui %a_index%:show, h30 w%ww% x%wx% y%wx%

Test(lw)

}
return


Test(f)
{
	WinGetPos, wx, wy, ww, wh, f
	
	MsgBox %wx% %wy% %ww% %wh% %f%
	
	WinGet, PrintSourceID, id
	hdd_frame := DllCall("GetDC", UInt, PrintSourceID)

	WinGet, PrintScreenID,  id, %f%
	hdc_frame := DllCall("GetDC", UInt, PrintScreenID)
	MsgBox %hdd_frame% %hdc_frame%
	
	DllCall( "gdi32.dll\StretchBlt"
                , UInt, hdc_frame
                , Int , 2                       ; nXOriginDest
                , Int , 2                       ; nYOriginDest
                , Int , ww-6                    ; nWidthDest
                , Int , wh-6                    ; nHeightDest
                , UInt, hdd_frame               ; hdcSrc
                , Int , wx - (ww / 2 / zoom)    ; nXOriginSrc
                , Int , wy - (wh / 2 / zoom)    ; nYOriginSrc
                , Int , ww / zoom               ; nWidthSrc
                , Int , wh / zoom               ; nHeightSrc
                , UInt, 0xCC0020)               ; dwRop (raster operation)

}


GuiClose:
handle_exit:
   DllCall("gdi32.dll\DeleteDC"    , UInt,hdc_frame )
   DllCall("gdi32.dll\DeleteDC"    , UInt,hdd_frame )
Process, Priority, , Normal
ExitApp

I changed the Repaint label to a function, I think dynamically generated gui only work this way, don't they?

testzugang
  • Members
  • 2 posts
  • Last active: Jun 14 2007 08:15 PM
  • Joined: 07 Jun 2007
I have changed some things but it still doesn't work...

Doesn't anybody know what's missing?

Process, Priority, , High
OnExit handle_exit
hotkey, Escape, GuiClose
nrW = 3		;number of windows
zoom      := 2
delay 	  := 100


WinGet, PrintSourceID, id
hdd_frame := DllCall("GetDC", UInt, PrintSourceID)
MsgBox Main %hdd_frame%

Loop %nrW%
{
	;MsgBox This window will be displayed three times.
	;fenster%a_index% = %a_index%
	;MsgBox fenster%a_index%
	labelW = f%a_index%
	ind = %a_index%
	wx := ind
	wx *= 100
	ww := 100
	gui %a_index%: +Label%labelW% +AlwaysOnTop -Resize -ToolWindow +E0x00000020
	lw = gui %a_index%	;current gui
	gui %a_index%: +LastFound
	WinSet, Transparent  , 254
	gui %a_index%: -Caption +Border
	gui %a_index%:show, h30 w%ww% x%wx% y%wx%

	WinGet, PrintScreenID,  id, %a_index%
	hdc_frame%a_index% := DllCall("GetDC", UInt, PrintScreenID)
	MsgBox % Looping hdc_frame%a_index%

	Test(lw, a_index, hdd_frame, zoom)
}
return


Test(f, c, hdd, z)
{
	WinGetPos, wx, wy, ww, wh, f
	;MsgBox %wx% %wy% %ww% %wh% %f% %c% %z%
	;WinGet, PrintSourceID, id
	;hdd_frame := DllCall("GetDC", UInt, PrintSourceID)
	;WinGet, PrintScreenID,  id, %f%
	;hdc_frame := DllCall("GetDC", UInt, PrintScreenID)
	hdc := % hdc_frame%c%
	MsgBox Test %hdd% - %hdc%
	DllCall( "gdi32.dll\StretchBlt"
            , UInt, hdc
            , Int , 2                       ; nXOriginDest
            , Int , 2                       ; nYOriginDest
            , Int , ww-6                    ; nWidthDest
            , Int , wh-6                    ; nHeightDest
            , UInt, hdd               ; hdcSrc
            , Int , wx - (ww / 2 / z)    ; nXOriginSrc
            , Int , wy - (wh / 2 / z)    ; nYOriginSrc
            , Int , ww / zoom               ; nWidthSrc
            , Int , wh / zoom               ; nHeightSrc
            , UInt, 0xCC0020)               ; dwRop (raster operation)
}

GuiClose:
handle_exit:

DllCall("gdi32.dll\DeleteDC"    , UInt,hdc_frame )
DllCall("gdi32.dll\DeleteDC"    , UInt,hdd_frame )
Process, Priority, , Normal
ExitApp


ricke
  • Members
  • 32 posts
  • Last active: Nov 29 2012 08:59 AM
  • Joined: 14 Sep 2006
So I decided to make my own version of this one.

Amazing work Holomind !!

Cred to all that made it possible..... I have just stolen code from all over the place and put the pieces together.

Dont forget that u need:
(see <!-- m -->http://www.autohotke...pic.php?t=11860<!-- m --> for links)
GDIplusWrapper.ahk
DllCallStruct.ahk
BinaryEncodingDecoding.ahk


I made a magnifier version mostly to be able to make very accurate screencaptures...
And I added the colorpicker so I can check and see that the cap is exactly as the original (the bmp quality setting confuses me.... use noParams now ;) seem to work.

pics taken with this tool should be easy to relocate with imagesearch....

So features:
-Screen Capture part of screen (win+P is the hotkey)
-Magnifier of Selected area (any height and width)
(change big window fast with mouse.... use keyboard for pixelperfection)
-Dual hair cross (somewhat modified)
-colorpicker (TrayTooltip with color info about the pixel in the haircross)



Only spent a day on this one so it may contain some bugs....

known bug: added keywait on almost every "step-key" because if i let it run at full speed.... (the key repeat rate) it seem to be too fast and it hang and flickers...
it's possible to replace keywait with sleep,70 or something

So here is the code

#NoEnv
#Include GDIPlusWrapper.ahk
SetBatchLines -1
CoordMode Mouse, Screen
CoordMode Pixel, Screen
OnExit GuiClose
zoom = 9                ; initial magnification
aimH = 20								; Height of aim window
aimW = 33								; Width of aim window

 
;;;;;;;;;; GUI big ;;;;;;;;;;
Gui +AlwaysOnTop +Caption +Resize +ToolWindow
Gui Show, % "w" aimW*zoom " h" aimH*zoom " x0 y0", Magnifier
WinGet MagnifierID, id,  Magnifier
WinSet Transparent, 255, Magnifier ; makes the window invisible to magnification
WinGet PrintSourceID, ID


;;;;;;;;;; GUI aim ;;;;;;;;;;
Gui 2:+AlwaysOnTop -Caption +ToolWindow +0x800000
Gui 2:Color, C
MouseGetPos mouseX, mouseY
Gui 2:Show, % "w" aimW " h" aimH " x" mouseX-aimW " y" mouseY-aimH, AimFrame
WinSet TransColor, C, AimFrame


hdd_frame := DllCall("GetDC", UInt, PrintSourceID)
hdc_frame := DllCall("GetDC", UInt, MagnifierID)

SetTimer Repaint, 50    ; flow through


;########## PROCEDURES ##########


;;;;;;;;;; Repaint - Updates the big window and displays the pixelcolor with TrayTip.

Repaint:
   MouseGetPos mouseX, mouseY
   PGC_Y:=mouseY-1
   PGC_X:=mouseX-1
   PixelGetColor, PGC, %PGC_X%, %PGC_Y%,RGB
   TrayTip,, RGB PixelColor:`n%PGC%, 1, 
   
   xz := In(mouseX-aimW/2,-1,A_ScreenWidth-aimW+1) ; keep the frame on screen
   yz := In(mouseY-aimH/2,-1,A_ScreenHeight-aimH+1) ;In(x,a,b) closest number to x in [a,b]
   WinMove AimFrame,,%xz%, %yz%, % aimW, % aimH
   DllCall("gdi32.dll\StretchBlt", UInt,hdc_frame, Int,0, Int,0, Int,aimW*zoom, Int,aimH*zoom
   , UInt,hdd_frame, UInt,xz, UInt,yz, Int,aimW, Int,aimH, UInt,0xCC0020) ; SRCCOPY
   DrawCross(aimW, aimH, zoom, hdc_frame)
Return

;;;;;;;;;; GuiSize - Scales the aim window if big is resized (and update caption on big window)

GuiSize:
   aimW := A_GuiWidth/zoom
   aimH := A_GuiHeight/zoom
   aimW := round(aimW)
	 aimh := round(aimH)
   Gui Show, % "w" aimW*zoom " h" aimH*zoom  ,(%aimW%x%aimH%) %zoom%x Zoom
Return

;;;;;;;;;; Cleaning up ;;;;;;;;;;

GuiClose:
   DllCall("gdi32.dll\DeleteDC", UInt,hdc_frame )
   DllCall("gdi32.dll\DeleteDC", UInt,hdd_frame )
ExitApp






;########## HOTKEYS ##########

;;;;;;;;;; Win+R - Reloads app ;;;;;;;;;;
#r::
 keywait, Lwin
 reload
return
;;;;;;;;;; Win+Up - Zooms In ;;;;;;;;;;
#Up::
if (((zoom+1)*aimW < A_ScreenWidth ) AND ((zoom+1)*aimH < (A_ScreenHeight-22) )) ;stops before window get bigger than screen
  zoom+=1
	Gui Show, % "w" aimW*zoom " h" aimH*zoom  ,(%aimW%x%aimH%) %zoom%x Zoom ;update capion and size
keywait, up ;Added because I got some glitches when at full "key repeat"-rate
return


;;;;;;;;;; Win+Down - Zooms Out ;;;;;;;;;;
#Down::
	if (zoom > 1) ;stop so it does go negative
	  zoom-=1
	Gui Show, % "w" aimW*zoom " h" aimH*zoom  ,(%aimW%x%aimH%) %zoom%x Zoom ;update capion and size
keywait, down ;Added because I got some glitches when at full "key repeat"-rate
return

;;;;;;;;;; Win+P - Takes a screenshot of whats inside the aim window

#P::
	filename=%A_Now%.bmp ;just a unique filename
	noParams = NONE

  GDIplus_Start()
  WinGetPos , X_cap, Y_cap, W_cap, H_cap, AimFrame
  GDIplus_CaptureScreenRectangle(bitmap, X_cap, Y_cap, W_cap, H_cap)

  GDIplus_GetEncoderCLSID(bmpEncoder, #GDIplus_mimeType_BMP)
  GDIplus_SaveImage(bitmap, filename, bmpEncoder, noParams)

  GDIplus_DisposeImage(bitmap)
  GDIplus_Stop()
return



;;;;;;;;;; Ctrl+Arrows - Moves the aim window 1 pixel at the time ;;;;;;;;;;
^Up::MouseMove, 0, -1, 0, R
^Down::MouseMove, 0, 1, 0, R
^Left::MouseMove, -1, 0, 0, R
^Right::MouseMove, 1, 0, 0, R

;;;;;;;;;; Shift+Arrows Change Size of aim window ;;;;;;;;;;
+Right::
	if (zoom*(aimW+1) < A_ScreenWidth)
  aimW+=1
	Gui Show, % "w" aimW*zoom " h" aimH*zoom  ,(%aimW%x%aimH%) %zoom%x Zoom
  keywait, right
return

+Left::
	if (aimW > 4)
  aimW-=1
	Gui Show, % "w" aimW*zoom " h" aimH*zoom  ,(%aimW%x%aimH%) %zoom%x Zoom
	keywait, left
return

+Down::
	if (zoom*(aimH+1) < (A_ScreenHeight-22))
  aimH+=1
	Gui Show, % "w" aimW*zoom " h" aimH*zoom  ,(%aimW%x%aimH%) %zoom%x Zoom
  keywait, Down
return

+Up::
	if (aimH > 4)
  aimH-=1
	Gui Show, % "w" aimW*zoom " h" aimH*zoom  ,(%aimW%x%aimH%) %zoom%x Zoom
  keywait, Up
return
	
	
	
	
;########## Functions ##########


;;;;;;;;;; Draws the Crosshairs ;;;;;;;;;;

DrawCross( X_CL , Y_CL, Z_CL, dc )
{
;specify the style, thickness and color of the cross lines
    h_pen := DllCall( "gdi32.dll\CreatePen", "int", 0, "int", 1, "uint", 0x0000FF)
;select the correct pen into DC
    DllCall( "gdi32.dll\SelectObject", "uint", dc, "uint", h_pen )         
;draw horizontal lines
    DllCall( "gdi32.dll\MoveToEx", "uint", dc, "int", 0, "int",floor((Y_CL-1)/2)*Z_CL , "uint", 0)
    DllCall( "gdi32.dll\LineTo", "uint", dc, "int", X_CL*Z_CL, "int", floor((Y_CL-1)/2)*Z_CL)
    DllCall( "gdi32.dll\MoveToEx", "uint", dc, "int", 0, "int",floor((Y_CL-1)/2)*Z_CL+Z_CL , "uint", 0)
    DllCall( "gdi32.dll\LineTo", "uint", dc, "int", X_CL*Z_CL, "int", floor((Y_CL-1)/2)*Z_CL+Z_CL)
;draw vertical lines
    DllCall( "gdi32.dll\MoveToEx", "uint", dc, "int",floor((X_CL-1)/2)*Z_CL, "int", 0, "uint", 0)
    DllCall( "gdi32.dll\LineTo", "uint", dc, "int", floor((X_CL-1)/2)*Z_CL, "int", Y_CL*Z_CL)
    DllCall( "gdi32.dll\MoveToEx", "uint", dc, "int",floor((X_CL-1)/2)*Z_CL+Z_CL, "int", 0, "uint", 0)
    DllCall( "gdi32.dll\LineTo", "uint", dc, "int", floor((X_CL-1)/2)*Z_CL+Z_CL, "int", Y_CL*Z_CL)
}



;;;;;;;;;; Select Compare ;;;;;;;;;;

In(x,a,b) {                      ; closest number to x in [a,b]
   IfLess x,%a%, Return a
   IfLess b,%x%, Return b
   Return x
}



Look inside the code to find all the hotkeys......

Open for suggestions for better solutions....

really want some input on how to optimize the code....

And again credit to all those that wrote the code in the first place.... this is just another version of their work.

Please report bugs (and solution if u found one)

///Ricke

Tekl
  • Members
  • 814 posts
  • Last active: May 03 2009 03:28 PM
  • Joined: 24 Sep 2004
Does anyone have an idea why the magnifier is just white when using Aero in Vista? Ok, I think it's because Aero uses DirectX, but could the Magnifier be improved to support that? The system's own magnifier works also with Aero.
Tekl

joebob
  • Guests
  • Last active:
  • Joined: --
How do I set up the Caps lock key to toggle the screen magnifier on and off?

Icarus
  • Members
  • 851 posts
  • Last active: Jan 02 2012 11:17 AM
  • Joined: 24 Nov 2005
Well,

I must admit I did not read through this entire thread, but I did test some of the variants of this nice script.

No offense, but with all the beauty of a 50-line magnifier code, there seem to be a basic problem with taking this to the next level.

In all the versions I tested, the smoothness of movement (both of the window, and of its content) are nothing close to the Windows magnifier. My eyes got tired after a couple of minutes with this magnifier.

Personally, I like using a magnifier, and I was looking to develop one my own - using AHK of course - so naturally, I started to look at this thread.

Couple questions, if anyone cares to share:
1. Did anyone manage to create a version that has smooth motion in both aspects (content, and window-following-mouse)
2. Did anyone manage to do a version that supports inverse colors?
3. Did anyone manage (or have an idea about how to do it) to show the mouse cursor itself in the window (and not some crosshair)
4. (yeah, more than a couple, sorry) An extremely important feature in a magnifier (to my taste) is the ability to follow keyboard caret and focus - anyone attempted that?