Drawing an image clipped into a polygon

Posted by Twisol on Sat 28 Aug 2010 02:46 AM — 5 posts, 15,968 views.

USA #0
I was bored, so I decided to figure out how to clip an image into a polygon. It took a few hours but I finally have a working method.

First, here's an example result, using Nick's miniwindow grid. Base image taken from Nick's WindowTransformImage topic, originally courtesy Isobel Gammon:

http://img801.imageshack.us/img801/8264/polygonclip.png

The image is drawn using WindowMergeImageAlpha, so the clipped area is transparent.

--[[ Setup ]]

-- make the visible window
local win = "win"
WindowCreate(win, 0, 0, 200, 250, 12, 0, ColourNameToRGB("saddlebrown"))

-- draw a grid
for i = 1, math.max(WindowInfo(win, 3), WindowInfo(win, 4)) / 25 do
  WindowLine(win, i * 25, 0, i * 25, WindowInfo(win, 4), 0xC0C0C0, 0, 1)
  WindowLine(win, 0, i * 25, WindowInfo(win, 3), i * 25, 0xC0C0C0, 0, 1)
end -- for



--[[ Load the image ]]

-- make the image-window
local image = "image"
WindowCreate(image, 0, 0, 0, 0, 0, 2, 0)
WindowLoadImage(image, "image", GetInfo (66) .. "may2010.png")
WindowResize(image,
  WindowImageInfo(image, "image", 2),
  WindowImageInfo(image, "image", 3),
  0)

-- initialize the alpha mask
WindowRectOp(image, 2, 0, 0, 0, 0, 0xFFFFFF) -- No transparency
WindowImageFromWindow(image, "alpha", image)



--[[ Clip into a polygon ]]

-- Draw a polygon around the selected area
WindowDrawImage(image, "image", 0, 0, 0, 0, 1, 0, 0, 0, 0)
WindowPolygon(image, "0,0,100,0,50,80,0,100", 0xFF0000, 0, 1, 0, 1, true, true)
WindowImageFromWindow(image, "image", image)

-- Create a mask in the shape of the clip space
WindowRectOp(image, 2, 0, 0, 0, 0, 0x000000) -- Full transparency
WindowPolygon(image, "0,0,100,0,50,80,0,100", 0xFFFFFF, 0, 1, 0xFFFFFF, 0, true, true) -- Draw "out" the transparency where the image should be visible.
WindowImageFromWindow(image, "clip", image)

-- Apply the clipping operation
WindowRectOp(image, 2, 0, 0, 0, 0, 0x000000)
WindowMergeImageAlpha(image, "alpha", "clip", 0, 0, 0, 0, 0, 1, 0, 0, 0, 0)
WindowImageFromWindow(image, "alpha", image)



--[[ Draw to the visible window ]]

-- Get the target image
WindowImageFromWindow(image, "target", win)

-- Apply the blend
WindowDrawImage(image, "target", 0, 0, 0, 0, 1, 50, 50, 0, 0)
WindowMergeImageAlpha(image, "image", "alpha", 0, 0, 0, 0, 0, 1, 0, 0, 0, 0)

-- Return to the target image
WindowImageFromWindow(win, "image", image)
WindowDrawImage(win, "image", 50, 50, 0, 0, 1, 0, 0, 0, 0)

-- Reset the image window
WindowDrawImage(image, "image", 0, 0, 0, 0, 1, 0, 0, 0, 0)



--[[ Show the changes ]]

WindowShow(win, true)


[EDIT] Removed extraneous WindowResize().
Amended on Sat 28 Aug 2010 06:47 AM by Twisol
Australia Forum Administrator #1
A copy of his image:

Amended on Sat 28 Aug 2010 03:59 AM by Nick Gammon
Australia Forum Administrator #2
Yes, very interesting. And if you change the line that draws the polygon to fill with gray, you get a partial mask.


-- Create a mask in the shape of the clip space
WindowRectOp(image, miniwin.rect_fill, 0, 0, 0, 0, 0x000000) -- Full transparency
WindowPolygon(image, "0,0,100,0,50,80,0,100", 0xFFFFFF, miniwin.pen_solid, 1, 0x777777, miniwin.brush_solid, true, true) 
WindowImageFromWindow(image, "clip", image)


Change to the paint colour in bold (from 0xFFFFFF).

Amended on Sat 28 Aug 2010 03:58 AM by Nick Gammon
USA #3
Yep! And you can use a preexisting alpha mask, too. The example starts fully blended, but if you had a PNG and you used its alpha mask instead, this trick would still work, because we're masking out only the part of the mask that needs to be clipped. Masking a mask with a mask is interesting. XD

[EDIT] This technique lets you do everything WindowImageOp does and more. I think that's the most interesting point to take from this.
Amended on Sat 28 Aug 2010 04:10 AM by Twisol
USA #4
It should be noted that clipping and fading can be composed separately, too:

-- Create a mask in the shape of the clip space
WindowRectOp(image, 2, 0, 0, 0, 0, 0x000000) -- Full transparency
WindowPolygon(image, "0,0,100,0,50,80,0,100", 0, 5, 0, 0xFFFFFF, 0, true, true) -- Draw "out" the transparency where the image should be visible.
WindowImageFromWindow(image, "mask", image)

-- Apply the clipping operation
WindowRectOp(image, 2, 0, 0, 0, 0, 0x000000)
WindowMergeImageAlpha(image, "alpha", "mask", 0, 0, 0, 0, 0, 1, 0, 0, 0, 0)
WindowImageFromWindow(image, "alpha", image)

-- Create a mask to fade the image
WindowRectOp(image, 2, 0, 0, 0, 0, 0x000000)
WindowPolygon(image, "0,0,100,0,50,80,0,100", 0, 5, 0, 0x777777, 0, true, true)
WindowImageFromWindow(image, "mask", image)

-- Apply the fade mask
WindowRectOp(image, 2, 0, 0, 0, 0, 0x000000)
WindowMergeImageAlpha(image, "alpha", "mask", 0, 0, 0, 0, 0, 1, 0, 0, 0, 0)
WindowImageFromWindow(image, "alpha", image)


(I've changed the image from "clip" to "mask", since it's not just for clipping anymore. Also, I removed the drawing of the border, and disabled the pen in the WindowPolygon calls. This can always be done separately of course.)

This feature lets you compose multiple operations separately, which can be easier to understand and implement.