Why applied CILinearGradient to CIMaskedVariableBlur shrinks image of UIImageView?

63 views Asked by At

I'm tring example code of Apple's Selectively Focusing on an Image article. However image of UIImageView is shrinked after filter applied. I can not figure out where is the problem. Needs your help.

Here is my code:

        self.view.addSubview(imageView)
        imageView.contentMode = .scaleAspectFill
        imageView.layer.masksToBounds = true
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        imageView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
        imageView.widthAnchor.constraint(equalToConstant: 270).isActive = true
        imageView.heightAnchor.constraint(equalToConstant: 480).isActive = true
        
        if let uiImage = UIImage(named: "Image"), let ciImage = CIImage(image: uiImage) {
            let h = ciImage.extent.size.height
            guard let topGradient = CIFilter(name:"CILinearGradient") else {
                return
            }
            topGradient.setValue(CIVector(x:0, y:0.85 * h),
                                 forKey:"inputPoint0")
            topGradient.setValue(CIColor.green,
                                 forKey:"inputColor0")
            topGradient.setValue(CIVector(x:0, y:0.6 * h),
                                 forKey:"inputPoint1")
            topGradient.setValue(CIColor(red:0, green:1, blue:0, alpha:0),
                                 forKey:"inputColor1")
            
            guard let bottomGradient = CIFilter(name:"CILinearGradient") else {
                return
            }
            bottomGradient.setValue(CIVector(x:0, y:0.35 * h),
                                    forKey:"inputPoint0")
            bottomGradient.setValue(CIColor.green,
                                    forKey:"inputColor0")
            bottomGradient.setValue(CIVector(x:0, y:0.6 * h),
                                    forKey:"inputPoint1")
            bottomGradient.setValue(CIColor(red:0, green:1, blue:0, alpha:0),
                                    forKey:"inputColor1")
            
            guard let gradientMask = CIFilter(name:"CIAdditionCompositing") else {
                return
            }
            gradientMask.setValue(topGradient.outputImage,
                                  forKey: kCIInputImageKey)
            gradientMask.setValue(bottomGradient.outputImage,
                                  forKey: kCIInputBackgroundImageKey)
            
            guard let maskedVariableBlur = CIFilter(name:"CIMaskedVariableBlur") else {
                return
            }
            maskedVariableBlur.setValue(ciImage, forKey: kCIInputImageKey)
            maskedVariableBlur.setValue(gradientMask.outputImage, forKey: "inputMask")
            if let selectivelyFocusedCIImage = maskedVariableBlur.outputImage {
                imageView.image = UIImage(ciImage: selectivelyFocusedCIImage)
            }
            
        }

Result:

enter image description here

I'm tring to apply CIMaskedVariableBlur fiter to my UIImageView however image of UIImageView is shrinked unexpectedly.

1

There are 1 answers

1
DonMag On

It's not really "shrinking" the image... in fact, it's growing the image. Because you have your image view's contentMode set to .scaleAspectFill you're not seeing the actual output UIImage.

Aside from that, things can get confusing anyway...

When using CIFilter and translating between UIImage and CIImage (and/or CGImage) we have to take the .extent rect into account.

Rather than trying to precisely explain that (in part because I'm not entirely clear on it to begin with), here's how you can get back what you're expecting from that (Apple's example) code.

If you change the very last "conversion" part from:

if let selectivelyFocusedCIImage = maskedVariableBlur.outputImage {
    imageView.image = UIImage(ciImage: selectivelyFocusedCIImage)
}

to:

if let selectivelyFocusedCIImage = maskedVariableBlur.outputImage {
    let context = CIContext()
    if let cgimg = context.createCGImage(selectivelyFocusedCIImage, from: ciImage.extent) {
        imageView.image = UIImage(cgImage: cgimg)
    }
}

you should get the expected result.