Using a CGBitmapContext


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 Bitmap

Allocating 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

CGImageRef CreateCGImageRef() {     // Were going to draw our image into an offscreen bitmap     // and then use that bitmap to create a CGImage.     const int kBytesPerPixel = 4;     const CGSize imageSize = { 512.0, 512.0 };     // calculate 16 byte aligned row bytes     unsigned long rowBytes = ((((unsigned int)imageSize.width *             kBytesPerPixel) + 15) / 16) * 16;     unsigned long dataLength = (unsigned int)imageSize.height *             rowBytes;     // allocate space for the image buffer     UInt8 *imageBuffer = (UInt8*) malloc(dataLength);     // we'll be using gray and rgb colors     CGColorSpaceRef rgbColorSpace =             CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);     CGColorSpaceRef grayColorSpace =             CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);     // Create the context. ARGB, 32 bits per pixel     CGContextRef bitmapContext = CGBitmapContextCreate( imageBuffer,             (int) imageSize.width, (int) imageSize.height, 8, rowBytes,             rgbColorSpace, kCGImageAlphaPremultipliedFirst);     // Use the offscreen context for drawing and create     // a CGImage from it in the retVal variable.     //     // ... code omitted ...     //     // we're done with the bitmap context and can release it     CGContextRelease(bitmapContext);     CGColorSpaceRelease(rgbColorSpace);     CGColorSpaceRelease(grayColorSpace);     return retVal; } 

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.

As is the case with CGImages, Quartz 2D supports a broad variety of pixel formats for bitmap contexts. The number of possible pixel arrangements is smaller for bitmap contexts than it is for images. The valid pixel formats are documented in Apple's Technical Q&A 1037, which can be found on the web at the URL

http://developer.apple.com/qa/qa2001/qa1037.html

At the time of this writing, this document was incomplete and did not include updated information for Mac OS X 10.4 Tiger. For example, in Tiger, Apple added support for floating point pixels in graphics context.


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.




Quartz 2D Graphics for Mac OS X Developers
Quartz 2D Graphics for Mac OS X Developers
ISBN: 0321336631
EAN: 2147483647
Year: 2006
Pages: 100

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net