skip to Main Content

enter image description hereI am trying to use a CALayer with an image as contents for masking a UIView. For the mask I have complex png image. If I apply the image as a view.layer.mask I get the opposite behaviour of what I want.
Is there a way to reverse the CAlayer? Here is my code:

layerMask = CALayer()
guard let layerMask = layerMask else { return }    
layerMask.contents = #imageLiteral(resourceName: "mask").cgImage
view.layer.mask = layerMask
// What I would like to to is
view.layer.mask = layerMask.inverse. // <---

I have seen several posts on reverse CAShapeLayers and Mutable paths, but nothing where I can reverse a CALayer.
What I could do is reverse the image in Photoshop so that the alpha is inverted, but the problem with that is that I won’t be able to create an image with the exact size to fit all screen sizes. I hope it does make sense.

2

Answers


  1. What I would do is construct the mask in real time. This is easy if you have a black image of the logo. Using standard techniques, you can draw the logo image into an image that you construct in real time, so that you are in charge of the size of the image and the size and placement of logo within it. Using a “Mask To Alpha” CIFilter, you can then convert the black to transparent for use as a layer mask.

    So, to illustrate. Here’s the background image: this is what we want to see wherever we punch a hole in the foreground:

    enter image description here

    Here’s the foreground image, lying on top of the background and completely hiding it:

    enter image description here

    Here’s the logo, in black (ignore the grey, which represents transparency):

    enter image description here

    Here’s the logo drawn in code into a white background of the correct size:

    enter image description here

    And finally, here’s that same image converted into a mask with the Mask To Alpha CIFilter and attached to the foreground image view as its mask:

    enter image description here

    Okay, I could have chosen my images a little better, but this is what I had lying around. You can see that wherever there was black in the logo, we are punching a hole in the foreground image and seeing the background image, which I believe is exactly what you said you wanted to do.

    The key step is the last one, namely the conversion of the black-on-white image of the logo (im) to a mask; here’s how I did that:

        let cim = CIImage(image:im)
        let filter = CIFilter(name:"CIMaskToAlpha")!
        filter.setValue(cim, forKey: "inputImage")
        let out = filter.outputImage!
        let cgim = CIContext().createCGImage(out, from: out.extent)
        let lay = CALayer()
        lay.frame = self.iv.bounds
        lay.contents = cgim
        self.iv.layer.mask = lay
    
    Login or Signup to reply.
  2. If you’re using a CALayer as a mask for another CALayer, you can invert the mask by creating a large opaque layer and subtracting out the mask shape with the xor blend mode.

    For example, this code subtracts a given layer from a large opaque layer to create an mask layer:

    // Create a large opaque layer to serve as the inverted mask
    let largeOpaqueLayer = CALayer()
    largeOpaqueLayer.bounds = CGRect(x: -10_000_000, y: -10_000_000, width: 20_000_000, height: 20_000_000)
    largeOpaqueLayer.backgroundColor = UIColor.black.cgColor
    
    // Subtract out the mask shape using the `xor` blend mode
    let maskLayer = ...
    largeOpaqueLayer.addSublayer(maskLayer)
    maskLayer.compositingFilter = "xor"
    

    enter image description here

    Then you can use that layer as the mask for some other CALayer. For example here I’m using it as the mask of a small blue rectangle:

    smallBlueRectangle.mask = largeOpaqueLayer
    

    enter image description here

    So you can see the mask is inverted! On the other hand if you just use the un-inverted maskLayer directly as a mask, you can see the mask is not inverted:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search