How do I draw on an image in Swift? How do I draw on an image in Swift? ios ios

How do I draw on an image in Swift?


All you need to do is create and get an Image Context object and access all its powerful drawing methods. You can learn more about the CGContext object features here.

This function draws a line and a circle on an UIImage and returns the modified image:

Swift 4

func drawOnImage(_ image: UIImage) -> UIImage {          // Create a context of the starting image size and set it as the current one     UIGraphicsBeginImageContext(image.size)          // Draw the starting image in the current context as background            image.draw(at: CGPoint.zero)     // Get the current context     let context = UIGraphicsGetCurrentContext()!     // Draw a red line     context.setLineWidth(2.0)     context.setStrokeColor(UIColor.red.cgColor)     context.move(to: CGPoint(x: 100, y: 100))     context.addLine(to: CGPoint(x: 200, y: 200))     context.strokePath()          // Draw a transparent green Circle     context.setStrokeColor(UIColor.green.cgColor)     context.setAlpha(0.5)     context.setLineWidth(10.0)     context.addEllipse(in: CGRect(x: 100, y: 100, width: 100, height: 100))     context.drawPath(using: .stroke) // or .fillStroke if need filling          // Save the context as a new UIImage     let myImage = UIGraphicsGetImageFromCurrentImageContext()     UIGraphicsEndImageContext()          // Return modified image     return myImage}


It's simple:

  1. Make an image graphics context. (Before iOS 10, you would do this by calling UIGraphicsBeginImageContextWithOptions. In iOS 10 there's another way, UIGraphicsImageRenderer, but you don't have to use it if you don't want to.)

  2. Draw (i.e. copy) the image into the context. (UIImage actually has draw... methods for this very purpose.)

  3. Draw your line into the context. (There are CGContext functions for this.)

  4. Extract the resulting image from the context. (For example, if you used UIGraphicsBeginImageContextWithOptions, you would use UIGraphicsGetImageFromCurrentImageContext.) Then close the context.


Details

Xcode 9.1, Swift 4

Solution

extension UIImage

extension UIImage {    typealias RectCalculationClosure = (_ parentSize: CGSize, _ newImageSize: CGSize)->(CGRect)    func with(image named: String, rectCalculation: RectCalculationClosure) -> UIImage {        return with(image: UIImage(named: named), rectCalculation: rectCalculation)    }    func with(image: UIImage?, rectCalculation: RectCalculationClosure) -> UIImage {        if let image = image {            UIGraphicsBeginImageContext(size)            draw(in: CGRect(origin: .zero, size: size))            image.draw(in: rectCalculation(size, image.size))            let newImage = UIGraphicsGetImageFromCurrentImageContext()            UIGraphicsEndImageContext()            return newImage!        }        return self    }}

extension UIImageView

    extension UIImageView {    enum ImageAddingMode {        case changeOriginalImage        case addSubview    }    func drawOnCurrentImage(anotherImage: UIImage?, mode: ImageAddingMode, rectCalculation: UIImage.RectCalculationClosure) {        guard let image = image else {            return        }        switch mode {        case .changeOriginalImage:            self.image = image.with(image: anotherImage, rectCalculation: rectCalculation)        case .addSubview:            let newImageView = UIImageView(frame: rectCalculation(frame.size, image.size))            newImageView.image = anotherImage            addSubview(newImageView)        }    }}

Images samples

Parent Image:

enter image description here

Child Image:

enter image description here


Usage example 1

func sample1(imageView: UIImageView) {    imageView.contentMode = .scaleAspectFit    imageView.image = UIImage(named: "parent")?.with(image: "child") { parentSize, newImageSize in        print("parentSize = \(parentSize)")        print("newImageSize = \(newImageSize)")        return CGRect(x: 50, y: 50, width: 90, height: 90)    }}

Result 1

enter image description here


Usage example 2

func sample2(imageView: UIImageView) {    imageView.contentMode = .scaleAspectFit    imageView.image = UIImage(named: "parent")    imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .changeOriginalImage) { parentSize, newImageSize in        print("parentSize = \(parentSize)")        print("newImageSize = \(newImageSize)")        let sideLength:CGFloat = 90        let indent:CGFloat = 50        return CGRect(x: parentSize.width-sideLength-indent, y: parentSize.height-sideLength-indent, width: sideLength, height: sideLength)    }}

Result 2

enter image description here


Usage example 3

func sample3(imageView: UIImageView) {    imageView.contentMode = .scaleAspectFill    imageView.clipsToBounds = true    imageView.image = UIImage(named: "parent")    imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .addSubview) { parentSize, newImageSize in        print("parentSize = \(parentSize)")        print("newImageSize = \(newImageSize)")        let sideLength:CGFloat = 90        let indent:CGFloat = 15        return CGRect(x: parentSize.width-sideLength-indent, y: indent, width: sideLength, height: sideLength)    }}

Result 3

enter image description here

Full sample code

Don't forget to add Solution code here

import UIKitclass ViewController: UIViewController {    override func viewDidLoad() {        super.viewDidLoad()        let imageView = UIImageView(frame: UIScreen.main.bounds)        view.addSubview(imageView)        sample1(imageView: imageView)       // sample2(imageView: imageView)       // sample3(imageView: imageView)    }    func sample1(imageView: UIImageView) {        imageView.contentMode = .scaleAspectFit        imageView.image = UIImage(named: "parent")?.with(image: "child") { parentSize, newImageSize in            print("parentSize = \(parentSize)")            print("newImageSize = \(newImageSize)")            return CGRect(x: 50, y: 50, width: 90, height: 90)        }    }    func sample2(imageView: UIImageView) {        imageView.contentMode = .scaleAspectFit        imageView.image = UIImage(named: "parent")        imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .changeOriginalImage) { parentSize, newImageSize in            print("parentSize = \(parentSize)")            print("newImageSize = \(newImageSize)")            let sideLength:CGFloat = 90            let indent:CGFloat = 50            return CGRect(x: parentSize.width-sideLength-indent, y: parentSize.height-sideLength-indent, width: sideLength, height: sideLength)        }    }    func sample3(imageView: UIImageView) {        imageView.contentMode = .scaleAspectFill        imageView.clipsToBounds = true        imageView.image = UIImage(named: "parent")        imageView.drawOnCurrentImage(anotherImage: UIImage(named: "child"), mode: .addSubview) { parentSize, newImageSize in            print("parentSize = \(parentSize)")            print("newImageSize = \(newImageSize)")            let sideLength:CGFloat = 90            let indent:CGFloat = 15            return CGRect(x: parentSize.width-sideLength-indent, y: indent, width: sideLength, height: sideLength)        }    }}