Context
The user is sketching with straight lines on a canvas in the current CGContext. The user can draw straight lines, scale(pinch), and translate(pan) the whole drawing. Once the user leaves the drawing scene, the app saves into a data structure all the drawn lines.
Problem
I want to save the drawing into an image (png, jpeg doesn't matter) when the user is on a completely different scene, hitting upload to send the image of the drawing to the server.
So far, I've found a way to export to an image only the current core graphics context. But I can't figure out how to create a context on the background, replicate the drawing from the stored data and then export it to an image, without rendering it on the screen.
I don't want to save the image while the user is on the canvas scene because I need to save the image without any transformations applied (i.e., scale, translate).
You could save it (to docs or temp directory) when the user finishes drawing, then load it to upload / display, etc.
Or, use UIGraphicsImageRenderer
to generate a UIImage
using your saved data structure.
Here's a quick, very simple example.
We create an array of points, then generate an image looping through those points with .addLine
to a bezier path:
class RenderDrawingVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let points: [CGPoint] = [
CGPoint(x: 60, y: 40),
CGPoint(x: 140, y: 40),
CGPoint(x: 140, y: 80),
CGPoint(x: 160, y: 120),
CGPoint(x: 100, y: 160),
CGPoint(x: 80, y: 120),
CGPoint(x: 20, y: 20),
]
let img = renderImage(bkgColor: .systemYellow, lineColor: .systemRed, size: CGSize(width: 200, height: 200), points: points)
// img is now a 200x200 UIImage
// save it, upload it, display it, whatever
}
func renderImage(bkgColor: UIColor, lineColor: UIColor, size: CGSize, points: [CGPoint]) -> UIImage {
let fmt = UIGraphicsImageRendererFormat()
fmt.scale = 1
fmt.opaque = true
let rndr = UIGraphicsImageRenderer(size: size, format: fmt)
let newImg = rndr.image { ctx in
ctx.cgContext.setFillColor(bkgColor.cgColor)
ctx.cgContext.addRect(CGRect(origin: .zero, size: size))
ctx.cgContext.drawPath(using: .fill)
let bez = UIBezierPath()
bez.move(to: points[0])
for i in 1..<points.count {
bez.addLine(to: points[i])
}
ctx.cgContext.setFillColor(UIColor.clear.cgColor)
ctx.cgContext.setStrokeColor(lineColor.cgColor)
ctx.cgContext.setLineWidth(4)
ctx.cgContext.setLineJoin(.round)
ctx.cgContext.setLineCap(.round)
ctx.cgContext.addPath(bez.cgPath)
ctx.cgContext.drawPath(using: .stroke)
}
return newImg
}
}
The resulting image: