2017-03-05 130 views
0

我有一个类设置,允许用户从他们的库中添加图像,裁剪并保存它。UIImage在裁剪后旋转

设置代码,以便如果检索到的图像是纵向的,则纵向出现纵向边框,以便在裁切之前对齐所有图像,并且如果横向,则出现园景边框。

如果选择的图像是规则形状的图像,则一切正常。但是,如果检索到的图像是纵向而不是正常比例(意思是接近正方形而实际上不是正方形),则图像在裁剪后会旋转。似乎认为该系统将其视为景观图像。

下面是裁剪之前和之后的示例。即使我放大,使图像覆盖整个屏幕,它旋转图像:

enter image description here

enter image description here

import Foundation 
import UIKit 

class SelectImageViewController: UIViewController, UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIScrollViewDelegate{ 


    @IBOutlet weak var imageView: UIImageView! 

    @IBOutlet weak var imageConstraintTop: NSLayoutConstraint! 
    @IBOutlet weak var imageConstraintRight: NSLayoutConstraint! 
    @IBOutlet weak var imageConstraintLeft: NSLayoutConstraint! 
    @IBOutlet weak var imageConstraintBottom: NSLayoutConstraint! 

    var lastZoomScale: CGFloat = -1 
    var imageName: String = "" 
    var userPhotoUUID = UUID().uuidString 
    let userDefault = UserDefaults.standard 
    var userDatabase: UserDatabase = UserDatabase() 
    let picker = UIImagePickerController() 


    @IBOutlet var scrollView: UIScrollView!{ 
     didSet{ 
      scrollView.delegate = self 
      scrollView.minimumZoomScale = 1.0 
      scrollView.maximumZoomScale = 5.0 
     } 
    } 

    @IBOutlet weak var ratioSelector: UISegmentedControl! 

    @IBOutlet var cropAreaViewL: CropAreaViewL! 

    var cropAreaL:CGRect{ 
     get{ 
      let factor = imageView.image!.size.width/view.frame.width 
      let scale = 1/scrollView.zoomScale 
      let imageFrame = imageView.imageFrame() 
      let x = (scrollView.contentOffset.x + cropAreaViewL.frame.origin.x - imageFrame.origin.x) * scale * factor 
      let y = (scrollView.contentOffset.y + cropAreaViewL.frame.origin.y - imageFrame.origin.y) * scale * factor 
      let width = cropAreaViewL.frame.size.width * scale * factor 
      let height = cropAreaViewL.frame.size.height * scale * factor 
      return CGRect(x: x, y: y, width: width, height: height) 
     } 
    } 

    @IBOutlet var cropAreaViewP: CropAreaViewP! 

    var cropAreaP:CGRect{ 
     get{ 
      let factor = imageView.image!.size.height/view.frame.height 
      let scale = 1/scrollView.zoomScale 
      let imageFrame = imageView.imageFrame() 
      let x = (scrollView.contentOffset.x + cropAreaViewP.frame.origin.x - imageFrame.origin.x) * scale * factor 
      let y = (scrollView.contentOffset.y + cropAreaViewP.frame.origin.y - imageFrame.origin.y) * scale * factor 
      let width = cropAreaViewP.frame.size.width * scale * factor 
      let height = cropAreaViewP.frame.size.height * scale * factor 
      return CGRect(x: x, y: y, width: width, height: height) 
     } 
    } 


    fileprivate var speciePhotos: Array<SpeciePhotoModel> = [SpeciePhotoModel]() 


    func randomNumber(range: ClosedRange<Int> = 30000...99998) -> Int { 
     let min = range.lowerBound 
     let max = range.upperBound 
     return Int(arc4random_uniform(UInt32(1 + max - min))) + min 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     navigationItem.rightBarButtonItem = UIBarButtonItem(title: "+", style: .plain, target: self, action: #selector(SelectImageViewController.add(_:))) 

     let id = randomNumber() 
     userDefault.set(id, forKey: "photoID") 

     self.cropAreaViewP.isHidden = true 
     self.cropAreaViewL.isHidden = true 
     self.cropAreaViewL.layer.borderColor = (UIColor.red).cgColor 
     self.cropAreaViewL.layer.borderWidth = 1.0 
     self.cropAreaViewP.layer.borderColor = (UIColor.red).cgColor 
     self.cropAreaViewP.layer.borderWidth = 1.0 
     self.add.layer.cornerRadius = 6.0 
     self.ratioSelector.layer.cornerRadius = 6.0 
     self.tabBarController?.tabBar.isHidden = true 
     self.add.isHidden = true 
     self.ratioSelector.isHidden = true 

     updateZoom() 

    } 


    func updateConstraints() { 
     if let image = imageView.image { 
      let imageWidth = image.size.width 
      let imageHeight = image.size.height 

      let viewWidth = scrollView.bounds.size.width 
      let viewHeight = scrollView.bounds.size.height 

      // center image if it is smaller than the scroll view 
      var hPadding = (viewWidth - scrollView.zoomScale * imageWidth)/2 
      if hPadding < 0 { hPadding = 0 } 

      var vPadding = (viewHeight - scrollView.zoomScale * imageHeight)/2 
      if vPadding < 0 { vPadding = 0 } 

      imageConstraintLeft.constant = hPadding 
      imageConstraintRight.constant = hPadding 

      imageConstraintTop.constant = vPadding 
      imageConstraintBottom.constant = vPadding 

      view.layoutIfNeeded() 
     } 
    } 

    fileprivate func updateZoom() { 
     if let image = imageView.image { 
      var minZoom = min(scrollView.bounds.size.width/image.size.width, 
           scrollView.bounds.size.height/image.size.height) 

      if minZoom > 1 { minZoom = 1 } 

      scrollView.minimumZoomScale = 0.3 * minZoom 

      // Force scrollViewDidZoom fire if zoom did not change 
      if minZoom == lastZoomScale { minZoom += 0.000001 } 

      scrollView.zoomScale = minZoom 
      lastZoomScale = minZoom 
     } 
    } 


    @IBAction func ratioSelector(_ sender: AnyObject) { 

     switch ratioSelector.selectedSegmentIndex 
     { 
     case 0:// Landscape 

      self.cropAreaViewP.isHidden = true 
      self.cropAreaViewL.isHidden = false 

     case 1: // Portrait 

      self.cropAreaViewL.isHidden = true 
      self.cropAreaViewP.isHidden = false 

     default: 
      break; 
     } 
    } 


    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { 
     dismiss(animated: true, completion: nil) 
    } 

    @IBOutlet weak var add : UIButton! 


    @IBAction func add(_ sender: UIButton) { 

     imageView.image = nil 

     let picker = UIImagePickerController() 
     picker.delegate = self 
     picker.sourceType = .photoLibrary 
     picker.allowsEditing = false 
     self.present(picker, animated: true, completion: nil) 

     self.ratioSelector.isHidden = false 
     self.add.isHidden = false 

     navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Crop", style: .plain, target: self, action: #selector(SelectImageViewController.crop(_:))) 

    } 

    @IBAction func change(_ sender: UIButton) { 

     imageView.image = nil 

     let picker = UIImagePickerController() 
     picker.delegate = self 
     picker.sourceType = .photoLibrary 
     picker.allowsEditing = false 
     self.present(picker, animated: true, completion: nil) 

     navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Crop", style: .plain, target: self, action: #selector(SelectImageViewController.crop(_:))) 

    } 


    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { 

     let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage 

     if chosenImage.size.height > chosenImage.size.width 
     { 
      self.cropAreaViewL.isHidden = true 
      self.cropAreaViewP.isHidden = false 
      self.ratioSelector.selectedSegmentIndex = 1 
      imageView.image = chosenImage 
     } 
     else 
     { 
      self.cropAreaViewP.isHidden = true 
      self.cropAreaViewL.isHidden = false 
      self.ratioSelector.selectedSegmentIndex = 0 
      imageView.image = chosenImage 
     } 
     self.dismiss(animated: true, completion: nil) 
    } 


    @IBAction func crop(_ sender: UIButton) { 

     if cropAreaViewP.isHidden == true { 
      self.cropAreaViewL.layer.borderColor = (UIColor.clear).cgColor 
      let croppedCGImage = imageView.image?.cgImage?.cropping(to: cropAreaL) 
      let croppedImage = UIImage(cgImage: croppedCGImage!) 
      imageView.image = croppedImage 
      scrollView.zoomScale = 1 
     } else { 
      self.cropAreaViewP.layer.borderColor = (UIColor.clear).cgColor 
      let croppedCGImage = imageView.image?.cgImage?.cropping(to: cropAreaP) 
      let croppedImage = UIImage(cgImage: croppedCGImage!) 
      imageView.image = croppedImage 
      scrollView.zoomScale = 1 
     } 

     navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(SelectImageViewController.saveButtonAction(_:))) 


    } 
} 

extension UIImageView{ 
    func imageFrame()->CGRect{ 
     let imageViewSize = self.frame.size 
     guard let imageSize = self.image?.size else{return CGRect.zero} 
     let imageRatio = imageSize.width/imageSize.height 
     let imageViewRatio = imageViewSize.width/imageViewSize.height 

     if imageRatio < imageViewRatio { // Portrait 
      let scaleFactor = imageViewSize.height/imageSize.height 
      let width = imageSize.width * scaleFactor 
      let topLeftX = (imageViewSize.width - width) * 0.5 
      return CGRect(x: topLeftX, y: 0, width: width, height: imageViewSize.height) 
     }else{ // Landscape 
      let scaleFactor = imageViewSize.width/imageSize.width 
      let height = imageSize.height * scaleFactor 
      let topLeftY = (imageViewSize.height - height) * 0.5 
      return CGRect(x: 0, y: topLeftY, width: imageViewSize.width, height: height) 
     } 
    } 
} 


class CropAreaViewL: UIView { 

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 
     return false 
    } 
} 

class CropAreaViewP: UIView { 

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { 
     return false 
    } 

} 

任何帮助将是巨大的。

+0

不相关的问题可以解决可能重绘图像。你可以使用max方法来确保你没有得到一个小于零的值'let vPadding = max((viewHeight - scrollView.zoomScale * imageHeight)/ 2,0)' –

+0

感谢Leo,你能给我一个例子吗?重绘?此外,我即将登机,并会尽快尝试vPadding的想法 –

+1

Leo,vPadding解决了我的问题。请把它作为答案,我会接受它。 –

回答

1

您可以使用最多的方法,以确保你不会低于零值:

let vPadding = max((viewHeight - scrollView.zoomScale * imageHeight)/2, 0) 

如果你需要让你的形象平方你可以做如下:

extension UIImage { 

    var isPortrait: Bool { return size.height > size.width } 
    var isLandscape: Bool { return size.width > size.height } 
    var breadth:  CGFloat { return min(size.width, size.height) } 
    var breadthSize: CGSize { return CGSize(width: breadth, height: breadth) } 
    var squared: UIImage? { 
     guard let cgImage = cgImage?.cropping(to: 
      CGRect(origin: CGPoint(x: isLandscape ? floor((size.width-size.height)/2) : 0, y: isPortrait ? floor((size.height-size.width)/2) : 0), 
        size: breadthSize)) else { return nil } 
     return UIImage(cgImage: cgImage) 
    } 
} 

要修复方向问题,您需要重新绘制图像,您可以使用此answer的flatten属性。


游乐场:

let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"https://i.stack.imgur.com/Xs4RX.jpg")!))! 
if let squared = profilePicture.squared { 
    squared 

} 
+0

狮子座,看起来我说得太快。它将它固定在模拟器上,但现在我正在iPhone上测试它,它仍然在旋转。对不起,但我不明白上面的重绘评论。我检查了这些网站,看起来似乎不相关,但这可能是由于我的经验不足 –

+0

您需要以所需的大小开始一个新的上下文并在那里绘制裁剪后的图像。你可以创建一个示例项目,以便我可以将重绘部分添加到您的?你有Gist(Github)吗? –

+0

@DavidSanford检查我的编辑。我添加了一个示例,显示如何根据其大小自动裁剪图像。 –