问题描述
我正在尝试使用自定义视图来裁剪图像。我有两个视图控制器,每个分别是ViewController和ResultViewController。 viewController有一个按钮和一个mageView,另一个有一个imageView。当我在ViewController上进行裁剪时,结果超出了ResultViewController上的透明自定义视图。我不知道我在哪里做错或想念。我已将图像视图的内容模式更改为宽高比填充,宽高比适合,缩放以适合和居中,但结果不是我想要的。任何帮助将不胜感激。
我阅读了官方文档:here
import UIKit
class ViewController: UIViewController {
let resultVC = UIStoryboard.init(name: "Main",bundle: nil).instantiateViewController(withIdentifier: "resultVC") as! ResultViewController
var rectangleView: UIView! = UIView(frame: CGRect(x: 100,y: 200,width: 100,height: 100))
// this is the transparent custom view as a mask.
@IBAction func okayButton(_ sender: Any) {
resultVC.resultimage = cropImage(imageView.image!,toRect: rectangleView.frame,viewWidth: self.view.frame.size.width,viewHeight: self.view.frame.size.height)
print(rectangleView.frame)
present(resultVC,animated: true)
}
@IBOutlet weak var imageView: UIImageView!
func cropImage(_ inputimage: UIImage,toRect cropRect: CGRect,viewWidth: CGFloat,viewHeight: CGFloat) -> UIImage?
{
let imageViewScale = max(inputimage.size.width / viewWidth,inputimage.size.height / viewHeight)
// Scale cropRect to handle images larger than shown-on-screen size
let cropZone = CGRect(x:cropRect.origin.x * imageViewScale,y:cropRect.origin.y * imageViewScale,width:cropRect.size.width * imageViewScale,height:cropRect.size.height * imageViewScale)
// Perform cropping in Core Graphics
guard let cutimageRef: CGImage = inputimage.cgImage?.cropping(to:cropZone)
else {
return nil
}
// Return image to UIImage
let croppedImage: UIImage = UIImage(cgImage: cutimageRef)
return croppedImage
}
override func viewDidLoad() {
super.viewDidLoad()
let imageFile = UIImage(named: "c.png")
// Do any additional setup after loading the view.
imageView.image = imageFile
view.addSubview(rectangleView)
rectangleView.backgroundColor = UIColor.init(white: 1,alpha: 0.5)
}
}
//ResultViewController
import UIKit
class ResultViewController: UIViewController {
var resultimage:UIImage!
@IBOutlet weak var resultimageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
resultimageView.image = resultimage
// Do any additional setup after loading the view.
}
}
裁剪前1
裁剪后2
解决方法
这里重要的一点是,在裁剪之前必须将所有帧的矩形转换为相同的坐标系。
为简便起见,我将选择图像作为基本坐标系,其原点为图像的最左点。请注意,我在这里提到的图像与用于显示图像的imageView不同。
对于裁剪功能,我将使用my library
public func crop(image: UIImage,toRect rect: CGRect) -> UIImage {
let orientation = image.imageOrientation
let scale = image.scale
var targetRect = CGRect()
switch orientation {
case .down:
targetRect.origin.x = (image.size.width - rect.maxX) * scale
targetRect.origin.y = (image.size.height - rect.maxY) * scale
targetRect.size.width = rect.width * scale
targetRect.size.height = rect.height * scale
case .right:
targetRect.origin.x = rect.minY * scale
targetRect.origin.y = (image.size.width - rect.maxX) * scale
targetRect.size.width = rect.height * scale
targetRect.size.height = rect.width * scale
case .left:
targetRect.origin.x = image.size.height - rect.maxY * scale
targetRect.origin.y = rect.minX * scale
targetRect.size.width = rect.height * scale
targetRect.size.height = rect.width * scale
default:
targetRect = CGRect(x: rect.origin.x * scale,y: rect.origin.y * scale,width: rect.width * scale,height: rect.height * scale)
}
if let croppedCGImage = image.cgImage?.cropping(to: targetRect) {
return UIImage(cgImage: croppedCGImage,scale: scale,orientation: orientation)
}
return image
}
要在示例中正确使用上述功能,必须将实现更改为此。请阅读评论以了解想法。
@IBAction func okayButton(_ sender: Any) {
// Get the rectangeView's frame in the imageView's coordinate system
let rectangleViewRectInImageView = rectangleView.convert(rectangleView.bounds,to: imageView)
let imageWHRatio = imageView.image!.size.width / imageView.image!.size.height
let imageViewWHRatio = imageView.bounds.width / imageView.bounds.height
// We are going to calculate the frame of the displayed image content inside the imageView
var imageRectInImageView: CGRect = .zero
if imageWHRatio > imageViewWHRatio {
// White spaces in the top & bottom
imageRectInImageView = CGRect(
x: 0,y: (imageView.bounds.height - imageView.bounds.width / imageWHRatio) / 2,width: imageView.bounds.width,height: imageView.bounds.width / imageWHRatio
)
} else {
// White spaces in the left & right
imageRectInImageView = CGRect(
x: (imageView.bounds.width - imageView.bounds.height * imageWHRatio) / 2,y: 0,width: imageView.bounds.height * imageWHRatio,height: imageView.bounds.height
)
}
// How big the image are being scaled to fit the imageView's bound.
let imageScale = imageView.image!.size.width / imageRectInImageView.width
// The frame of the rectangeView in the displayed image content view's coordinate system
let toRect = CGRect(
x: (rectangleViewRectInImageView.minX - imageRectInImageView.minX) * imageScale,y: (rectangleViewRectInImageView.minY - imageRectInImageView.minY) * imageScale,width: rectangleViewRectInImageView.width * imageScale,height: rectangleViewRectInImageView.height * imageScale)
// Now you have the frame of the rectangleView in proper coordinate system,so you can my method above safely
resultVC.resultImage = crop(image: imageView.image!,toRect: toRect)
print(rectangleView.frame)
present(resultVC,animated: true)
}
请确保您必须选择scaleAspectFill
作为imageView的contentMode
,才能使其正常工作。