Replicate result `func masking(_ mask: CGImage) -> CGImage?` by Core Image framework

533 views Asked by At

Is there an option to replicate func masking(_ mask: CGImage) -> CGImage? from Core Graphics using CoreImage and one of CIFilter? I've tried CIBlendWithMask and CIBlendWithAlphaMask without success. Most important thing is that I need to preserve alpha channel, so I want image to be masked in such way, that if mask is black -> show Image, if mask is white -> transparent. My masking code:

extension UIImage {
    
    func masked(by mask: UIImage) -> UIImage {
        guard let maskRef = mask.cgImage,
            let selfRef = cgImage,
            let dataProvider = maskRef.dataProvider,
            let mask = CGImage(
                maskWidth: maskRef.width,
                height: maskRef.height,
                bitsPerComponent: maskRef.bitsPerComponent,
                bitsPerPixel: maskRef.bitsPerPixel,
                bytesPerRow: maskRef.bytesPerRow,
                provider: dataProvider,
                decode: nil,
                shouldInterpolate: false),
            let masked = selfRef.masking(mask) else {
                    fatalError("couldnt create mask!")
        }
        let maskedImage = UIImage(cgImage: masked)
        return maskedImage
    }
}
2

There are 2 answers

0
Prettygeek On BEST ANSWER

I found solution. Key is to use image that has grayscale format, rgb and other will not work. Resizing step can be removed, if image and maks have the same size. Doable as extension, can be done as subclass of CIImage too. Enjoy:)

Of course It can be modified as extension to UIImage, CIImage, CIFilter, how You like it.

extension CGImage {
    
    func masked(by cgMask: CGImage) -> CIImage {
        let selfCI = CIImage(cgImage: self)
        let maskCI = CIImage(cgImage: cgMask)
        
        let maskFilter = CIFilter(name: "CIMaskToAlpha")
        maskFilter?.setValue(maskCI, forKey: "inputImage")
        let scaleFilter = CIFilter(name: "CILanczosScaleTransform")
        scaleFilter?.setValue(maskFilter?.outputImage, forKey: "inputImage")
        scaleFilter?.setValue(selfCI.extent.height / maskCI.extent.height, forKey: "inputScale")
        let filter: CIFilter! = CIFilter(name: "CIBlendWithAlphaMask")
        filter.setValue(selfCI, forKey: "inputBackgroundImage")
        let maskOutput = scaleFilter?.outputImage
        filter.setValue(maskOutput, forKey: "inputMaskImage")
        let outputImage = filter.outputImage!
        return outputImage
    }
}
2
rommex On

You need to create your own custom CIFilter. The tutorials:

Apple Docs

Apple Docs 2

Raywenderlich.com Tutorial

This is not trivial, but it pays off when you learn how to do it :)