Visual_Novel_iOS/crush/Crush/Src/Components/Photo/AvatarCrop/CircleCropViewController.swift

179 lines
6.5 KiB
Swift

//
// CircleCropViewController.swift
// CIrcleCropView
//
// Created by Bhavesh Chaudhari on 08/05/20.
// Copyright © 2020 Bhavesh. All rights reserved.
//
import UIKit
public class CropViewController: UIViewController {
var image: UIImage
let imageView: UIImageView
let scrollView: UIScrollView
let completion: (UIImage?) -> Void
private var circleView: CircleCropView?
var backButton: StyleButton = {
let button = StyleButton()
button.tertiary(size: .large)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Cancel", for: .normal)
return button
}()
var okButton: StyleButton = {
let button = StyleButton()
button.primary(size: .large)
button.setTitle("Confirm", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
public init(image: UIImage, completion: @escaping (UIImage?) -> Void) {
self.image = image
self.completion = completion
imageView = UIImageView(image: image)
scrollView = UIScrollView()
scrollView.contentInsetAdjustmentBehavior = .never
super.init(nibName: nil, bundle: nil)
}
override public func viewDidLoad() {
super.viewDidLoad()
circleView = CircleCropView(frame: view.bounds)
view.addSubview(scrollView)
view.addSubview(circleView!)
view.addSubview(okButton)
view.addSubview(backButton)
scrollView.addSubview(imageView)
scrollView.contentSize = image.size
scrollView.delegate = self
view.backgroundColor = UIColor(red: 33/255.0, green: 26/255.0, blue: 43/255.0, alpha: 1)
scrollView.frame = view.frame//.inset(by: view.safeAreaInsets)
circleView?.frame = scrollView.frame//.inset(by: view.safeAreaInsets)
backButton.addTarget(self, action: #selector(backClick), for: .touchUpInside)
okButton.addTarget(self, action: #selector(okClick), for: .touchUpInside)
modalPresentationStyle = .fullScreen
addConstraint()
}
func addConstraint() {
backButton.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(24)
make.bottom.equalToSuperview().offset(-16-UIWindow.safeAreaBottom*0.5)
}
okButton.snp.makeConstraints { make in
make.trailing.equalToSuperview().offset(-24)
make.bottom.equalToSuperview().offset(-16-UIWindow.safeAreaBottom*0.5)
}
}
override public var preferredStatusBarStyle: UIStatusBarStyle {
return .default
}
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}
override public func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let scrollFrame = scrollView.frame
let imSize = image.size
guard let hole = circleView?.circleInset, hole.width > 0 else { return }
let verticalRatio = hole.height / imSize.height
let horizontalRatio = hole.width / imSize.width
let maxRatio = max(horizontalRatio, verticalRatio)
if(maxRatio > 1){ //
scrollView.minimumZoomScale = maxRatio
scrollView.maximumZoomScale = maxRatio * 2
scrollView.zoomScale = maxRatio
}else{
scrollView.minimumZoomScale = maxRatio
scrollView.maximumZoomScale = 1
scrollView.zoomScale = scrollView.minimumZoomScale
}
let insetHeight = (scrollFrame.height - hole.height) / 2
let insetWidth = (scrollFrame.width - hole.width) / 2
scrollView.contentInset = UIEdgeInsets(top: insetHeight, left: insetWidth, bottom: insetHeight, right: insetWidth)
okButton.clipsToBounds = true
}
override public func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.setNavigationBarHidden(false, animated: animated)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func backClick(sender: UIButton) {
dismiss(animated: true, completion: nil)
}
@objc func okClick(sender: UIButton) {
cropImage()
}
private func cropImage() {
guard let rect = circleView?.circleInset else { return }
let shift = rect.applying(CGAffineTransform(translationX: scrollView.contentOffset.x, y: scrollView.contentOffset.y))
let scaled = shift.applying(CGAffineTransform(scaleX: 1.0 / scrollView.zoomScale, y: 1.0 / scrollView.zoomScale))
let newImage = image.imageCropped(toRect: scaled)
completion(newImage)
dismiss(animated: true, completion: nil)
}
}
extension CropViewController: UIScrollViewDelegate {
func zoomOut() {
let newScale = scrollView.zoomScale == scrollView.minimumZoomScale ? 0.5 : scrollView.minimumZoomScale
scrollView.setZoomScale(newScale, animated: true)
}
public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
public func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
// need empty implementation for zooming
}
}
extension UIImage {
func imageCropped(toRect rect: CGRect) -> UIImage {
let rad: (Double) -> CGFloat = { deg in
CGFloat(deg / 180.0 * .pi)
}
var rectTransform: CGAffineTransform
switch imageOrientation {
case .left:
let rotation = CGAffineTransform(rotationAngle: rad(90))
rectTransform = rotation.translatedBy(x: 0, y: -size.height)
case .right:
let rotation = CGAffineTransform(rotationAngle: rad(-90))
rectTransform = rotation.translatedBy(x: -size.width, y: 0)
case .down:
let rotation = CGAffineTransform(rotationAngle: rad(-180))
rectTransform = rotation.translatedBy(x: -size.width, y: -size.height)
default:
rectTransform = .identity
}
rectTransform = rectTransform.scaledBy(x: scale, y: scale)
let transformedRect = rect.applying(rectTransform)
let imageRef = cgImage!.cropping(to: transformedRect)!
let result = UIImage(cgImage: imageRef, scale: scale, orientation: imageOrientation)
print("croped Image width and height = \(result.size)")
return result
}
}