skip to Main Content

I’m trying to apply this mask to the original image

enter image description here

Notice there are some grey areas, I want to keep everything except PURE black.

I’ve found this code

 func maskImage(image: UIImage, mask: UIImage) -> UIImage {
    let imageReference = (image.cgImage)!
    let maskReference = (mask.cgImage)!

    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
    )

    return (UIImage(cgImage: (imageReference.masking(imageMask!))!))
}

But it does the opposite, it removes all white pixels instead.

2

Answers


  1. 
    func maskImage(image: UIImage, mask: UIImage) -> UIImage {
        let imageReference = image.cgImage!
        let maskReference = mask.cgImage!
        
        let width = maskReference.width
        let height = maskReference.height
        let bitsPerComponent = maskReference.bitsPerComponent
        let bitsPerPixel = maskReference.bitsPerPixel
        let bytesPerRow = maskReference.bytesPerRow
        
        let context = CGContext(
            data: nil,
            width: width,
            height: height,
            bitsPerComponent: bitsPerComponent,
            bytesPerRow: bytesPerRow,
            space: CGColorSpaceCreateDeviceGray(),
            bitmapInfo: CGImageAlphaInfo.none.rawValue
        )
        
        context!.draw(maskReference, in: CGRect(x: 0, y: 0, width: width, height: height))
        
        let maskImage = context!.makeImage()!
        
        let maskedReference = imageReference.masking(maskImage)!
        
        return UIImage(cgImage: maskedReference)
    }
    

    This code creates a new CGContext specifically for the mask image and sets the color space to grayscale (CGColorSpaceCreateDeviceGray()) to ensure that only black pixels are treated as opaque. The CGImageAlphaInfo.none parameter is used to specify that the mask image has no alpha channel.

    By drawing the maskReference into the context, the mask is created with the desired behavior of keeping all non-black pixels. Then, the maskImage is used to mask the imageReference, resulting in an image with the desired effect.

    Login or Signup to reply.
  2. Make the mask inverted before applying it like:

    let maskReference = (mask.inverseImage()!.cgImage)!
    

    Using this simple extension:

    extension UIImage {
        func inverseImage() -> UIImage? {
            let coreImage = CIImage(image: self)
            guard let filter = CIFilter(name: "CIColorInvert") else { return nil }
            filter.setValue(coreImage, forKey: kCIInputImageKey)
            guard let result = filter.value(forKey: kCIOutputImageKey) as? CIImage else { return nil }
            guard let cgImage = CIContext(options: nil).createCGImage(result, from: result.extent) else { return UIImage(ciImage: result) }
            return UIImage(cgImage: cgImage)
        }
    }
    

    By the way, I suggest inverting the mask outside the code for better performance if possible

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