Cannot get a CIFilter originated image to display in IB or simulator

I am unable to get an image that was originally created via a CIFilter to display in IB on on a simulator. Display on a device is fine.


Here is how I am rendering the image:

        if let f = constructFilter(radius: radius, value: sliderView.value.hsba.brightness), let foi = f.outputImage {
            circleView.image = UIImage(ciImage: foi)
        }


And here is how I consruct the filter (the 'value' input parameter is always 1.0):

    private func constructFilter(radius: CGFloat, value: CGFloat) -> CIFilter? {
        guard let cs = CGColorSpace.init(name: CGColorSpace.extendedSRGB) else { return nil }
        
        return CIFilter(name: "CIHueSaturationValueGradient", parameters: [
            "inputColorSpace" : cs,
            "inputDither" : 0,
            "inputRadius" : radius,
            "inputSoftness" : 0,
            "inputValue" : value])
    }


The specific color space doesn't change the behaviour. This also fails:

        return CIFilter(name: "CIHueSaturationValueGradient", parameters: [
            "inputColorSpace" : CGColorSpaceCreateDeviceRGB(),
            "inputDither" : 0,
            "inputRadius" : radius,
            "inputSoftness" : 0,
            "inputValue" : value])


Of course, if I generate the image from a resource it works just fine on device, IB and simulator.


Poking around in the debugger, I notice that extracting png data from the UIImage returns nil when the image has been created from CIFilter - which could explain why IB and simulator fail to display anything


Any thoughts would be welcome.


Regards,

ac

Accepted Reply

When you create a

UIImage
from a
CIImage
(
UIImage(ciImage: foi)
), the filter is not actually applied yet. Only when the
UIImage
is used somewhere, the GPU would process your filter chain. And from my experience this is not very reliable in all scenarios.


What you can do instead is to explicitly render the

CIImage
into a
CGImage
and continue with that:


let context = CIContext() // ideally you only create that once and re-use it
if let outputCGImage = context.createCGImage(image: foi, from: foi.extent) {
    circleView.image = UIImage(cgImage: outputCGImage)
}
dash-apple-api://load?request_key=hsjer5Z_Yw&language=swiftdash-apple-api://load?request_key=hs4qSehPwa&language=swift

Replies

When you create a

UIImage
from a
CIImage
(
UIImage(ciImage: foi)
), the filter is not actually applied yet. Only when the
UIImage
is used somewhere, the GPU would process your filter chain. And from my experience this is not very reliable in all scenarios.


What you can do instead is to explicitly render the

CIImage
into a
CGImage
and continue with that:


let context = CIContext() // ideally you only create that once and re-use it
if let outputCGImage = context.createCGImage(image: foi, from: foi.extent) {
    circleView.image = UIImage(cgImage: outputCGImage)
}
dash-apple-api://load?request_key=hsjer5Z_Yw&language=swiftdash-apple-api://load?request_key=hs4qSehPwa&language=swift

Frank,


Thanks you for your response. I have resolved the issue following along with your advice thus:


        if let f = constructFilter(radius: radius, brightness: sliderView.value.hsba.brightness), let foi = f.outputImage {
            #if TARGET_INTERFACE_BUILDER
            let context = CIContext()
            if let outputCGImage = context.createCGImage(foi, from: foi.extent) {
                circleView.image = UIImage(cgImage: outputCGImage)
            }
            #else
            circleView.image = UIImage(ciImage: foi)
            #endif
        }


I am curious as to the underlying issue here and how IB rendering differs from device rendering. Maybe it is GPU related?


If you have any insights on this I would appreciate heraing them.


Regards,

ac

>how IB rendering differs from device rendering


Remember, the simulator is not an emulator, and runs a stack specifically for your mac and it's hardware. You're basically asking how rendering differs between those platforms...


Stick to device testing if actionable parity is important.


General info via Simulator Help / Differences between simulated and physical devices