2006/03/01
Quartz Musings: Recap
- The first post was about basic CoreGraphics drawing: line and shape drawing, a bit of path handling, the recently added and powerful layer abstraction, and general Quartz discussion.
- The second episode was about graphics contexts in CoreGraphics. The PDF context is an important one, as the Quartz drawing model is directly inspired by PDF. This post described how to easily generate PDF data (post updated to include PDF rendering).
- The third part was again about graphics contexts, with the example of the more experimental Quartz GLContext.
- The fourth post showed how to integrate CoreGraphics with another graphic system: OpenGL. In the code example, the CoreGraphics rendering is drawn on an offscreen bitmap context, and then uploaded as a texture in OpenGL.
- The fifth post is also GPU-oriented, but stays in OS X API, with a bitmap rendering used as an image on which a realtime GPU zoom/blur effect is applied, through the Core Image framework.
Here is the compiled application, and a source archive. As I'm using CoreImage and CGLayer, this application is 10.4 only, although the source code is probably still interesting for the PDF, GLContext and raw CoreGraphics snippets for older systems. Note also that the Core Image, OpenGL, or GLContext might give bogus results on some graphic cards, as I'm playing with unusually big textures (I tested with a GeForce6800 - I know there are issues with a 4MX for instance, and it won't work with a Rage128). These examples are provided on an as-is basis, so use at your own risk. In some cases, the code has been simplified to be a better example, and is probably not of production quality. Please let me know if you find this useful or if you spot any error or omission!
The solution to all of this was to call graphicsContextWithGraphicsPort in a new NSAutoReleasePool, and letting the release pool go, which allows the cgcontext to be destroyed when CGReleaseContext is called.
Here is my code:
// (almost same as you have, but note we are supposed to call CGPDFContextBeginPage....
CGContextRef context;
CGDataConsumerRef datacon;
NSMutableData* data;
data = [[[NSMutableData alloc] init] autorelease];
datacon = CGDataConsumerCreateWithCFData((CFMutableDataRef)data);
context = CGPDFContextCreate(datacon,&bounds,NULL);
CGPDFContextBeginPage (context, NULL); // use PDF variants
/* My drawing code, using 'context' */
CGPDFContextEndPage (context);
CGContextRelease (context); // the ref count on the context needs to go to zero here so the context can dealloc, which will write PDF trailer out.
CGDataConsumerRelease(datacon);
[self setDocument:[[[PDFDocument alloc] initWithData:data] autorelease]];
myCustomDrawingInContext(CGContextRef inContext, NString* theString)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Create an NSGraphicsContext that draws into the CGContext.
NSGraphicsContext *graphicsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:inContext flipped:NO];
// Make the NSGraphicsContext current and draw into it.
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:graphicsContext];
NSPoint thePoint;
thePoint.x = 200;
thePoint.y = 200;
[theString drawAtPoint:thePoint withAttributes:NULL];
[NSGraphicsContext restoreGraphicsState];
[pool release];
graphicsContext = NULL; // the destruction of the graphicsContext with a dealloc that happened at pool release will allow the CGContextRef to really destroy itself
}
Thought I should post this, as it took me a while to figure this out.
Tom Andersen
http://www.bodyjournal.com/
<< Home