Creating a Custom Context
Instead of getting the current context, which will be one that is drawn directly to the screen, we can create our own and draw things to that.
We'll need to tell the context what type of bitmap it will be drawing and how big it is.
let scale: CGFloat = 2
let bounds = CGRect(x: 0, y: 0, width: 320, height: 320)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGImageAlphaInfo.premultipliedFirst.rawValue
let context = CGContext(
width: Int(bounds.width * scale),
height: Int(bounds.height * scale),
Preparing the Context for Drawing
We also want to scale our drawing so that we can support the pixel density of the screen we are using. For retina, this means we'll draw things twice as large...
// Apply scale
context.scaleBy(x: scale, y: scale)
You'll notice that when drawing with a custom context, the origin is in the lower-left, unlike
UIView which has an origin in the top left. To draw int he same way, we'll have to invert our Y-Axis:
// Invert Y axis
context.translateBy(x: bounds.midX, y: bounds.midY)
context.scaleBy(x: 1, y: -1)
context.translateBy(x: -bounds.midX, y: -bounds.midY)
Then we can draw whatever we want:
// Draw square
context.setFillColor(CGColor(colorSpace: colorSpace, components: [0, 0, 1, 1])!)
context.fill(CGRect(x: 20, y: 20, width: 100, height: 100))
Obtaining an Image from our Drawing
let cgImage = context.makeImage()!
UIImage(cgImage: cgImage, scale: scale, orientation: .up) // or NSImage
Alternatively, (on iOS) we can use an image context and get some of the above setup for free:
UIGraphicsBeginImageContextWithOptions(bounds.size, false, scale)
UIBezierPath(rect: CGRect(x: 20, y: 20, width: 100, height: 100)).fill()
let image = UIGraphicsGetImageFromCurrentImageContext()