Building Contexts in Quartz
Core Graphics enables you to build bitmap contexts without using the UIKit entry points. This approach uses an older API set and is helpful when you need to access drawing data on a byte-by-byte basis. Chapter 3 uses Quartz-based contexts to power several of its image-processing examples.
Listing 1-4 showcases the calls involved. These highlight the greater complexity of using Quartz compared to UIKit. That’s because, among other things, Quartz uses the older-style Core Foundation system of objects, with their manual retain and release patterns.
Always run the Static Analyzer (Product > Analyze in Xcode) on Quartz code to check whether your references are properly released. It provides a source code analysis tool that discovers potential bugs in your iOS code for both UIKit methods and Quartz functions. Read more about the Clang analyzer on the LLVM website, at http://clang-analyzer.llvm.org.
In Listing 1-4, notice the iterative nature of the release patterns. If the context cannot be created, the color space must be freed. At each stage of Core Graphics drawing, you accumulate a trail of allocated objects, which you must properly manage before returning control from a method or function.
As a final point, note how this example uses kCGImageAlphaPremultipliedFirst. This specifies an ARGB byte order, using Quartz-friendly alpha premultiplication. For each pixel, the alpha value is stored in the first of 4 bytes and the blue value in the last. This arrangement is documented in the CGImageAlphaInfo definition in the CGImage.h header file.
Listing 1-4 Building an Image Using Core Graphics Calls
// Create a color space CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); if (colorSpace == NULL) { NSLog(@"Error allocating color space"); return nil; } // Create the bitmap context. (Note: in new versions of // Xcode, you need to cast the alpha setting.) CGContextRef context = CGBitmapContextCreate( NULL, width, height, BITS_PER_COMPONENT, // bits = 8 per component width * ARGB_COUNT, // 4 bytes for ARGB colorSpace, (CGBitmapInfo) kCGImageAlphaPremultipliedFirst); if (context == NULL) { NSLog(@"Error: Context not created!"); CGColorSpaceRelease(colorSpace ); return nil; } // Push the context. // (This is optional. Read on for an explanation of this.) // UIGraphicsPushContext(context); // Perform drawing here // Balance the context push if used. // UIGraphicsPopContext(); // Convert to image CGImageRef imageRef = CGBitmapContextCreateImage(context); UIImage *image = [UIImage imageWithCGImage:imageRef]; // Clean up CGColorSpaceRelease(colorSpace ); CGContextRelease(context); CFRelease(imageRef);