Swift: CGImage.masking returns nil

Viewed 917

Why does CGImage.masking method may return nil? I can't find any documentation on this. My code for some images returns nil:

extension UIImage {

func maskedImage(mask:(UIImage))->UIImage{
    let croppingRect = CGRect(x: abs(self.size.width-mask.size.width)/2*self.scale,
                              y: abs(self.size.height-mask.size.height)/2*self.scale,
                              width: mask.size.width*self.scale,
                              height: mask.size.height*self.scale).integral
    let maskReference = mask.cgImage!
    let imageReference = self.cgImage!.cropping(to: croppingRect)!
    let imageMask = CGImage(maskWidth: maskReference.width,
                            height: maskReference.height,
                            bitsPerComponent: maskReference.bitsPerComponent,
                            bitsPerPixel: maskReference.bitsPerPixel,
                            bytesPerRow: maskReference.bytesPerRow,
                            provider: maskReference.dataProvider!, decode: nil, shouldInterpolate: true)

    let maskedReference = imageReference.masking(imageMask!)
    // maskedReference is nil so the next line crashes
    let maskedImage = UIImage(cgImage:maskedReference!, scale: self.scale, orientation: self.imageOrientation)

    return maskedImage        
}

}

UPDATE This code in for playground wit exact same image and mask does not crash. Though it doesn't mask image properly:

import UIKit

extension UIImage {
    static func resizeImage(image: UIImage, width: CGFloat) -> UIImage {
        let scale = width / image.size.width
        let newHeight = round(image.size.height * scale)
        UIGraphicsBeginImageContextWithOptions(CGSize(width:width, height:newHeight), false, image.scale)

        image.draw(in: CGRect(origin: CGPoint(x:0, y:0), size: CGSize(width: width, height: newHeight)))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    }

    static func resizeImage(image: UIImage, height: CGFloat) -> UIImage {
        let scale = height / image.size.height
        let newWidth = round(image.size.width * scale)
        UIGraphicsBeginImageContextWithOptions(CGSize(width:newWidth, height:height), false, image.scale)
        image.draw(in: CGRect(origin: CGPoint(x:0, y:0), size: CGSize(width: newWidth, height: height)))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    }
}

let image = UIImage(named: "image.jpg")!
var mask = UIImage(named: "mask.jpg")!

let k1 = image.size.width / image.size.height
let k2 = mask.size.width / mask.size.height

if k1 >= k2
{
    mask = UIImage.resizeImage(image: mask, height: image.size.height)
}
else
{
    mask = UIImage.resizeImage(image: mask, width: image.size.width)
}

image
mask

let center = CGPoint(x: image.size.width/2, y: image.size.height/2)
let croppingRect = CGRect(x: abs(image.size.width-mask.size.width)/2*image.scale,
                                  y: abs(image.size.height-mask.size.height)/2*image.scale,
                                  width: mask.size.width*image.scale,
                                  height: mask.size.height*image.scale).integral
let maskReference = mask.cgImage!
let imageReference = image.cgImage!.cropping(to: croppingRect)!
let imageMask = CGImage(maskWidth: maskReference.width,
                        height: maskReference.height,
                        bitsPerComponent: maskReference.bitsPerComponent,
                        bitsPerPixel: maskReference.bitsPerPixel,
                        bytesPerRow: maskReference.bytesPerRow,
                        provider: maskReference.dataProvider!, decode: nil, shouldInterpolate: true)

imageMask?.colorSpace
imageMask?.alphaInfo

let maskedReference = imageReference.masking(imageMask!)
let maskedImage = UIImage(cgImage:maskedReference!, scale: image.scale, orientation: image.imageOrientation)

image:

image

mask:

mask

The only difference between playground code and real code is that the image is being fetched from the network and initialized like UIImage(data: imageData, scale: UIScreen.main.scale).

0 Answers
Related