swiftuiimageimage-editing

Create new UIImage from freehand drawn line over UIImage - Swift


This is my first question, so please excuse me if I'm unclear in any way.

I would like to be able to create a new UIImage2 from the contents of a freehand drawn shape over an existing UIImage1 to display over the existing UIImage1.

A visual example: UIImage1 is a photo of a city skyline. The user should be able to draw an outline around a skyscraper and create a new UIImage2 which will be displayed stacked over UIImage1, with the ability to edit (size, color, etc) of UIImage 2.

Drawing lines over a UIImage isn't too difficult, but I've yet to figure out how to capture the content from the UIImage within that freehand drawn shape creating a separate UIImage.

I'd greatly appreciate any help.


Solution

  • If you want to create an image from a masked path, you can:

    For example:

    class ViewController: UIViewController {
    
        @IBOutlet weak var imageView: UIImageView!
        
        private var path: UIBezierPath?
        private var strokeLayer: CAShapeLayer?
        
        @IBAction func didHandlePan(_ gesture: UIPanGestureRecognizer) {
            let location = gesture.location(in: imageView)
            
            switch gesture.state {
            case .began:
                path = UIBezierPath()
                path?.move(to: location)
                strokeLayer = CAShapeLayer()
                imageView.layer.addSublayer(strokeLayer!)
                strokeLayer?.strokeColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1).cgColor
                strokeLayer?.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
                strokeLayer?.lineWidth = 5
                strokeLayer?.path = path?.cgPath
                
            case .changed:
                path?.addLine(to: location)
                strokeLayer?.path = path?.cgPath
                
            case .cancelled, .ended:
                // remove stroke from image view
                
                strokeLayer?.removeFromSuperlayer()
                strokeLayer = nil
    
                // mask the image view
                
                let mask = CAShapeLayer()
                mask.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).cgColor
                mask.strokeColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
                mask.lineWidth = 0
                mask.path = path?.cgPath
                imageView.layer.mask = mask
    
                // get cropped image
    
                let image = imageView?.snapshot
                imageView.layer.mask = nil
    
                // perhaps use that image?
    
                imageView.image = image
    
            default: break
            }
        }        
    }
    

    By the way, to create UIImage from a view (masked or otherwise), you can use:

    extension UIView {
        var snapshot: UIImage {
            UIGraphicsImageRenderer(bounds: bounds).image { _ in
                drawHierarchy(in: bounds, afterScreenUpdates: true)
            }
        }
    }
    

    That yields something like:

    enter image description here