Occasionally you will want to do some custom drawing, but not have that presented directly on the screen. Sometimes this is to "bake" the drawing into an image for faster scrolling performance (a single flattened image can be sent to the GPU easily without having to composite a bunch of views together). This is also often used to resize images that are too large for the intended view. This episode covers drawing to a custom context offscreen and obtaining an image out of it.
Links Drawing and Creating Images 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( data: nil, width: Int(bounds.width * scale), height: Int(bounds.height * scale), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo )! 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) Drawing 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) UIColor.blue.setFill() UIBezierPath(rect: CGRect(x: 20, y: 20, width: 100, height: 100)).fill() let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext()