Has anyone created a wrapper class for the CGContext group of functions?
I created a simple Gradient class yesterday which encapsulates a subset of CGGradient functionality for simpler memory management. It was pretty straightforward. But there are obviously quite a few more CGContext operations, and I'm not sure I'd want to reinvent the wheel there.
Essentially what I'm looking for is stuff like...
@interface CGContext : NSObject
{
CGContextRef context;
}
+ (CGContext *) bitmapContextWithData:(void *)data
width:(size_t)width
height:(size_t)height
bitsPerComponent:(size_t)bitsPerComponent
bytesPerRow:(size_t)bytesPerRow
colorspace:(CGColorSpaceRef)colorspace
bitmapInfo:(CGBitmapInfo)bitmapInfo;
- (void) saveGState;
- (void) restoreGState;
- (void) setBlendMode:(CGBlendMode)mode;
- (void) addLineToPoint:(CGPoint)point;
- (void) addLineToPointX:(CGFloat)x pointY:(CGFloat)y;
- (void) drawImage:(CGImageRef)image rect:(CGRect)rect;
- (void) concatCTM:(CGAffineTransform)transform;
- (CGAffineTransform) getCTM;
@end
and so forth.
(I do 99% of my drawing into off-screen bitmaps, which is why I care about memory management in this case. If I was always drawing into the current UI graphics context such as the active screen, then I wouldn't really find a wrapper class to be of much use.)
The UIBezierPath class, according to the docs, "is an Objective-C wrapper for the path-related features in the Core Graphics framework... [it] is really just a wrapper for a CGPathRef data type and the drawing attributes associated with that path." The "Drawing and Printing Guide for iOS" has a description of this class with some nice diagrams. (See also its cousins NSBezierPath and CGPathRef.)
As for a wrapper for CGContext itself... Update: ...after I wrote my own proof-of-concept wrapper, I discovered MPWDrawingContext by Marcel Weiher. It adds a bunch of useful methods, and supports chaining too!
I just whipped up a Ruby script to generate a wrapper class for CGContext called CGCanvas:
It's not very useful yet, but it proves the concept. I like being able to see the parameter names, though the API is still cumbersomely functional.
Before:
CGContextFillEllipseInRect(context, CGRectMake(30.0, 210.0, 60.0, 60.0));
CGContextAddArc(context, 150.0, 60.0, 30.0, 0.0, M_PI/2.0, false);
CGContextStrokePath(context);
CGContextAddArc(context, 150.0, 60.0, 30.0, 3.0*M_PI/2.0, M_PI, true);
CGContextStrokePath(context);
After:
[canvas fillEllipseInRect:CGRectMake(30.0, 210.0, 60.0, 60.0)];
[canvas addArc_x:150.0 y:60.0 radius:30.0 startAngle:0.0 endAngle:M_PI/2.0 clockwise:false];
[canvas strokePath];
[canvas addArc_x:150.0 y:60.0 radius:30.0 startAngle:3.0*M_PI/2.0 endAngle:M_PI clockwise:true];
[canvas strokePath];
I did some tricks to make the names make sense... for instance, function names with more than one parameter get the name of the first parameter appended to the base name (unless it already ends with it). I used an underscore instead of the more Cocoa-like "with" to separate the base name from the parameter name, e.g. moveToPoint_x:y:
instead of moveToPointWithX:y:
or moveToPoint:y:
.
If I continue using this class, I'll probably add more constructors, and maybe some block methods (like this guy did), so you can start, build, and stroke a path all at once. Also a lot of names could be shorter still, and a lot of methods could use some defaults.
And maybe method chaining! If only Objective-C wasn't so bracket-crazy. It would have to look like this:
[[[[[[[[canvas
setRGBStrokeColor_red: 1.0 green: 1.0 blue: 1.0 alpha: 1.0]
setRGBFillColor_red:0.0 green:0.0 blue:1.0 alpha:1.0]
setLineWidth:2.0]
fillEllipseInRect:CGRectMake(30.0, 210.0, 60.0, 60.0)]
addArc_x:150.0 y:60.0 radius:30.0 startAngle:0.0 endAngle:M_PI/2.0 clockwise:false]
strokePath]
addArc_x:150.0 y:60.0 radius:30.0 startAngle:3.0*M_PI/2.0 endAngle:M_PI clockwise:true]
strokePath];
(which isn't so horrible, I suppose...)