How to get a screenshot of the View (Drawing View) used for drawing using UIBezeir path - ios

I have a Drawing View which is on a Scroll View. After drawing is completed I need a screenshot of the drawing which I will be uploading to the server.
I am using UIBezeir path to draw on the view.
let path = UIBezierPath()
for i in self.drawView.path{
path.append(i)
}
self.drawView.path is an NSArray with all the bezeir paths of the drawing.
But when I use the bounding box of this path and get max and min values of coordinates and try to capture a screenshot I get this
var rect:CGRect = CGRect(x: path.bounds.minX, y: path.bounds.minY, width: path.bounds.maxX, height: path.bounds.maxY)
I also tried to give the bounds of the path itself
let rect:CGRect = CGRect(x: path.bounds.origin.x - 5, y: path.bounds.origin.y - 5, width: path.bounds.size.width + 5, height: path.bounds.size.height + 5)
Just for reference I tried using this rect and create a view (clear color with border layer) and placed it over the Drawing, it work pretty fine but when I try to capture an image it goes out of bounds
This is the function I am using to capture the screen
func imgScreenShot(bounds:CGRect) -> UIImage{
let rect: CGRect = bounds
self.drawView.isOpaque = false
self.drawView.backgroundColor = UIColor.clear
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
var context: CGContext? = UIGraphicsGetCurrentContext()
if let aContext = context {
self.drawView.layer.render(in: aContext)
}
var capturedImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//let finalImage = scaleImage(image: capturedImage)
return capturedImage!
}
I am also tried getting a UIView with this function
let vw = self.drawView.resizableSnapshotView(from: rect, afterScreenUpdates: true, withCapInsets: UIEdgeInsets.zero)
This gives me a perfect UIView with the drawing in that, but again when I try to convert the UIView to UIImage using the function giving the views bounds, I get a blank image.
Can anyone suggest what I am doing wrong or any other solution for how I can get this, bounds of image starting right exactly at the bounds of the drawing
let vw = self.drawView.resizableSnapshotView(from: rect2, afterScreenUpdates: true, withCapInsets: UIEdgeInsets.zero)
vw?.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
vw?.layer.borderColor = UIColor.red.cgColor
vw?.layer.borderWidth = 1
self.drawView.addSubview(vw!)
let image = vw?.snapshotImage
let imgView = UIImageView(frame: CGRect(x: 250, y: 50, width: 100, height: 100))
imgView.layer.borderColor = UIColor.gray.cgColor
imgView.layer.borderWidth = 1
self.drawView.addSubview(imgView)

Make an extension of UIView and UIImage , so in whole application lifecycle you can use those methods(which one i will be describe at below) for capture the screenshort of any perticular UIView and resize the existing image(if needed).
Here is the extension of UIView :-
extension UIView {
var snapshotImage : UIImage? {
var snapShotImage:UIImage?
UIGraphicsBeginImageContext(self.frame.size)
if let context = UIGraphicsGetCurrentContext() {
self.layer.render(in: context)
if let image = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
snapShotImage = image
}
}
return snapShotImage
}
}
Here is the extension of UIImage :-
extension UIImage {
func resizeImage(newSize:CGSize) -> UIImage? {
var newImage:UIImage?
let horizontalRatio = newSize.width / size.width
let verticalRatio = newSize.height / size.height
let ratio = max(horizontalRatio, verticalRatio)
let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
UIGraphicsBeginImageContext(newSize)
if let _ = UIGraphicsGetCurrentContext() {
draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
if let image = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
newImage = image
}
}
return newImage
}
}
How to use those functions in our desired class ?
if let snapImage = yourUIView.snapshotImage {
///... snapImage is the desired image you want and its dataType is `UIImage`.
///... Now resize the snapImage into desired size by using this one
if let resizableImage = snapImage.resizeImage(newSize: CGSize(width: 150.0, height: 150.0)) {
print(resizableImage)
}
}
here yourUIView means , the one you have taken for drawing some inputs. it can be IBOutlet as well as your UIView (which you have taken programmatically)

Related

Saving a UIImage cropped to a CGPath

I am trying to mask a UIImage and then save the masked image. So far, I have got this working when displayed in a UIImageView preview as follows:
let maskLayer = CAShapeLayer()
let maskPath = shape.cgPath
maskLayer.path = maskPath.resized(to: imageView.frame)
maskLayer.fillRule = .evenOdd
imageView.layer.mask = maskLayer
let picture = UIImage(named: "1")!
imageView.contentMode = .scaleAspectFit
imageView.image = picture
where shape is a UIBezierPath().
The resized function is:
extension CGPath {
func resized(to rect: CGRect) -> CGPath {
let boundingBox = self.boundingBox
let boundingBoxAspectRatio = boundingBox.width / boundingBox.height
let viewAspectRatio = rect.width / rect.height
let scaleFactor = boundingBoxAspectRatio > viewAspectRatio ?
rect.width / boundingBox.width :
rect.height / boundingBox.height
let scaledSize = boundingBox.size.applying(CGAffineTransform(scaleX: scaleFactor, y: scaleFactor))
let centerOffset = CGSize(
width: (rect.width - scaledSize.width) / (scaleFactor * 2),
height: (rect.height - scaledSize.height) / (scaleFactor * 2)
)
var transform = CGAffineTransform.identity
.scaledBy(x: scaleFactor, y: scaleFactor)
.translatedBy(x: -boundingBox.minX + centerOffset.width, y: -boundingBox.minY + centerOffset.height)
return copy(using: &transform)!
}
}
So this works in terms of previewing the outcome I'd like. I'd now like to save this modified UIImage to the user's photo album, in it's original size (so basically generate it again but don't resize the image to fit a UIImageView - keep it as-is and apply the mask over it).
I have tried this, but it just saves the original image - no path/mask applied:
func getMaskedImage(path: CGPath) {
let picture = UIImage(named: "1")!
UIGraphicsBeginImageContext(picture.size)
if let context = UIGraphicsGetCurrentContext() {
let pathNew = path.resized(to: CGRect(x: 0, y: 0, width: picture.size.width, height: picture.size.height))
context.addPath(pathNew)
context.clip()
picture.draw(in: CGRect(x: 0.0, y: 0.0, width: picture.size.width, height: picture.size.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
UIImageWriteToSavedPhotosAlbum(newImage!, nil, nil, nil)
}
}
What am I doing wrong? Thanks.
Don't throw away your layer-based approach! You can still use that when drawing in a graphics context.
Example:
func getMaskedImage(path: CGPath) -> UIImage? {
let picture = UIImage(named: "my_image")!
let imageLayer = CALayer()
imageLayer.frame = CGRect(origin: .zero, size: picture.size)
imageLayer.contents = picture.cgImage
let maskLayer = CAShapeLayer()
let maskPath = path.resized(to: CGRect(origin: .zero, size: picture.size))
maskLayer.path = maskPath
maskLayer.fillRule = .evenOdd
imageLayer.mask = maskLayer
UIGraphicsBeginImageContext(picture.size)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
imageLayer.render(in: context)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
return newImage
}
return nil
}
Note that this doesn't actually resize the image. If you want the image resized, you should get the boundingBox of the resized path. Then do this instead:
// create a context as big as the bounding box
UIGraphicsBeginImageContext(boundingBox.size)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
// move the context to the top left of the path
context.translateBy(x: -boundingBox.origin.x, y: -boundingBox.origin.y)
imageLayer.render(in: context)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
return newImage
}

How to get circle imageView in as titleView of navigation bar iOS

I am trying to get a navigation bar similar to the one in iOS messages app. This is what I have, and it creates a bit of a circle shape but gets cut off. If you were to recreate the centered image from Messages how would you?
let imageView = UIImageView(image: UIImage(named: "test-image"))
imageView.contentMode = .scaleAspectFit
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
imageView.frame = titleView.bounds
imageView.layer.masksToBounds = true
imageView.layer.cornerRadius = imageView.frame.height / 2
titleView.addSubview(imageView)
self.navigationItem.titleView = titleView
The current outcome with this snippet:
The desired outcome:
Tested solutions In dark mode:
Please excuse my eggs ;) It's my favorite test pic
Set image view content mode .scaleAspectFill
imageView.contentMode = .scaleAspectFill
The following is what I have done.
I use two functions to work with an image. The makeCutout function creates a square cutout based on the height of an image of your selection. The position of the cutout is placed at the center of the source image. (See let cutoutRect = ...) The second one, the makeCircularImage function, makes the cutout image circular. Note that I'm assuming the original image is horizontally-long, which means that the diameter of the cutout will be the height of the image.
import UIKit
class ViewController: UIViewController {
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
if let image = UIImage(named: "jenniferGarner.jpg") {
let imageWidth = image.size.width
let imageHeight = image.size.height
let cutoutRect = CGRect(origin: CGPoint(x: (imageWidth - imageHeight) / 2.0, y: 0.0), size: CGSize(width: imageHeight, height: imageHeight))
if let cutoutImage = makeCutout(image: image, rect: cutoutRect) {
/* making it a circular image */
if let circleImage = makeCircularImage(sourceImage: cutoutImage, diameter: cutoutImage.size.height) {
testImageView.isHidden = true
let imageView = UIImageView(image: circleImage)
imageView.contentMode = .scaleAspectFit
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
//titleView.backgroundColor = UIColor.green
imageView.frame = titleView.bounds
imageView.layer.masksToBounds = true
imageView.layer.cornerRadius = imageView.frame.height / 2
titleView.addSubview(imageView)
self.navigationItem.titleView = titleView
}
}
}
}
// MARK: - Making a cutout image
func makeCutout(image: UIImage, rect: CGRect) -> UIImage? {
if let cgImage = image.cgImage {
let contextImage: UIImage = UIImage(cgImage: cgImage)
// Create bitmap image from context using the rect
var croppedContextImage: CGImage? = nil
if let contextImage = contextImage.cgImage {
if let croppedImage = contextImage.cropping(to: rect) {
croppedContextImage = croppedImage
}
}
// Create a new image based on the imageRef and rotate back to the original orientation
if let croppedImage: CGImage = croppedContextImage {
let image: UIImage = UIImage(cgImage: croppedImage, scale: image.scale, orientation: image.imageOrientation)
return image
}
}
return nil
}
func makeCircularImage(sourceImage: UIImage, diameter: CGFloat) -> UIImage? {
let imageView = UIImageView(image: sourceImage)
let layer = imageView.layer
layer.masksToBounds = true
layer.cornerRadius = diameter / 2.0
UIGraphicsBeginImageContext(imageView.bounds.size)
layer.render(in: UIGraphicsGetCurrentContext()!)
if let finalImage = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
return finalImage
}
return nil
}
}
I have Jeniffer Garner as a guest as shown below. The source image size is 480 px X 180 px.
The following is the final work with an iPhone simulator with the dark mode.

How to save a layered image using a extension function

I am using a extension function to save a uiview as a uiimage. The code works to save the uiimage. However what I am trying to do is save a transparent image over the image being saved to the photo gallery. So I am trying to save a layered image using a extension function. Right now only the uiivew is being save and the 2nd layer is not being saved.
class ViewController: UIViewController,UINavigationControllerDelegate {
#IBAction func press(_ sender: Any) {
let jake = drawingView.takeSnapshotOfView(view: drawingView)
guard let selectedImage = jake else {
print("Image not found!")
return
}
UIImageWriteToSavedPhotosAlbum(selectedImage, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}}
func takeSnapshotOfView(view:UIView) -> UIImage? {
UIGraphicsBeginImageContext(CGSize(width: view.frame.size.width, height: view.frame.size.height))
view.drawHierarchy(in: CGRect(x: 0.0, y: 0.0, width: view.frame.size.width, height: view.frame.size.height), afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let star:UIImage = UIImage(named: "e.png")!
let newSize = CGSize(width: star.size.width, height: star.size.height )
UIGraphicsBeginImageContextWithOptions(newSize, false, star.scale)
star.draw(in: CGRect(x: newSize.width/12,
y: newSize.height/8,
width: newSize.width/1.2,
height: newSize.height/1.2),
blendMode:CGBlendMode.normal, alpha:1)
UIGraphicsEndImageContext()
return image
}
Here is a UIView extension that takes in CGRect and UIImage, and alternitavely you can also supply it another CGRect or CGSize to make it more dynamic for the watermark placement/size
extension UIView {
/// Takes a screenshot of a UIView, with an option to clip to view bounds and place a waterwark image
/// - Parameter rect: offset and size of the screenshot to take
/// - Parameter clipToBounds: Bool to check where self.bounds and rect intersect and adjust size so there is no empty space
/// - Parameter watermark: UIImage of the watermark to place on top
func screenshot(for rect: CGRect, clipToBounds: Bool = true, with watermark: UIImage? = nil) -> UIImage {
var imageRect = rect
if clipToBounds {
imageRect = bounds.intersection(rect)
}
return UIGraphicsImageRenderer(bounds: imageRect).image { _ in
drawHierarchy(in: CGRect(origin: .zero, size: bounds.size), afterScreenUpdates: true)
watermark?.draw(in: CGRect(origin: imageRect.origin, size: CGSize(width: 32, height: 32))) // update origin to place watermark where you want, with this update it will place it in top left or screenshot.
}
}
}
You can call it like so:
let image = self.view.screenshot(for: CGRect(x: 0, y: 0, width: 200, height: 200), with: UIImage(named: "star"))
This will work for all subviews of the view that calls screenshot(...)
For a anyone using the above extension, I added additional info in this answer

How to merge two UIImages while keeping the aspect ratio and size?

The code is added to Github to let you understand the real problem.
This is the hierarchy:
-- ViewController.View P [width: 375, height: 667]
---- UIImageView A [width: 375, height: 667] Name: imgBackground
[A is holding an image of size(1287,1662)]
---- UIImageView B [width: 100, height: 100] Name: imgForeground
[B is holding an image of size(2400,982)]
I am trying to merge A with B but the result is stretched.
This is the merge code:
func mixImagesWith(frontImage:UIImage?, backgroundImage: UIImage?, atPoint point:CGPoint, ofSize signatureSize:CGSize) -> UIImage {
let size = self.imgBackground.frame.size
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)
backgroundImage?.draw(in: CGRect.init(x: 0, y: 0, width: size.width, height: size.height))
frontImage?.draw(in: CGRect.init(x: point.x, y: point.y, width: signatureSize.width, height: signatureSize.height))
let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
Note:
.contentMode = .scaleAspectFit
Code works but the result is stretched.
See this line in code, let size = self.imgBackground.frame.size – I need to change this to fix the problem. Find the origin of subview with respect to UIImage size
Here's the screenshot to understand the problem:
What should I do to get the proper output of merge function?
You have two bugs in your code:
You should also calculate aspect for document image to fit it into UIImageView. In mergeImages() replace:
img.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
with:
img.draw(in: getAspectFitFrame(sizeImgView: size, sizeImage: img.size))
When calculating aspect you center image horizontally/vertically if its width/height less then UIImageView width/height. But instead of comparing newWidth and newHeight you should compare factors:
if hfactor > vfactor {
y = (sizeImgView.height - newHeight) / 2
} else {
x = (sizeImgView.width - newWidth) / 2
}
Try bellow code it works for me, hope it works for you too,
func addWaterMarkToImage(img:UIImage, sizeWaterMark:CGRect, waterMarkImage:UIImage, completion : ((UIImage)->())?){
handler = completion
let img2:UIImage = waterMarkImage
let rect = CGRect(x: 0, y: 0, width: img.size.width, height: img.size.height)
UIGraphicsBeginImageContext(img.size)
img.draw(in: rect)
let frameAspect:CGRect = getAspectFitFrame(sizeImgView: sizeWaterMark.size, sizeImage: waterMarkImage.size)
let frameOrig:CGRect = CGRect(x: sizeWaterMark.origin.x+frameAspect.origin.x, y: sizeWaterMark.origin.y+frameAspect.origin.y, width: frameAspect.size.width, height: frameAspect.size.height)
img2.draw(in: frameOrig, blendMode: .normal, alpha: 1)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if handler != nil {
handler!(result!)
}
}
//MARK - Get Aspect Fit frame of UIImage
func getAspectFitFrame(sizeImgView:CGSize, sizeImage:CGSize) -> CGRect{
let imageSize:CGSize = sizeImage
let viewSize:CGSize = sizeImgView
let hfactor : CGFloat = imageSize.width/viewSize.width
let vfactor : CGFloat = imageSize.height/viewSize.height
let factor : CGFloat = max(hfactor, vfactor)
// Divide the size by the greater of the vertical or horizontal shrinkage factor
let newWidth : CGFloat = imageSize.width / factor
let newHeight : CGFloat = imageSize.height / factor
var x:CGFloat = 0.0
var y:CGFloat = 0.0
if newWidth > newHeight{
y = (sizeImgView.height - newHeight)/2
}
if newHeight > newWidth{
x = (sizeImgView.width - newWidth)/2
}
let newRect:CGRect = CGRect(x: x, y: y, width: newWidth, height: newHeight)
return newRect
}

How do I draw on an image in Swift?

I need to be able to programmatically draw on an image, and save that image for later use. Say, draw a line on specific x and y coordinates on the image, save the image, and display it onto a simple view controller. How would I go about doing this in Swift? (Preferably Swift 2, I am still in development and haven't updated my mac to Sierra)
Update: Possibly something to do with converting a UIImage to a CGLayer, drawing on it, and then converting it back to a UIImage.
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:
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.)
Draw (i.e. copy) the image into the context. (UIImage actually has draw... methods for this very purpose.)
Draw your line into the context. (There are CGContext functions for this.)
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:
Child Image:
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
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
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
Full sample code
Don't forget to add Solution code here
import UIKit
class 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)
}
}
}
Since iOS 10 you can use the UIGraphicImageRenderer, which has a better syntax and has some great features!
Swift 4
let renderer = UIGraphicsImageRenderer(size: view.bounds.size)
let image = renderer.image { context in
// draw your image into your view
context.cgContext.draw(UIImage(named: "myImage")!.cgImage!, in: view.frame)
// draw even more...
context.cgContext.setFillColor(UIColor.red.cgColor)
context.cgContext.setStrokeColor(UIColor.black.cgColor)
context.cgContext.setLineWidth(10)
context.cgContext.addRect(view.frame)
context.cgContext.drawPath(using: .fillStroke)
}
Updated Answer: Once you get the From and To coordinates, here is how to draw a line in a UIImage with those coordinates. From and To coordinates are in image pixels.
func drawLineOnImage(size: CGSize, image: UIImage, from: CGPoint, to: CGPoint) -> UIImage {
// begin a graphics context of sufficient size
UIGraphicsBeginImageContext(size)
// draw original image into the context
image.drawAtPoint(CGPointZero)
// get the context for CoreGraphics
let context = UIGraphicsGetCurrentContext()
// set stroking width and color of the context
CGContextSetLineWidth(context, 1.0)
CGContextSetStrokeColorWithColor(context, UIColor.blueColor().CGColor)
// set stroking from & to coordinates of the context
CGContextMoveToPoint(context, from.x, from.y)
CGContextAddLineToPoint(context, to.x, to.y)
// apply the stroke to the context
CGContextStrokePath(context)
// get the image from the graphics context
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
// end the graphics context
UIGraphicsEndImageContext()
return resultImage }

Resources