2017-03-05 198 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檢查我的編輯。我添加了一個示例,顯示如何根據其大小自動裁剪圖像。 –