MHCsk MHCsk - 5 months ago 30
iOS Question

Cropping part of UIImage with the screen aspect ratio

I've been struggling with this for quite some time now. I'd like to make image cropper similar to the one included in iOS itself when you select your wallpaper. Basically I want the area that user selects cropped from the image with zoom and aspect ratio of the screen (so the user can use the image as a wallpaper later on). Like this:

https://gfycat.com/TornMaleAlligatorsnappingturtle

I've managed to create the interface with UIScrollView and UIImageView:

import UIKit

class ViewController: UIViewController, UIScrollViewDelegate {

var scrollView: UIScrollView!
var imageView: UIImageView!

var croppedImage: UIImage?

@IBOutlet weak var cropButton: UIButton! {
didSet{
cropButton.backgroundColor = UIColor.gray
}
}


override func viewDidLoad() {

super.viewDidLoad()

let image = UIImage(named: "mountains")!

imageView = UIImageView(image: image)
imageView.frame = CGRect(origin: CGPoint(x: 0, y: 0), size:image.size)
imageView.contentMode = .scaleAspectFill

scrollView = UIScrollView(frame: view.bounds)
scrollView.backgroundColor = UIColor.black
scrollView.contentSize = imageView.bounds.size

scrollView.delegate = self

setZoomScale()
//centerScrollViewContents()

scrollView.addSubview(imageView)
view.addSubview(scrollView)
view.bringSubview(toFront: cropButton)

}

func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}

@IBAction func crop(_ sender: UIButton) {

let rect = CGRect(x: ?, y: ?, width: ?, height: ?)
let croppedCGImage = imageView.image?.cgImage?.cropping(to: rect)
self.croppedImage = UIImage(cgImage: croppedCGImage!)
}

func setZoomScale() {
let imageViewSize = imageView.bounds.size
let scrollViewSize = scrollView.bounds.size
//let widthScale = scrollViewSize.width / imageViewSize.width
let heightScale = scrollViewSize.height / imageViewSize.height

scrollView.minimumZoomScale = heightScale //min(widthScale, heightScale)
scrollView.maximumZoomScale = 3
scrollView.zoomScale = heightScale

print(heightScale)
}
}.


I can zoom and pan around the image no problem. The problem is I don't know how to create the CGRect rectangle that represents the area that is displayed to the user, which is also the area I want to crop from the original image. Any ideas that will put me out of my misery are greatly appreciated!

Answer Source

snapshotImageFromMyView is the output image

self.btn.isHidden = true

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        UIGraphicsBeginImageContextWithOptions(self.YourView.bounds.size, self.YourView.isOpaque, 0.0)
        self.YourView.drawHierarchy(in: self.YourView.bounds, afterScreenUpdates: false)
    let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext()
     UIGraphicsEndImageContext()

}