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
holomind
  • Members
  • 341 posts
  • Last active: Aug 23 2015 03:27 PM
  • Joined: 11 Mar 2006
my optimized version

* removed buffer
* move away when mouse is inside the Magnifier

#NoEnv
SetBatchLines -1

CoordMode Mouse, Screen
OnExit #x
zoom = 2                ; initial magnification, 1..32
R = 128                 ; half side of magnifier window
Rz := R/zoom
                        ; GUI 2 shows the magnified image
Gui 2:+AlwaysOnTop -Caption +Resize +ToolWindow +E0x20
Gui 2:Show, % "w" 2*R+3 " h" 2*R+3 " x0 y0", Magnifier
WinGet MagnifierID, id,  Magnifier
WinSet Transparent, 255, Magnifier ; makes the window invisible to magnification
WinGet PrintSourceID, ID
                        ; Frame around magnified area
Gui +AlwaysOnTop -Caption +ToolWindow +E0x20 +0x800000
Gui Color, C
MouseGetPos x, y
Gui Show, % "w" 2*Rz " h" 2*Rz " x" x-Rz " y" y-Rz, Frame
WinSet TransColor, C, Frame

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

SetTimer Repaint, 50   ; flow through

Repaint:
   MouseGetPos x, y
   xz := In(x-Rz-6,0,A_ScreenWidth-2*Rz) ; keep the frame on screen
   yz := In(y-Rz-6,0,A_ScreenHeight-2*Rz)
   WinMove Frame,,%xz%, %yz%, % 2*Rz, % 2*Rz
   DllCall("gdi32.dll\StretchBlt", UInt,hdc_frame, Int,0, Int,0, Int,2*R, Int,2*R
   , UInt,hdd_frame, UInt,xz, UInt,yz, Int,2*Rz, Int,2*Rz, UInt,0xCC0020) ; SRCCOPY
   
   inside_old := inside
   inside := (( x < R*2 ) and ( y < R*2 ) ) * R*2  
   if ( %inside_old% <> %inside% )
       WinMove Magnifier,, ,%inside%
   
Return

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

^+WheelUp::                      ; Ctrl+Shift+WheelUp to zoom in
^+WheelDown::                    ; Ctrl+Shift+WheelUp to zoom out
  If (zoom < 31 and A_ThisHotKey = "^+WheelUp")
     zoom *= 1.189207115         ; sqrt(sqrt(2))
  If (zoom >  1 and A_ThisHotKey = "^+WheelDown")
     zoom /= 1.189207115
  Rz := R/zoom
  TrayTip,,% "Zoom = " Round(100*zoom) "%"
Return

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


d-man
  • Members
  • 290 posts
  • Last active: Jun 28 2015 09:26 AM
  • Joined: 08 Jun 2006
could someone make one where the magnifier is on the bottom and takes the whole width of the screen. i would want to make the middle mouse button turn it on & off also

holomind
  • Members
  • 341 posts
  • Last active: Aug 23 2015 03:27 PM
  • Joined: 11 Mar 2006

could someone make one where the magnifier is on the bottom and takes the whole width of the screen. i would want to make the middle mouse button turn it on & off also


Like This ? you only have to play around with the numbers for R and w/h/x/y ??

if you move to much right it blurs. as it is offscreen!

if you want that windows dont maximize over the magnifier you can in win2k and xp . drag and drop a folder to the side of the screen, which then will be "snapped" to the border. then resize it and rightclick and make it always on top like the taskbar. later you can hide and close this toolbar with a rightclick on your taskbar, and you will find your folder there which you can check/uncheck.

or you simply make your taskbar bigger temporaily and cannot use it while the magnifier is on. ?

Mouseclick is enabled, or usw win-p for "pause". (repaint is stopped )

the script keeps running until you press win-x "exit"

#NoEnv
SetBatchLines -1

CoordMode Mouse, Screen
OnExit #x
zoom = 2                ; initial magnification, 1..32
R = 128                 ; half side of magnifier window
Rz := R/zoom
                        ; GUI 2 shows the magnified image
Gui 2:+AlwaysOnTop -Caption +Resize +ToolWindow +E0x20
Gui 2:Show, % "w" A_ScreenWidth " h" 2*R+3 " x0 y" A_ScreenHeight -2*R , Magnifier
WinGet MagnifierID, id,  Magnifier
WinSet Transparent, 255, Magnifier ; makes the window invisible to magnification
WinGet PrintSourceID, ID
                        ; Frame around magnified area
Gui +AlwaysOnTop -Caption +ToolWindow +E0x20 +0x800000
Gui Color, C
MouseGetPos x, y
Gui Show, % "w" 2*Rz " h" 2*Rz " x" x-Rz " y" y-Rz, Frame
WinSet TransColor, C, Frame

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

SetTimer Repaint, 50   ; flow through

Repaint:
   MouseGetPos x, y
   xz := In(x-Rz-6,0,A_ScreenWidth-2*Rz) ; keep the frame on screen
   yz := In(y-Rz-6,0,A_ScreenHeight-2*Rz)
   WinMove Frame,,%xz%, %yz%, % 2*Rz, % 2*Rz
   DllCall("gdi32.dll\StretchBlt", UInt,hdc_frame, Int,0, Int,0, Int,A_ScreenWidth, Int,2*R
   , UInt,hdd_frame, UInt,xz, UInt,yz, Int,A_ScreenWidth / zoom, Int,2*Rz, UInt,0xCC0020) ; SRCCOPY
   
Return

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

#p::
MButton::
   if paused = 
   {
        Gui, 2:Hide 
        Gui, Hide 
        SetTimer, Repaint, Off
        paused = 1
   }
   else
   {
        Gui, 2:Show 
        Gui, Show 
        SetTimer, Repaint, 50
        paused =
   }
Return

^+WheelUp::                      ; Ctrl+Shift+WheelUp to zoom in
^+WheelDown::                    ; Ctrl+Shift+WheelUp to zoom out
  If (zoom < 31 and A_ThisHotKey = "^+WheelUp")
     zoom *= 1.189207115         ; sqrt(sqrt(2))
  If (zoom >  1 and A_ThisHotKey = "^+WheelDown")
     zoom /= 1.189207115
  Rz := R/zoom
  TrayTip,,% "Zoom = " Round(100*zoom) "%"
Return

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


d-man
  • Members
  • 290 posts
  • Last active: Jun 28 2015 09:26 AM
  • Joined: 08 Jun 2006
sweet thx a lot

Like This ? you only have to play around with the numbers for R and w/h/x/y ??

ah.. well.. yea... uh... the script looked so scary i was afraid to touch it :oops:

holomind
  • Members
  • 341 posts
  • Last active: Aug 23 2015 03:27 PM
  • Joined: 11 Mar 2006

ah.. well.. yea... uh... the script looked so scary i was afraid to touch it :oops:


yeah, thats lazlo's *compact* style. no line too much. and mixed up by three authors ;)

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

to make it even shorter, i recognized the buffers are not used.

I removed the corresponding 4 lines in my script above.

due to +E0x20, the magnifier is stuck in the top-left corner.

You are right, there is no need for the style +E0x20. I deleted it, and now, like in your original script, the magnifier window is movable by dragging it with its title bar.

The window is also resizable. Under the GuiSize label we set the dimensions used in the script, so any size rectangular magnifier window is possible. The moving frame adjusts to this.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Holomind's jumping magnifier window idea is clever, but it is hard to implement with resizable windows. There might not be enough room inside the screen, and you probably want the window to jump when the frame overlaps it, not when the mouse pointer enters it. Also, if you happen to be interested in the transition area, the jumping window drives you crazy, therefore, you might need some hysteresis.

If someone (d-man) wants a huge magnifier window, he just has to move and resize it.

holomind
  • Members
  • 341 posts
  • Last active: Aug 23 2015 03:27 PM
  • Joined: 11 Mar 2006
you could use "WinSet Region" and make the region of the Frame-Window visible. (Digg hole in the Magnifier-Window using 2 polygons ) but i dont know if this is usefull. if your magnifier is bigger then half of the screen it doesnt make much sense to move it out of the way, but with less then A_ScreenHeight or A_ScreenWidth it might make sense.
i also like the hidden feature to doubleclick the titlebar of Magnifier and have fullscreen magnifier and "simulate" a different screen resolution ;) ideal for zooming swf-videos. quicktime gets zoomed , but not avi. but thats not a problem as avi can be made fullscreen.

i also like the new #p (pause) button i made for d-man, so the script can run in background and wakes up when needed. (but perhaps it saves memory to close and restart the script from an outside ahk-script ?)

also you can use the antialize toggle, which IMO makes sense with odd zoomlevels (half pixels). the SetStrechBltMode only has to set once and not before every DC-Copy.

#a::
  antialize := 4 - antialize
  DllCall( "gdi32.dll\SetStretchBltMode", "uint", hdc_frame, "int", antialize )  ; Antializing ?
Return 


Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
(Bist du verrückt? Es ist fünf Uhr Samstagmorgen!)

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
I used the magnifier to get hints from existing icons, how to set the colors of pixels in my own icons. In that application antialiasing makes more harm than good. However, as you say, magnifying small web pictures, even videos is another good application, where antialiasing improves the image. In your code example you have to initialize the "antialize" variable, but with this variant you don't (and save a whole line of code).
#a::

  antialize := !antialize

  DllCall("gdi32.dll\SetStretchBltMode", UInt,hdc_frame, Int,4*antialize)

Return


Trombonisto
  • Members
  • 7 posts
  • Last active: Jan 19 2007 06:51 AM
  • Joined: 18 Aug 2006
Hello!

You did a really good job! Congratulation!

I modified the magnifier for my situation e.g. no mouse wheel, that was simple. But I'm not able to make a crosshair I need in the magnifier. Could you help me please?

The centre of the crosshair must be the mouse point. I saw a magnifier with a little square in the middle of the crosshair showing an one pixel hole for exactly finding the right position. And if the crosshair could invert its colour over black it would be perfect.

For explanation: I would use the magnifier in combination with an own small tool for measurement of graphs and drawings and insert the coordinates into a spreadsheet. BTW how can I hinder that with every transmission the spreadsheet window shortly pops up?

I would be very grateful if you could help me.

Best greetings

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
You can find a few crosshair scripts here. If you make the splash images semi-transparent (WinSet Transparent, 255…), they won't show up in the magnified image (too thick), but with another crosshair in the middle of the magnifier window, you can mark its center.

I don't know any simple way to invert the crosshair color, dependent on the background. The easiest, but not very nice solution was to just periodically redraw the lines, once black, once white, creating a flashing effect.

If you want to send input to an inactive window, try ControlSend.

holomind
  • Members
  • 341 posts
  • Last active: Aug 23 2015 03:27 PM
  • Joined: 11 Mar 2006
hi, which version of the magniferscript do you use ? we have about 4 variants in this thread ;) i quess the last one from lazlo?

one idea to draw the crosshair is to use some strechblt or bitblt to invert the crosshair over the magnified image.

the current copy-mode is "SRCCOPY" but there also is a mode which produces XOR i think. this would invert all pixels. then it would not be really black but invert, perhaps this is even better as you dont loose the colorinformation behind the crosshair (as its inverse and you can guess?)

or one uses DLLCall for drawing Lines with GDI, there are Commands for Draw Dot, Draw Circle?, Draw Line, FillRect.

one trick could also be to create a black buffer (DC) and then bitblt only the needed black line over to the magnifier window/gui/DC.

in the bitblt you define the source-coordinates and the destination-coordinates. so you would need 2 bitblts to create your crosshair by bitblt of something like. destx1=mag_size/2, desty1=0, destx2=mag_size/2 +1, desty2=magnifier_height...
you get the idea

you should also check lazlos link for crosshair scripts.

i guess using ddl-calls for gdi32.dll will be fastest performance!
the magnifier already makes heavy use of bitblt or strechblt so it would be natural to use it for the crosshair also.
(adding 2 stechblts with SCRINVERT for exampe, one for horizontal and one for vertical line)

eg. like here:
<!-- m -->http://www.autohotke...opic.php?t=5273<!-- m -->
;#############   draw cross lines   ###########################################
DrawCross( p_x, p_y, p_w, p_h )
  {
    global   hdc_frame, h_pen
         
    ;margin to the inside of the region to start drawing the lines
    LineMargin = 10

    ;select the correct pen into DC
    DllCall( "gdi32.dll\SelectObject"
           , "uint", hdc_frame
           , "uint", h_pen )
               
    ;update the current position to specified point
    DllCall( "gdi32.dll\MoveToEx"
           , "uint", hdc_frame
           , "int", p_x+LineMargin
           , "int", p_y+LineMargin
           , "uint", 0)
   
    ;draw a line from the current position up to, but not including, the specified point.
    DllCall( "gdi32.dll\LineTo"
           , "uint", hdc_frame
           , "int", p_x+p_w-LineMargin
           , "int", p_y+p_h-LineMargin)
   
    DllCall( "gdi32.dll\MoveToEx"
           , "uint", hdc_frame
           , "int", p_x+p_w-LineMargin
           , "int", p_y+LineMargin
           , "uint", 0)

    DllCall( "gdi32.dll\LineTo"
           , "uint", hdc_frame
           , "int", p_x+LineMargin
           , "int", p_y+p_h-LineMargin) 

for the xor idea see:
<!-- m -->http://msdn.microsof... ... bitblt.asp<!-- m -->
SRCAND 	Combines the colors of the source and destination rectangles by using the Boolean AND operator.
SRCCOPY 	Copies the source rectangle directly to the destination rectangle.
SRCERASE 	Combines the inverted colors of the destination rectangle with the colors of the source rectangle by using the Boolean AND operator.
SRCINVERT 	Combines the colors of the source and destination rectangles by using the Boolean XOR operator.
SRCPAINT 	Combines the colors of the source and destination rectangles by using the Boolean OR operator.

the integerss for the modes
public enum TernaryRasterOperations
{
SRCCOPY = 0x00CC0020, /* dest = source*/
SRCPAINT = 0x00EE0086, /* dest = source OR dest*/
SRCAND = 0x008800C6, /* dest = source AND dest*/
SRCINVERT = 0x00660046, /* dest = source XOR dest*/
SRCERASE = 0x00440328, /* dest = source AND (NOT dest )*/
NOTSRCCOPY = 0x00330008, /* dest = (NOT source)*/
NOTSRCERASE = 0x001100A6, /* dest = (NOT src) AND (NOT dest) */
MERGECOPY = 0x00C000CA, /* dest = (source AND pattern)*/
MERGEPAINT = 0x00BB0226, /* dest = (NOT source) OR dest*/
PATCOPY = 0x00F00021, /* dest = pattern*/
PATPAINT = 0x00FB0A09, /* dest = DPSnoo*/
PATINVERT = 0x005A0049, /* dest = pattern XOR dest*/
DSTINVERT = 0x00550009, /* dest = (NOT dest)*/
BLACKNESS = 0x00000042, /* dest = BLACK*/
WHITENESS = 0x00FF0062, /* dest = WHITE*/
};
i also like the idea with

Gui +E0x20
for making the window "clickthrough" and allowing normal usage of mouse and context-menu. but this would interfere with moving the magnifierwindow as already discussed.

perhaps you already use the version which acts as a lens following the mouse directly.

Trombonisto
  • Members
  • 7 posts
  • Last active: Jan 19 2007 06:51 AM
  • Joined: 18 Aug 2006
Hello Laszlo and holomind!

Many thanks for your very quick response!

I use the holomind version from August 11.

All your sugestions sound very good but I guess to implemet them in my script should be too hard for me as a poor AHK- beginner. But in the next few days I want to try it. Hope that I can't destroy someting in my system with such code?

I set the code from http://www.autohotke...opic.php?t=5273 into the August 11 version after
WinGet PrintSourceID, ID
and tried to adapt:
;#############   draw cross lines   ###########################################
;specify the style, thickness and color of the cross lines
  h_pen := DllCall( "gdi32.dll\CreatePen"
                   , "int", 1
                   , "int", 1
                   , "uint", 0x00BBGGRR) 

;retrieve the ID number 
  WinGet, hw_frame, id 

;Get handle to display device context (DC) for the client area of a specified window
  hdc_frame := DllCall( "GetDC"
                      , "uint", hw_frame )                    

DrawCross( x, y, w, h )
  {
    global   hdc_frame, h_pen
         
    ;margin to the inside of the region to start drawing the lines
    LineMargin = 10

    ;select the correct pen into DC
    DllCall( "gdi32.dll\SelectObject"
           , "uint", hdc_frame
           , "uint", h_pen )
               
    ;update the current position to specified point
    DllCall( "gdi32.dll\MoveToEx"
           , "uint", hdc_frame
           , "int", x+LineMargin
           , "int", y+LineMargin
           , "uint", 0)
   
    ;draw a line from the current position up to, but not including, the specified point.
    DllCall( "gdi32.dll\LineTo"
           , "uint", hdc_frame
           , "int", x+w-LineMargin
           , "int", y+h-LineMargin)
   
    DllCall( "gdi32.dll\MoveToEx"
           , "uint", hdc_frame
           , "int", x+w-LineMargin
           , "int", y+LineMargin
           , "uint", 0)

    DllCall( "gdi32.dll\LineTo"
           , "uint", hdc_frame
           , "int", x+LineMargin
           , "int", y+h-LineMargin)
  }
But nothing happens :cry: I repeat it seems to be too dfficult to me!

Maybe tomorrow I have a better day. Bye

Trombonisto

holomind
  • Members
  • 341 posts
  • Last active: Aug 23 2015 03:27 PM
  • Joined: 11 Mar 2006
oh, i thought my hints for using this functions would be enough for a startoff.
perhaps i find some time on weekend to try my version with srcinvert and bitblt. which should be realtively easy and fast.

you took the idea with moveTo and LineTo. so more like classical draw-a-line.

do you really need a black crosshair? as i gues using little xors with bitblt would be easier. like applying a mask/filter with a image-editor.