Masking an image in Swift using CALayer and UIImage

user2732722 picture user2732722 · Dec 30, 2014 · Viewed 13.8k times · Source

I'm programming in Swift. I want to mask an image using CALayer and UIImage. I'm creating my mask image programmatically. The created mask image is a UIImage and works fine when I view it on its own. But when I use it as a mask the whole screen becomes white. I suspect that my problem is in configuring the CALayer object. I would appreciate your help. Thanks!

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        var maskImageSize = CGSizeMake(self.imageView.frame.width, self.imageView.frame.height)
        UIGraphicsBeginImageContextWithOptions(maskImageSize, false, 0.0)

        var color = UIColor(white: 1.0, alpha: 1.0)
        color.setFill()
        var rect = CGRectMake(0, 0, self.imageView.frame.width, self.imageView.frame.height)
        UIRectFill(rect)

        color = UIColor(white: 0.0, alpha: 1.0)
        color.setFill()
        rect = CGRectMake((self.imageView.frame.width/2)-100, (self.imageView.frame.height/2)-100, 200, 200)
        UIRectFill(rect)

        var maskImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        var maskLayer = CALayer()
        maskLayer.contents = maskImage
        maskLayer.contentsRect = CGRectMake(0, 0, self.imageView.bounds.width, self.imageView.bounds.height)


        self.imageView.image = UIImage(named: "pictobemasked.png")

        self.imageView.layer.mask = maskLayer;
    }

}

Answer

matt picture matt · Dec 30, 2014

Unfortunately you've asked your question rather badly - you have not said what it is that you are actually trying to do! It looks, however, as if you might be trying to punch a rectangular hole in your image view using a mask. If so, your code has at least three huge flaws.

  • One reason your code is not working is that a mask is based on transparency, not on color. You are using an opaque white and an opaque black, which are both opaque, so there is no difference there. You need your two colors to be like this:

     var color = UIColor(white: 1.0, alpha: 1.0)
    // ... and then, later ...
    color = UIColor(white: 1.0, alpha: 0.0)
    
  • The second problem is that your layer has no size. You need to give it one:

    var maskLayer = CALayer()
    maskLayer.frame = CGRectMake(
        0, 0, self.imageView.bounds.width, self.imageView.bounds.height)
    
  • The third and biggest problem is that your mask image is never getting into your mask layer, because you have forgotten to extract its CGImage:

    maskLayer.contents = maskImage.CGImage
    

That last one is really the killer, because if you set the contents to a UIImage without extracting its CGImage, the image fails silently to get into the layer. There is no error message, no crash - and no image.

Making those three corrections in your code, I was able to make the mask punch a rectangular hole in an image. So if that's your purpose, those changes will achieve it.