Magnifying glass

13 replies [Last post]
f2cx
User offline. Last seen 16 weeks 3 days ago. Offline
Joined: 13 Sep 2010

Did anyone try to create a magnifying glass and have Lua code to share?

Here's an example in ObjectiveC: http://www.craftymind.com/2009/02/10/creating-the-loupe-or-magnifying-glass-effect-on-the-iphone/
I've difficulties to see equivalences in CoronaLua, specially regarding the concept of "mask".
Any help welcomed, thanks.

Replies

jmp909
User offline. Last seen 10 weeks 5 days ago. Offline
Joined: 14 May 2010

you'd need a mask. we dont have masks yet

f2cx
User offline. Last seen 16 weeks 3 days ago. Offline
Joined: 13 Sep 2010

Are masks mandatory to do a magnifying glass? Another way?

jmp909
User offline. Last seen 10 weeks 5 days ago. Offline
Joined: 14 May 2010

Yes, no

erpy
User offline. Last seen 7 weeks 20 hours ago. Offline
Joined: 24 Mar 2010

Uh, and you'd also need a "screen grab" function that stores the result in memory rather than "on disk". Otherwise you'd have to wait twice, once for saving and once for loading. With the current grabber it would probably not be a very "responsive" effect. :)

jmp909
User offline. Last seen 10 weeks 5 days ago. Offline
Joined: 14 May 2010

that's not true. you don't need to grab anything. you just display the same image again zoomed and with a mask added

1
2
3
4
5
6
7
8
local myImage = display.newImage("book.png")
local myMagnifiedImage = display.newImage("book.png")
local myMaskImage = display.newImage("mask.png")
 
myMagnifiedImage.xScale=2
myMagnifiedImage.yScale=2
 
myMagnifiedImage.mask = myMaskImage

(note this code won't work... yet... until ansca add the feature!)

erpy
User offline. Last seen 7 weeks 20 hours ago. Offline
Joined: 24 Mar 2010

Why does people always look at *single* things ? - like you having a single bitmap. :)
How about having several display objects in hierarchy at different positions and scale on the same screen ? What would you magnify in that "most-of-the-times" case, if you don't "render-to-texture" the entire stage ? ;)

jmp909
User offline. Last seen 10 weeks 5 days ago. Offline
Joined: 14 May 2010

ok good point erpy. for that we need to be able to "draw" the contents of our display group to a flat bitmap. this feature is possibly on the roadmap

erpy
User offline. Last seen 7 weeks 20 hours ago. Offline
Joined: 24 Mar 2010

Exactly, which isn't that different from the current "take screenshot"... just, as said, needs to be faster - i.e. saved straight to memory.

This is commonly known as "render to texture" in 3D realtime... and since Corona is OpenGL-based sounds like an appropriate term. :)

horacebury's picture
horacebury
User is online Online
Joined: 17 Aug 2010

Hi,

I've been thinking about this and the only way I can see of doing it currently is to have a stationary touch event cause a screen grab into the app's resource directory; then to open a web popup near the touch with a customised, local web page which accepts parameters to load the screen grab, position and scale it appropriately using the touch coordinates.

I don't know if the web popup could be moved relative to the touch or if touch events stop getting passed to the corona app when the touch moves onto the web popup, but I've done the photoshop/html/css work to produce a magnifier which loads the scaled image.

https://files.me.com/horacebury/cxj2us

I hope someone can finish the corona code, I'm going to bed and can't work on this for a while.

Matt.

jmp909
User offline. Last seen 10 weeks 5 days ago. Offline
Joined: 14 May 2010

ok here's a (very rough) magnifying glass using capture screen, but it's late and i can't work out the maths to scale the movement. I didnt understand the need for the web popup in your example though

a couple of things to note

* the screen capture is scaled, then masked
* scaling the capture seems to scale the mask (bug?)
* the screen capture would also actually need to move based on the scale, otherwise you end up with the lens showing the wrong thing underneath. i've not implemented this. basically since i've magnified from the centre, as you move towards the edge the magnified bit is further away.
* it doesn't scale correctly when viewing as iPhone4 etc... need to modify some of the calculations config etc i think

if someone could post any fixes that would be great

the end target would be to have it re-capture the display anytime the user clicks on the screen/magnifying glass etc. this would mean that the main original screen would need to be static (not updating) until you let go again. essentially you're just viewing a screen capture.

also you'd probably want to overlay the graphic of a magnifying glass at the same position as the mask. it probably gets more complicated if you try to start putting them in display groups together, as the mask isnt a separate image as such , it's a part of the scaled image here

regards
J

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
display.setStatusBar( display.HiddenStatusBar )
 
local halfW = display.contentCenterX
local halfH = display.contentCenterY
 
local W = display.contentWidth
local H = display.contentHeight
 
local canvas = display.newGroup()
 
local rnd = math.random
 
for i=1, 200, 1 do
        local line = display.newLine(rnd()*W, rnd()*H, rnd()*W, rnd()*H)
        line:setColor(rnd()*255,rnd()*255,rnd()*255)
        canvas:insert(line)
        
        local box = display.newRect(rnd()*W, rnd()*H, 2+rnd()*50, 2+rnd()*50)
        box:setFillColor(rnd()*255,rnd()*255,rnd()*255)
        canvas:insert(box)
end
 
local canvascopy = display.captureScreen()
 
local SCALE_RATIO = 2
 
canvascopy.xScale=SCALE_RATIO
canvascopy.yScale=SCALE_RATIO
 
local mask = graphics.newMask( "circlemask.png" )
canvascopy:setMask(mask)
 
canvascopy.maskScaleX=1/SCALE_RATIO
canvascopy.maskScaleY=1/SCALE_RATIO
 
function onTouch( event )
        print("touch")
        local t = event.target
 
        local phase = event.phase
        if "began" == phase then
                display.getCurrentStage():setFocus( t )
 
                -- Spurious events can be sent to the target, e.g. the user presses 
                -- elsewhere on the screen and then moves the finger over the target.
                -- To prevent this, we add this flag. Only when it's true will "move"
                -- events be sent to the target.
                t.isFocus = true
 
                -- Store initial position               
                t.x0 = (event.x - t.maskX*SCALE_RATIO)
                t.y0 = (event.y - t.maskY*SCALE_RATIO)
                
        elseif t.isFocus then
                if "moved" == phase then
                        -- Make object move (we subtract t.x0,t.y0 so that moves are
                        -- relative to initial grab point, rather than object "snapping").
                        t.maskX = (event.x - t.x0)/SCALE_RATIO
                        t.maskY = (event.y - t.y0)/SCALE_RATIO
                elseif "ended" == phase or "cancelled" == phase then
                        display.getCurrentStage():setFocus( nil )
                        t.isFocus = false
                end
        end
 
        return true
end
 
canvascopy:addEventListener( "touch", onTouch )

horacebury's picture
horacebury
User is online Online
Joined: 17 Aug 2010

Good work!

The web popup in my code was because we didn't have masking back then.

M

jmp909
User offline. Last seen 10 weeks 5 days ago. Offline
Joined: 14 May 2010

can anyone help solve this please? the inverse ratios combined with the fact that the mask is scaled with the zoomed layer is throwing me!

i've put the cap in a group and overlaid a circle to show the group moving but the screencap not moving to where it needs to be. t.canvascap.maskX needs to be changed based on the zoom ratio etc and I can't work that out.

thanks
j

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
display.setStatusBar( display.HiddenStatusBar )
 
local halfW = display.contentCenterX
local halfH = display.contentCenterY
 
local W = display.contentWidth
local H = display.contentHeight
 
print(W,H)
 
local lines={}
 
local canvas = display.newGroup()
 
local rect=display.newRect(0,0,display.contentWidth, display.contentHeight)
rect:setFillColor(0,0,0)
canvas:insert(rect)
 
 
local rnd = math.random
 
for i=1, 200, 1 do
        local line = display.newLine(rnd()*W, rnd()*H, rnd()*W, rnd()*H)
        line:setColor(rnd()*255,rnd()*255,rnd()*255)
        canvas:insert(line)
        
        local box = display.newRect(rnd()*W, rnd()*H, 2+rnd()*50, 2+rnd()*50)
        box:setFillColor(rnd()*255,rnd()*255,rnd()*255)
        canvas:insert(box)
end
 
local canvascap = display.captureScreen()
 
canvascopy = display.newGroup()
 
 
local SCALE_RATIO = 2
 
canvascap.xScale=SCALE_RATIO
canvascap.yScale=SCALE_RATIO
 
 
local mask = graphics.newMask( "circlemask.png" )
canvascap:setMask(mask)
 
canvas.alpha=0.7
canvascopy.alpha=1
 
canvascap.maskScaleX=1/SCALE_RATIO
canvascap.maskScaleY=1/SCALE_RATIO
canvascopy.canvascap = canvascap
canvascopy:insert(canvascap)
canvascopy.isHitTestable=true
 
local circ = display.newCircle(halfW, halfH, 100)
circ.alpha=0.25
canvascopy:insert(circ)
 
function onTouch( event )
        --print("touch")
        local t = event.target
 
        local phase = event.phase
        if "began" == phase then
                display.getCurrentStage():setFocus( t )
 
                t.isFocus = true
 
                -- Store initial position               
                t.x0 = (event.x - t.x)
                t.y0 = (event.y - t.y)
                
        elseif t.isFocus then
                if "moved" == phase then
                        -- Make object move (we subtract t.x0,t.y0 so that moves are
                        -- relative to initial grab point, rather than object "snapping").
                        
                t.x = event.x - t.x0
                t.y = event.y - t.y0
        
        --      t.canvascap.maskX = (event.x - t.x0) 
        --      t.canvascap.maskY = (event.y - t.y0) 
 
                
                elseif "ended" == phase or "cancelled" == phase then
                        display.getCurrentStage():setFocus( nil )
                        t.isFocus = false
                end
        end
 
        return true
end
 
canvascopy:addEventListener( "touch", onTouch )

loghound
User offline. Last seen 17 weeks 2 days ago. Offline
Joined: 26 Mar 2011

Here is a modification that seems to work a bit better (at least for my purposes)

http://db.tt/veZ3pLG

The trick & change from the original is you need to move the background canvas in the opposite direction so the circlemask is always 'magnifying' the correct visible portion -- a small change but provides a more convincing result (my project file includes a picture so you can visually see it's lining up better)

There are still a few problems (the magnifier flies off screen on second click) and it doesn't work right for scale factors > 2 but as I said it seems to do a more convincing magnification

Thanks to the orginal poster actually mentioned this so this is just a (very small) clean up of that

-John

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.