5

I am having trouble with getting a UIImage from and CIImage. The line of code below works fine on iOS6: (Output image is an CIImage)

self.imageView = [UIImage imageWithCIImage:outputImage];

or

[self.imageView setImage:[UIImage imageWithCIImage:outputImage]];

When I run this same line of code on a device that is running iOS 5 the imageView is blank. If I log the size property of the UIImage it is correct but the image never displays on the screen.

When I use a CGImageRef (as shown below) it works fine on both devices but it causes huge memory growth when I do a heap shot analysis.

context = [CIContext contextWithOptions:nil];
CGImageRef ref = [context createCGImage:outputImage fromRect:outputImage.extent];
self.imageView.image = [UIImage imageWithCGImage:ref scale:1.0 orientation:UIImageOrientationUp];
CGImageRelease(ref);

Does anyone know why UIImage imageWithCIImage does not work? According to the UIImage class reference it should work on iOS5 and above. Also why does using CGImageRef cause such massive heap growth?

Thank you

Brad Larson
  • 168,330
  • 45
  • 388
  • 563
dana0550
  • 1,125
  • 1
  • 8
  • 16

1 Answers1

4

On iOS 5.0, -imageWithCIImage: never seemed to work properly, and we were told to use the -createCGImage:fromRect: approach you describe above in order to render the Core Image filter chain to a raster output.

As you see, the downside to this is that -createCGImage:fromRect: creates a new CGImageRef at the size of your target image, and the bitmap at its heart is passed on to your new UIImage. This probably means that you have at least two full bitmaps representing your final filtered frame in memory at one point, which could cause quite a spike if these are large images.

It appears that -imageWithCIImage: has been fixed in iOS 6.0 (Core Image has had a lot of improvements made from 5.0 to 6.0). While I can only speculate as to why it doesn't lead to this memory spike, I bet it's due to the use of a texture cache to share memory between the output OpenGL ES texture from the filtering process and the final bitmap that's stored in your UIImage. I do this in my GPUImage framework to cut down on memory consumption when filtering large images, and it would make sense for Core Image to do the same. Again, this is just speculation.

Unfortunately, it looks like you'll need to do a little version testing here and fall back to the old way of getting output from CIImages if you want to support iOS 5.0 with your application.

Brad Larson
  • 168,330
  • 45
  • 388
  • 563
  • Brad thank you for the answer. On the way home yesterday I was going over this problem in my head and I think I found a solution. I really appreciate your response and I noticed this question has been asked before. The main problem with using the CGImageRef is that the heap continuously grows even though I am releasing the object. I will post my solution below after a little more testing in instruments but I do like your approach of version testing. Thanks again. – dana0550 Oct 16 '12 at 13:55
  • 2
    I've found imageWithCIImage to still be very buggy as of iOS 8 – jjxtra Mar 12 '15 at 01:05
  • 3
    @dana0550 Have you ever find an optimal solution to this problem? It seems like imageWithCIImage is still bugged in iOS 8. – Montas Aug 26 '15 at 15:01
  • 2
    Seems to be bugged in iOS 12, too. – Wizard Oct 17 '18 at 11:46