PaintCode Review: Dynamic Graphics Made Easy

In this PaintCode review, we’ll show you how PaintCode turns your graphics into Swift and Objective-C code – and answer whether it’s worth the cost. By Bill Morefield.

Leave a rating/review
Save for later
Share

PaintCode is an app that allows you to draw controls, icons, and other graphics elements like you would in programs like Sketch, Photoshop, or Illustrator.

Except PaintCode has one major difference – it generates Objective-C or Swift Core Graphics code from your drawings in real time!

You can then integrate this code into your app, allowing you to dynamically scale your graphics to any size, or programmatically change your graphics based on user input.

We’ve covered PaintCode in several tutorials in the past (one for developers, one for designers), but if you don’t have PaintCode yet you might be wondering – is it worth the money?

Keep reading to find out! :]

Why PaintCode?

Before we begin, it’s important to understand the problem that PaintCode aims to solve.

As an iOS or OS X developer, you usually receive image assets from designers in terms of PNGs. This works great, but has three major drawbacks:

  1. You need multiple image versions. Since PNGs are made at a specific image size, you need to save multiple versions of each file – such as image.png, image@2x.png, and image@3x.png.
  2. They don’t scale. If you want to scale an image to be larger than the original size, it looks pixelated.
  3. They’re pre-generated. Since the images are pre-generated, you can’t customize them easily at runtime.

This is where PaintCode comes in. By generating the graphics at runtime based on Core Graphics code, your graphics can work on any resolution, scaled as much as you would like – and you can customize the graphics programmatically at run-time.

Let’s take a look at how PaintCode works – starting with a tour!

PaintCode Quick Tour

When you open up PaintCode, you get a blank canvas you can draw into using basic shapes such as rectangles, polygons, ovals, text and Bezier curves. Here’s a happy face icon that I drew in about a minute using an Oval and three stroked Bezier paths:

HappyFace

You can easily give a name to each shape you create in the Canvas pane:

CanvasPane

You can also name the colors that you use in the Colors pane:

ColorsPane

By naming your shapes and colors, the code that PaintCode generates is nice and descriptive. For example, here’s the code that was generated for the happy face:

//// Color Declarations
let faceBackground = NSColor(calibratedRed: 0.956, green: 1, blue: 0.204, alpha: 1)
let faceForeground = NSColor(calibratedRed: 0, green: 0, blue: 0, alpha: 1)

//// Face Drawing
let facePath = NSBezierPath(ovalInRect: NSMakeRect(62, 6, 112, 106))
faceBackground.setFill()
facePath.fill()
faceForeground.setStroke()
facePath.lineWidth = 3
facePath.stroke()

//// Smile Drawing
var smilePath = NSBezierPath()
smilePath.moveToPoint(NSMakePoint(78.5, 53.5))
smilePath.curveToPoint(NSMakePoint(160.5, 53.5), controlPoint1: NSMakePoint(79.5, 8.15), controlPoint2: NSMakePoint(160.5, 16.39))
NSColor.blackColor().setStroke()
smilePath.lineWidth = 3
smilePath.stroke()

//// Right Eye Drawing
var rightEyePath = NSBezierPath()
rightEyePath.moveToPoint(NSMakePoint(102.5, 92.5))
rightEyePath.lineToPoint(NSMakePoint(102.5, 59.5))
NSColor.blackColor().setStroke()
rightEyePath.lineWidth = 3
rightEyePath.stroke()

//// Left Eye Drawing
var leftEyePath = NSBezierPath()
leftEyePath.moveToPoint(NSMakePoint(131.5, 92.5))
leftEyePath.lineToPoint(NSMakePoint(131.5, 59.5))
NSColor.blackColor().setStroke()
leftEyePath.lineWidth = 3
leftEyePath.stroke()

How cool is that? Imagine trying to do this on your own via CoreGraphics. It would take ages!

“But wait”, you cry, “I could just design this in Photoshop or Pixelmator, or better yet, Illustrator or Sketch. Why would I switch to PaintCode?!”

Screen Shot 2015-08-24 at 3.47.23 PM

You could, but remember that every time you made a tiny change, like changing the color or size of the happy face, you’d have to re-export your assets. But by generating your code with Core Graphics, you could scale the happy face to any size!

PaintCode and Dynamic Graphics

Although PaintCode’s ability to draw an image at any size at runtime is certainly a benefit, where PaintCode truly shines is its ability to make dynamic graphics.

For example – you could tweak the code above to allow the user to dynamically change the background and foreground color, or even write some code to programmatically generate the size of the happy face’s smile!

DynamicSmile

Let me highlight three features of PaintCode designed to make dynamic graphics easy: the library, variables, and expressions.

The library

PaintCode’s library lets you create, name and manage colors, gradients, and shadows that you can share across all tabs and canvases in your document. Changing the parameter of an item changes it everywhere that item is used.

The library also lets you define colors and gradients based on other items and create colors as highlights, shadows, or transparencies of other colors. Again, changing the base item automatically updates the derived items to match.

The image below shows how changing the base color from red to blue updates the colors derived from the original red:

Derived Colors

Derived Colors

Changing base color to blue changes derived color.

Changing base color to blue changes derived color.

Variables

Variables provide a great deal of flexibility in the generated code; numbers, booleans, points, rectangles, sizes, or colors can all be represented by variables you can attach to a shape’s attributes.

For example, instead of specifying a specific width for a shape, you can create a variable to specify the width when it’s drawn:

DynamicWidth

When you generate code from a drawing, the variables become parameters in the generated methods:

func drawCanvas1(#width: CGFloat) {
    //// Color Declarations
    let faceBackground = UIColor(red: 0.956, green: 1.000, blue: 0.204, alpha: 1.000)
    let faceForeground = UIColor(red: 0.000, green: 0.000, blue: 0.000, alpha: 1.000)

    //// Face Drawing
    var facePath = UIBezierPath(ovalInRect: CGRectMake(62, 8, 112, 106))
    faceBackground.setFill()
    facePath.fill()
    faceForeground.setStroke()
    facePath.lineWidth = width
    facePath.stroke()
    
    //// ...
}

Expressions

Expressions are a special type of variable; they perform simple calculations in an easy-to-use language based on a subset of C and Javascript. You can use expressions for things such as setting the color of a shape based on a variable’s value, or calculating the ending angle for a given starting angle of an arc. The expressions then become local variables in the generated code.

While this feature is certainly quite powerful and incredibly useful, I think that using a different language for expressions feels a bit disconnected from the overall paradigm of Mac and iOS development. There’s a lack of autocomplete on the expression syntax; a minor detail, but hopefully one that will be addressed in the future! :]

Example of expression that sets a different color based on a variable.

Example of expression that sets a different color based on a variable.