It’s been over six months since I first shared my pleasant Objective-C drawing contextpublic, and I’ve been busy! While adapting my code to use MPWDrawingContext and expanding its graphical capabilities (like coding icons), I’ve learned a lot about making code-based drawing more enjoyable.
Blocks
Blocks and graphics contexts are a perfect match, and most updates center around blocks.
Operations like gsave/grestore now have block versions for better nesting reflection in Objective-C:
| |
This is more concise than the standard code, which needs a @try/@finally block for exception safety in the graphics state stack:
| |
Similarly, drawing shadows is easier:
| |
This is cleaner than manual setting and unsetting, harder to mess up when rearranging code, and remains exception-safe:
| |
Stored, Delayed, and Repeated Drawing
You can prepare drawings for later use by sending the -laterWithSize:(NSSize)size content:(DrawingBlock)commands message. Here’s a diamond shape example:
| |
This diamond can be drawn anywhere, at any scale and orientation, using -drawImage::
| |
You can use layerWitSize:content: and bitmapWithSize:content: for CGLayer or CGImage output. However, laterWithSize:content: maximizes quality and automatically uses CGLayer for PDF contexts to minimize PDF file size.
Patterns
As mentioned in earlier, patterns use stored drawing commands (from the previous section) as colors:
| |
For a comparison with plain CG, refer to Apple’s documentation.
Currently, only colored patterns are supported because color spaces aren’t exposed yet. The process for uncolored patterns will be similar.
Polymorphic Object Arguments
Path construction and graphics state messages now accept a single object argument for point values, in addition to separate float arguments (e.g., moveto:(float)x :(float)y).
These messages are:
- moveto:
- lineto:
- translate:
- scale:
The single argument can be an Objective-C array:
| |
Or any custom object responding to count and objectAtIndex:, (float)realAtIndex:, or getReals:(float*)buffer length:(int)maxLen. The scale: message also accepts a single NSNumber for uniform x and y scaling.
Linecap Parameters
Dedicated messages simplify linecap settings:
- setlinecapRound
- setlinecapButt
- setlinecapSquare
While multiple messages might seem unusual, it reduces naming complexity. These scoped names are easier to grasp than global constant strings or enums:
| |
versus:
| |
Future
Message-based design simplifies bridging to other languages, such as interactive drawing environments like Creating a badge (youtube).
Experiments with other outputs are underway. The same badge can be rendered with CALayer objects using the same drawing commands. Future outputs include SVG, HTML5 Canvas, and direct OpenGL textures.
Image processing operations, both standalone and chained, are planned, alongside advanced text layout options.
P.S.: Now available on hacker news.