• Stars
    star
    100
  • Rank 330,186 (Top 7 %)
  • Language
    Objective-C
  • Created almost 12 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An Objective-C wrapper for CoreGraphics CGContext

MPWDrawingContext, version 0.3

An Objective-C wrapper around the CoreGraphics CGContextRef. It includes the MPWDrawingContext protocol and the MPWCGDrawingContext class that implements that protocol by calling CoreGraphics CGContextRef functions.

The idea is for the context to be lightweight and straightforward enough that including it is a no-brainer.

The MPWDrawingContext protocol itself has no dependencies on AppKit, UIKit or CoreGraphics.

Also includes is MPWView, a View class that subclasses UIView on iOS and NSView on OSX and renders using an MPWDrawingContext. The sample applications for both OSX and iOS use the same view code. MPWView also allows drawing and event-handling code to be specified using blocks, so trivial views don't require a subclass.

PhoneGeometry.h provides NSPoint, NSSize and NSRect data-types on iOS by mapping them to their CoreGraphcis equivalents there.

The protocol aims to provide a "fluent" interface so that commands can be chained.

ChangeLog

Version 0.3

  • object-based single argument convenience methods (moveto,lineto,etc.)
  • shadows also block-based
  • linecap
  • drawOnContext: for blocks
  • some unit tests

Version 0.2

  • actually made separate subclasses for PDF and Bitmap contexts
  • initial pattern support (only for colored patterns)
  • blocks everywhere, especially for re-usable images
  • use images or block-drawables directly as (pattern colors)

Version 0.1

  • first release

Future Plans

  • expand text rendering to include most of CoreText (or equivalents)
  • more context types, for example rendering to CALayers, SVG and Canvas or OpenGL textures
  • image processing options, both stand-alone and as layered contexts

Creation

Creation methods are not part of the MPWDrawingContext protocol, but left to specific context classes.

If you already have a CGContextRef or want to use the current one:

+contextWithCGContext:(CGContextRef)c;
-initWithCGContext:(CGContextRef)newContext;
+currentContext;

Alternatively you can create a new bitmap context with a current size.

+rgbBitmapContext:(NSSize)size;
+cmykBitmapContext:(NSSize)size;

-initBitmapContextWithSize:(NSSize)size colorSpace:(CGColorSpaceRef)colorspace;

Paths

These are direct analogs to the corresponding CG functions. Use like this: [[context nsrect:[self bounds]] fill];

Construction:

-(id <MPWDrawingContext>)moveto:(float)x :(float)y;
-(id <MPWDrawingContext>)lineto:(float)x :(float)y;
-(id <MPWDrawingContext>)curveto:(float)cp1x :(float)cp1y :(float)cp2x :(float)cp2y :(float)x :(float)y;
-(id <MPWDrawingContext>)closepath;
-(id <MPWDrawingContext>)nsrect:(NSRect)r;
-(id <MPWDrawingContext>)arcWithCenter:(NSPoint)center radius:(float)radius startDegrees:(float)start endDegrees:(float)stop  clockwise:(BOOL)clockwise;
-(id <MPWDrawingContext>)arcFromPoint:(NSPoint)p1 toPoint:(NSPoint)p2 radius:(float)radius;
-(id <MPWDrawingContext>)ellipseInRect:(NSRect)r;

Drawing:

-(void)clip;
-(void)fill;
-(void)eofill;
-(void)eofillAndStroke;
-(void)fillAndStroke;
-(void)stroke;

Gradients:

-(id <MPWDrawingContext>)drawLinearGradientFrom:(NSPoint)startPoint to:(NSPoint)endPoint colors:(NSArray*)colors offsets:(NSArray*)offsets;
-(id <MPWDrawingContext>)drawRadialGradientFrom:(NSPoint)startPoint radius:(float)startRadius to:(NSPoint)endPoint radius:(float)endRadius colors:(NSArray*)colors offsets:(NSArray*)offsets;

Images

There is currently just a single method:

-(id <MPWDrawingContext>)drawImage:anImage;

The type of the image is purposely undefined. MPWCGDrawingContext expects that it either responds to (a) -CGImage to return a CGImageRef (as both UIImage and NSBitmapImageRep do) or (b) can render itself using -drawOnContext:(id )aContext;

Images are rendered at their natural size (sent -size).

Text

-(id <MPWDrawingContext>)show:(id)someText; 
-(id <MPWDrawingContext>)setTextPosition:(NSPoint)p;
-(id)fontWithName:(NSString*)name size:(float)size;
-(id <MPWDrawingContext>)setFont:aFont;

Text support is currently very rudimentary, sporting only the single -show: message. It can be passed either an NSString or an NSAttributedString. In the former case, drawing parameters will be taken from the current graphics state, in the latter they will be taken from the NSAttributedString itself.

The -setFont: message takes as its argument a font returned by -fontWithName:size:. We purposely don't specify what exact class the font will be.

Graphics State

Setting colors uses the same pattern as setting fonts: there are two basic color-setting messages:

-(id <MPWDrawingContext>)setFillColor:(id)aColor;
-(id <MPWDrawingContext>)setStrokeColor:(id)aColor;

These are complemented by a number of messages returning color objects, again we don't exactly say what class they will be, just that they are compatible with the color-setting methods.

-(id)colorRed:(float)r green:(float)g blue:(float)b alpha:(float)alpha;
-(id)colorCyan:(float)c magenta:(float)m yellow:(float)y black:(float)k alpha:(float)alpha;
-(id)colorGray:(float)gray alpha:(float)alpha;

So setting an RGB fill color works as follows:

[context setFillColor:[context colorRed:1.0 green:0 blue:0 alpha:0]];

There are also plural versions of these methods:

-(id)colorsRed:r green:g blue:b alpha:alpha;
-(id)colorsCyan:c magenta:m yellow:y black:k alpha:alpha;
-(id)colorsGray:gray alpha:alpha;

The key to these methods is that they allow array parameters and allow array an non-array parameters to be mixed. For example:

[context colorRed:@[ 0.0 0.5 1.0 ] green:@0 blue:@0 alpha:@1];

will return 3 colors ranging from black to red. This comes in handy when specifying sets of related colors, for example for gradients.

CTM transformations:

-(id <MPWDrawingContext>)translate:(float)x :(float)y;
-(id <MPWDrawingContext>)scale:(float)x :(float)y;
-(id <MPWDrawingContext>)rotate:(float)degrees;

Saving and restoring:

-(id <MPWDrawingContext>)gsave;
-(id <MPWDrawingContext>)grestore;

Miscellaneous parameters:

-(id <MPWDrawingContext>)setdashpattern:array phase:(float)phase;
-(id <MPWDrawingContext>)setlinewidth:(float)width;
-(id <MPWDrawingContext>)setlinecapRound;
-(id <MPWDrawingContext>)setlinecapSquare;
-(id <MPWDrawingContext>)setlinecapButt;


-(id <MPWDrawingContext>)setAlpha:(float)alpha;
-(id <MPWDrawingContext>)setAntialias:(BOOL)doAntialiasing;
-(id <MPWDrawingContext>)setShadowOffset:(NSSize)offset blur:(float)blur color:(id)aColor;
-(id <MPWDrawingContext>)clearShadow;

Block-based:

-withShadowOffset:(NSSize)offset blur:(float)blur color:aColor draw:(DrawingBlock)commands;
-ingsave:(DrawingBlock)drawingCommands;
-(id)drawLater:(DrawingBlock)drawingCommands;
-layerWithSize:(NSSize)size content:(DrawingBlock)drawingCommands;
-laterWithSize:(NSSize)size content:(DrawingBlock)drawingCommands;
-page:(NSDictionary*)parameters content:(DrawingBlock)drawingCommands;

Convenience:

-(id <MPWDrawingContext>)translate:(id)aPoint;
-(id <MPWDrawingContext>)scale:(id)aPointOrNumber;
-(id <MPWDrawingContext>)moveto:(id)aPoint;
-(id <MPWDrawingContext>)lineto:(id)aPoint;

Infrequently Asked Questions

Why would anyone need an Objective-C drawing context?

In short, while CoreGraphics is an awesome graphics subsystem, not having OO features makes CGContext closed to extension by anyone but Apple, and somewhat unpleasant to use, IMHO.

I explain a bit more about the motivation on my blog: http://blog.metaobject.com/2012/06/pleasant-objective-c-drawing-context.html

Who cares about possible future expansion when that means there's lots of code to integrate with nasty dependencies?

It used to be just 1 Class, 1 Protocol, 3 extra include files to equalize some of the differences between iOS and OSX (could probably be reduced), but it's admittedly a little more now: Classes for different context types, for storing drawing commands and even (gasp!) an abstract class that captures some commonality between contexts. Still totally worth it, though.

1 additional class (MPWView) is purely optional

In the github project, the code is actually integrated into an adapted version of Matt Gallagher's IconApp (with some inspiration from Marcus Crafter's iOS port of same), so you have a working example right there.

But Cocoa has some fine drawing functionality with NSBezierPath, NSAffineTransform and friends

True, but MPWDrawingContext works identically on both iOS and Mac OS X. In fact there's also an MPWView class that works on both iOS and OSX, which is used in the sample code mentioned above to create an iOS app using the same drawing code as the OS X app.

I also prefer my graphics context to not be a hidden global parameter that's implicitly used by a bunch of other objects.

Who cares about OSX^H^H^H iOS?

Based on my unscientific experiments, MPWDrawingContext reduces the code I have to write for even one of the two platforms by about 20-30%. Your mileage will almost certainly vary.

Who cares about less code?

Well, it\s not just less code, it's more pleasant code as well:

[[[[[context moveto:0 :0] lineto:100 :0] lineto:50 :50] closepath] stroke];

vs.

CGContextMoveToPoint( context, 0, 0 );
CGContextAddLineToPoint( context, 100, 0);
CGContextAddLineToPoint( context, 50, 50 );
CGContextClosePath( context );
CGContextFillPath( context );

And

    bitmap = [context bitmapWithSize:NSMakeSize( 595, 842 ) commands:^(Drawable){  ... }];

vs.

bitmapContext = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0,
                       CGColorSpaceCreateDeviceRGB(),   
                       kCGImageAlphaPremultipliedLast)  | kCGBitmapByteOrderDefault );
{ .... } 
    cgBitmap = CGBitmapContextCreateImage( bitmapContext );
bitmap = [UIImage imageWithCGImage:cgBitmap];
CGImageRelease(cgBitmap);
CGContextRelease(bitmapContext);

No it's not!

OK :-)

More Repositories

1

Objective-Smalltalk

Objective-C
224
star
2

iOS-macOS-performance

Sample Code for "iOS and macOS Performance Tuning" (Addison Wesley)
Objective-C
146
star
3

MPWFoundation

Objective-C
111
star
4

ObjectiveHTTPD

High performance Objective-C web framework based on libmicrohttpd
Objective-C
22
star
5

Objective-XML

Objective-C
20
star
6

UIKonf-2015-Software-Arch

Presentation Slides for the UIKonf 2015 talk on software architecture in iOS and MacOS X applications
13
star
7

pLucid-osx

A "port" of plucid that works on OS X
C
12
star
8

MPWTest

The simplest Objective-C Unit Test Framework that could possibly work...
Objective-C
9
star
9

ObjectiveTcc

Tinycc as an Objective-C framework
Objective-C
7
star
10

HOM

Higher Order Messaging
Objective-C
7
star
11

SoftArchLon2016-In-Process-REST

Slides for my In-process REST presentation held at the O'Reilly Software Architecture Conference London 2016
5
star
12

DrawingContext

Objective-C
4
star
13

DeltaBlueObjC

Port of the C version of DeltaBlue to Objective-C
PostScript
3
star
14

FlowChat

Super simplistic network chat application demonstrating the use of ObjectFlow
Objective-C
3
star
15

marcelweiher-libobjc2

Automatically exported from code.google.com/p/marcelweiher-libobjc2
Objective-C
3
star
16

stsh

Smalltalk scripting shell based on Objective-Smalltalk
Objective-C
2
star
17

objective-smalltalk-container

Dockerfile and binaries to create a docker container for running stsh, the Objective-Smalltalk shell
Shell
2
star
18

musselwind

iPhone App that reports wind conditions at the Mussel Rock paragliding site outside of San Francisco
Objective-C
1
star
19

dc-lib

Automatically exported from code.google.com/p/dc-lib
C
1
star
20

SoftArchLon2016-Reactive-Dataflow-Constraints

Slides for my Reactive Dataflow Constraints presentation held at the O'Reilly Software Architecture Conference London 2016
1
star