Image manipulation and drawing using Quartz in the background threads

August 3rd, 2009 / in IPhone / by keremk /

In many of the iPhone samples, the recommended way of drawing onto off-screen bitmap context begins by getting a bitmap context using the UIGraphicsBeginImageContext() API call. This works great if your drawing code is in the main UI thread, but in some cases you may want to do some processing in a background thread as well. The prime candidate for this is, when you download an image in a background thread and do some resizing/cropping shadows, borders on that image. You would still want to do that in the background thread in order not to block the UI thread and present a smooth experience. That is exactly what I was doing in my latest project (which BTW you can see the work in progress here).

The code works most of the time if you use the UIGraphicsBeginImageContext, but then crashes randomly at some random CoreGraphics calls. The culprit in this case sounded like it was some thread safety issue, and turns out it indeed was. As documented in the SDK, when this API call is made, the drawing environment is pushed onto the graphics context stack immediately. And that seems to be what is causing our threading issues. The context stack becomes shared between the UI thread which does its regular drawing code and the background thread which does the background image manipulation.

Luckily fixing this problem is not hard. All you need to do is to stop using the UIKit APIs and go back to the lower level Quartz APIs.

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height,
                                                 BITS_PER_COMPONENT,
                                                 NUM_OF_COMPONENTS * size.width,
                                                 colorSpaceRef,
                                                 kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colorSpaceRef);
    CGRect rect = CGRectMake(0.0, 0.0, size.width, size.height);
    CGContextClearRect(context, rect);
 
    // Do your drawing and image manipulation..
 
    CGImageRef cgImage = CGBitmapContextCreateImage(context);
    UIImage *image = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);
    CGContextRelease(context);

Tags: , , , , , ,

Reader Comments

  • useful information. It’s really good

  • As far as I understand, none of UIKit is thread safe. So it might be best to do the UIImage creation on the main thread via performSelectorOnMainThread:

    That’s what (I think) I do in my own code.

  • UIKit is not thread safe, but CoreGraphics (mostly) is. In this case, I am creating many images in the background. This is basically piece of some code that displays thumbnails of images in a vertically scrolling view (sort of like image gallery app) with some adornments such as shadows, borders etc. In this case moving this image generation code to the UI thread makes the app unresponsive, as each image generation blocks the UI thread and makes the scrolling jerky. It is best to handle that in the background thread along with downloading of the images in the first place.

  • Some time ago I worked on a “graphics-driven” project and found the same way to make off-screen drawings. Very usefull article.

Add Your Comment