The first discussion point here is the technique of using a CGBitmapContext for offscreen drawing. Quartz 2D can create graphics contexts on just about any pixel buffer. Just as when working with CGImages, an application owns the memory that the context draws into. Given a block of memory and a series of parameters that describe how the pixels should be laid out in that memory, the routine CGBitmapContextCreate builds a drawing context. The result is "just another CGContextRef" of all of the drawing techniques described in this book that can be applied to it. Given that Quartz does not own the pixel buffer, once the application has finished drawing into the context, it is free to use the pixels in any way. If the offscreen image represents a cached graphic, a common technique is to create a CGImage from the pixel buffer as described in Chapter 8, "Image Basics." Drawing that image will reproduce the graphic on another context. This same CGImage could be written to a file using the processes described in Chapter 9, "Importing and Exporting Images," as well. The application might generate a histogram of the image using the routines in vImage or even swizzle the pixels with custom code. The possibilities are limitless. Creating an Offscreen BitmapAllocating the pixel buffer can be as easy as calling the canonical dynamic memory allocation routine, malloc. The pixel buffer remains the responsibility of the application. In particular the application must make sure that the pixel buffer exists as long as the context is attached to it. The program is also responsible for releasing the pixel buffer after it is no longer needed. After allocating the memory, Quartz 2D also has to know how the application wants to organize the pixels in the memory space. In the discussion of CGImages in Chapter 8, the text covered the parameters that Quartz 2D uses to describe any pixel buffer that contains image data. Core Graphics uses the same fields to describe the buffers for bitmap contexts. The CGBitmapContextCreate routine accepts parameters that describe the pixel format, size, and color environment of the buffer and returns a CGContext that draws on the pixel buffer. This technique has been used several times in the code samples of previous chapters. For example, the full source of the Image I/O Export sample in Chapter 9 creates an offscreen bitmap and draws a simple graphic on it. That part of the code was not examined in Chapter 9, but the code that creates the offscreen context is part of the CreateCGImageRef routine in that sample. That routine is shown in Listing 12.1. Listing 12.1. The CreateCGImageRef Routine from the Image I/O Export Sample
The code begins by declaring constants for many of the parameters that describe our offscreen pixel buffer. One of the oddest calculations is the dance done to calculate rowBytes for the buffer. The point of this dance is to create a rowBytes value that aligns each row to a 16-byte boundary. This is a performance technique that is directed at letting the graphics system use AltiVec with the pixel buffer. The graphics libraries will find it easier to employ AltiVec if each row of the buffer is aligned to a 16-byte boundary. The first row of the image will be 16 byte aligned by virtue of the fact that malloc aligns the memory it allocates to 16-byte boundaries. By fixing the rowBytes to be an even multiple of 16 bytes, we ensure that each row of the offscreen is 16-byte aligned. This is not strictly necessary, particularly for such a simple example. We have retained it in this code sample just to demonstrate a potential optimization you may be able to use in your own code. The code allocates the pixel buffer using malloc and creates a couple of color spaces. The code sample creates the Generic RGB color space for use with the bitmap context. (The grayscale color space is used in drawing code that has been omitted from the listing). With the attributes of the context in hand, you can create the context itself. The parameters to CGBitmapContextCreate ask this sample to treat the memory as a buffer of 32-bit-per-pixel ARGB pixels. The alpha channel will be the first byte of each pixel, and the channels will be premultiplied with the alpha.
For Listing 12.1 the code that actually draws into the offscreen context and creates an image from it has been omitted. After using the context, however, the routine releases the context and the color spaces and then returns from the routine. You will notice that this routine does not release the memory allocated for the offscreen pixel buffer. This code that uses the offscreen buffer creates a CGImage from it. The pixel buffer must exist as long as that image is around to use it. If that were not a requirement, disposing of the pixel buffer would have been as simple as calling free on it. |