Search code examples
iosswiftuiimagecgimageciimage

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


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
    }
}

Solution

  • 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
        }
    }