Home > Software engineering >  Save image from CGContext on background
Save image from CGContext on background

Time:07-15

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).

CodePudding user response:

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:

enter image description here

  • Related