An Objective-C wrapper for CoreGraphics CGContext

Overview

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 :-)

You might also like...
Easy to use CFNetwork wrapper for HTTP requests, Objective-C, Mac OS X and iPhone

ASIHTTPRequest is an easy to use wrapper around the CFNetwork API that makes some of the more tedious aspects of communicating with web servers easier

An easy-to-use Objective-C wrapper for the Uber API (no longer supported)
An easy-to-use Objective-C wrapper for the Uber API (no longer supported)

UberKit UberKit is a simple Objective-C wrapper for the new Uber API . Installation Cocoapods UberKit is available through Cocoapods. To install it, s

Simple Objective-C wrapper for the keychain that works on Mac and iOS

SAMKeychain SAMKeychain is a simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system Keyc

Contacts wrapper for iOS 9 or upper with Objective-C

ContactsWrapper Contacts wrapper for iOS 9 or upper with Objective-C. For the information translated to Russian, take a look at this link. Requirement

💡 A light Swift wrapper around Objective-C Runtime
💡 A light Swift wrapper around Objective-C Runtime

A light wrapper around Objective-C Runtime. What exactly is lumos? lumos as mentioned is a light wrapper around objective-c runtime functions to allow

NTP library for Swift and Objective-C. Get the true time impervious to device clock changes.
NTP library for Swift and Objective-C. Get the true time impervious to device clock changes.

TrueTime for Swift Make sure to check out our counterpart too: TrueTime, an NTP library for Android. NTP client for Swift. Calculate the time "now" im

Soulful docs for Swift & Objective-C
Soulful docs for Swift & Objective-C

jazzy is a command-line utility that generates documentation for Swift or Objective-C About Both Swift and Objective-C projects are supported. Instead

Modern thread-safe and type-safe key-value observing for Swift and Objective-C

Now Archived and Forked PMKVObserver will not be maintained in this repository going forward. Please use, create issues on, and make PRs to the fork o

MisterFusion is Swift DSL for AutoLayout. It is the extremely clear, but concise syntax, in addition, can be used in both Swift and Objective-C. Support Safe Area and Size Class.
MisterFusion is Swift DSL for AutoLayout. It is the extremely clear, but concise syntax, in addition, can be used in both Swift and Objective-C. Support Safe Area and Size Class.

MisterFusion MisterFusion makes more easier to use AutoLayout in Swift & Objective-C code. Features Simple And Concise Syntax Use in Swift and Objecti

The ultimate API for iOS & OS X Auto Layout — impressively simple, immensely powerful. Objective-C and Swift compatible.
The ultimate API for iOS & OS X Auto Layout — impressively simple, immensely powerful. Objective-C and Swift compatible.

The ultimate API for iOS & OS X Auto Layout — impressively simple, immensely powerful. PureLayout extends UIView/NSView, NSArray, and NSLayoutConstrai

A Matcher Framework for Swift and Objective-C

Nimble Use Nimble to express the expected outcomes of Swift or Objective-C expressions. Inspired by Cedar. // Swift expect(1 + 1).to(equal(2)) expect(

The Swift (and Objective-C) testing framework.
The Swift (and Objective-C) testing framework.

Quick is a behavior-driven development framework for Swift and Objective-C. Inspired by RSpec, Specta, and Ginkgo. // Swift import Quick import Nimbl

SwiftyTimer allows you to instantly schedule delays and repeating timers using convenient closure syntax. It's time to get rid of Objective-C cruft.

SwiftyTimer Modern Swifty API for NSTimer SwiftyTimer allows you to instantly schedule delays and repeating timers using convenient closure syntax. It

Catch Objective-C exceptions in Swift

ExceptionCatcher Catch Objective-C exceptions in Swift There are many Cocoa APIs that can throw exceptions that cannot be caught in Swift (NSKeyedUnar

Swift-friendly API for a set of powerful Objective C runtime functions.
Swift-friendly API for a set of powerful Objective C runtime functions.

ObjectiveKit ObjectiveKit provides a Swift friendly API for a set of powerful Objective C runtime functions. Usage To use ObjectiveKit: Import Objecti

TraceLog is a highly configurable, flexible, portable, and simple to use debug logging system for Swift and Objective-C applications running on Linux, macOS, iOS, watchOS, and tvOS.

Please star this github repository to stay up to date. TraceLog Introduction TraceLog is a highly configurable, flexible, portable, and simple to use

Color framework for Swift & Objective-C (Gradient colors, hexcode support, colors from images & more).
Color framework for Swift & Objective-C (Gradient colors, hexcode support, colors from images & more).

Swift 3 To use the Swift 3 version, add this to your Podfile (until 2.2 or higher is released): pod 'ChameleonFramework/Swift', :git = 'https://githu

Logging utility for Swift and Objective C
Logging utility for Swift and Objective C

Swell - Swift Logging A logging utility for Swift and Objective C. ##Features Turn on logging during development, turn them off when building for the

Swift Property Wrappers, but in Objective-C. And done horribly.

TOPropertyAccessor is an open source, Objective-C abstract class. Similar to Realm's Cocoa API, it uses the dynamic nature of the Objective-C runtime to access the properties of any of its subclasses, and routes calling them through overridable access points.

Comments
  • Unnamed method parameters should be replaced

    Unnamed method parameters should be replaced

    This looks like a great project, Marcel — I noticed in some of the samples you've posted to the mailing list and elsewhere that some of the methods use unnamed parameters. ie.

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

    This is not great practice, and I feel you'd be better off using something simpler like:

    -(id <MPWDrawingContext>)translate:(CGSize)size;
    

    I don't think a change like this violates what you're trying to achieve here, but it also means that you're not off the beaten path of unreadable method names.

    opened by tonyarnold 3
Owner
Marcel Weiher
Marcel Weiher
The code for my CoreGraphics+CoreAnimation talk, held during the 2012 iOS Game Design Seminar at the Technical University Munich.

PKCoreTechniques ======= Core Techniques is the result of a presentation I held at the Technical University of Munich during the 'iOS Game Design Semi

Philip Kluz 143 Sep 21, 2022
The application is develop in Objective IOS. kids can draw whatever they want and also kids can save the drawing as well as undo erase the drawing.

IOSObjC_KidsBoard The application is develop in Objective IOS. kids can draw whatever they want and also kids can save the drawing as well as undo era

Haresh 0 Oct 28, 2021
Light-weight, operator-overloading-free complements to CoreGraphics!

Graphicz ?? Light-weight, operator-overloading-free complements to CoreGraphics! Even though I shipped it with my app, I still need to invest the time

Kitz 44 Oct 25, 2021
The code for my CoreGraphics+CoreAnimation talk, held during the 2012 iOS Game Design Seminar at the Technical University Munich.

PKCoreTechniques ======= Core Techniques is the result of a presentation I held at the Technical University of Munich during the 'iOS Game Design Semi

Philip Kluz 143 Sep 21, 2022
A Swift library for parsing and drawing SVG images to CoreGraphics contexts.

SwiftDraw A Swift library for parsing and drawing SVG images to CoreGraphics contexts. SwiftDraw can also convert an SVG into Swift source code. Usage

Simon Whitty 119 Jan 3, 2023
JSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.

JSPatch 中文介绍 | 文档 | JSPatch平台 请大家不要自行接入 JSPatch,统一接入 JSPatch 平台,让热修复在一个安全和可控的环境下使用。原因详见 这里 JSPatch bridges Objective-C and JavaScript using the Object

bang 11.4k Jan 1, 2023
💡 A light Swift wrapper around Objective-C Runtime

A light wrapper around Objective-C Runtime. What exactly is lumos? lumos as mentioned is a light wrapper around objective-c runtime functions to allow

Suyash Shekhar 139 Dec 19, 2022
Simple Objective-C wrapper for the keychain that works on Mac and iOS

SAMKeychain SAMKeychain is a simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system Keyc

Sam Soffes 5.4k Dec 29, 2022
A Cocoa / Objective-C wrapper around SQLite

FMDB v2.7 This is an Objective-C wrapper around SQLite. The FMDB Mailing List: https://groups.google.com/group/fmdb Read the SQLite FAQ: https://www.s

August 13.7k Dec 28, 2022
An Objective-C wrapper for RocksDB - A Persistent Key-Value Store for Flash and RAM Storage.

ObjectiveRocks ObjectiveRocks is an Objective-C wrapper of Facebook's RocksDB - A Persistent Key-Value Store for Flash and RAM Storage. Current RocksD

Iskandar Abudiab 56 Nov 5, 2022