Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add semi-transparent mask to CALayer?

I'm trying to darken the surrounding area of my UIImageView, and leave a portion alone (which I define with my mask).

Right now I'm defining my mask and setting my imageView.layer.mask, however instead of darkening the rest of the image, it's completely removing it instead.

Example of the type of effect I want: http://i.imgur.com/vVUiuyk.png

Example of what I'm getting: http://i.imgur.com/5DTXo0S.png

The reference docs mention that the mask uses it's layer's alpha, so I've tried manipulating the mask's opacity. However, that only seems to affect the opacity of the portion I want to leave alone, while the rest of the image is still being cut out completely.

Can anyone point out what I'm doing wrong? Thanks.

Here's my code:

CAShapeLayer *mask = [CAShapeLayer layer];
GMutablePathRef path = CGPathCreateMutable();

CGPathMoveToPoint(path, nil, 1052, 448);
CGPathAddLineToPoint(path, nil, 2, 484);
CGPathAddLineToPoint(path, nil, 54, 1263);
CGPathAddLineToPoint(path, nil, 56, 1305);
CGPathAddLineToPoint(path, nil, 380, 1304);
CGPathAddLineToPoint(path, nil, 1050, 1311);
CGPathCloseSubpath(path);
mask.path = path;
CGPathRelease(path);

//mask.opacity = 0.5; //doesn't affect the surrounding portion, only the cut out area.
self.imageView.layer.mask = mask;
like image 204
Vadoff Avatar asked Apr 04 '13 04:04

Vadoff


2 Answers

What you're doing wrong is using a layer mask in the first place. You are trying to shade or darken an area of your image. That's not what a layer mask does at all! Basically a layer mask punches through in an existing layer, causing whatever is behind it to show through. That's exactly what you discovered:

it's completely removing it instead

Yes, because that's what layer masks do! If you don't want that, why are you using a layer mask?

What you want is just to lay a second image view (or just a sublayer) over the first one. It contains an image that you draw. It is transparent except where it has a semi-transparent dark color fill. That will darken what's behind it. You use a clipping path to define the area that doesn't get the dark color fill.

Alternatively, alter the image in your image view by drawing on top of it with compositing or possibly using a CIFilter.

like image 179
matt Avatar answered Oct 04 '22 21:10

matt


In case anyone else has the same issue: if the goal is to darken the layer, the mask is not suitable. But if you need to make a part of the image transparent or semi-transparent, it is definitely a great way to go.

For example, this code could live in an NSView subclass:

    let imageLayer = CALayer()
    let maskLayer = CAShapeLayer()

    let ovalPath = NSBezierPath(ovalIn: bounds)
    maskLayer.path = ovalPath
    maskLayer.autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
    maskLayer.frame = bounds
    maskLayer.backgroundColor = NSColor.black.withAlphaComponent(0.2).cgColor

    imageLayer.contents = NSImage(named: "sampleImage")
    imageLayer.autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
    imageLayer.frame = bounds


    imageLayer.mask = maskLayer

This gives 0.2 opacity to an oval 'hole' in the imageLayer.

like image 26
julia_v Avatar answered Oct 04 '22 20:10

julia_v