swift - 在 Swift 中裁剪肖像照片
问题描述
我试图快速将照片裁剪到特定尺寸。目前,我目前的裁剪器对于水平照片的效果非常好,但是垂直拍摄的照片(人像模式)会被拉伸并且裁剪不当。是否有人对此有解决方案或我可以实施的简单裁剪器?任何建议或帮助都会很棒!我意识到下面有很多代码,所以如果有人有任何更短的解决方案,那就太好了。到目前为止,这是我的代码:
我cropImage()
在结构中的函数是我用来裁剪图像的。
该操作cropPressed()
是我调用按钮操作的地方,并创建了一个 CGRect 以将裁剪格式化为
该函数getCGImageWithCorrectOrientation()
通过将原始图像翻转到正确的方向来校正原始图像(我在裁剪后旋转图像的手机方向有一些问题,所以这解决了它)
最后imageFrame() -> CGRect
,在 imageview 扩展中有助于找到实际的图像帧。
我的整个代码:
import UIKit
struct imageCropHandler {
static let sharedInstance = imageCropHandler()
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.minX * imageViewScale,
y:cropRect.minY * 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
}
}
class cropperViewController: UIViewController, UIScrollViewDelegate,UIImagePickerControllerDelegate, UINavigationControllerDelegate {
@IBOutlet var scrollView: UIScrollView! {
didSet{
scrollView.delegate = self
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 4.0
}
}
@IBOutlet var imageView: UIImageView!
@IBOutlet var cropView: UIView!
@IBOutlet var newPhotoButton: UIButton!
@IBOutlet var cropButton: UIButton!
@IBOutlet var undoButton: UIButton!
@IBOutlet var doneButton: UIButton!
var previousImage:[UIImage] = []
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
showPicker()
imageView.isHidden = true
cropView.isHidden = true
doneButton.isHidden = true
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.setNavigationBarHidden(true, animated: animated)
}
override func viewDidLoad() {
super.viewDidLoad()
cropView.layer.borderWidth = 2.0
cropView.layer.borderColor = UIColor.label.cgColor
let buttons = [newPhotoButton, cropButton, undoButton]
for button in buttons {
button!.layer.masksToBounds = true
button!.layer.cornerRadius = button!.bounds.height/2
button!.titleLabel!.textColor = .systemBlue
button?.layer.borderWidth = 1
button?.layer.borderColor = UIColor.systemBlue.cgColor
}
doneButton.layer.masksToBounds = true
doneButton.layer.cornerRadius = doneButton.bounds.height/2
}
func showPicker(){
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.allowsEditing = false
present(imagePickerController,animated: true, completion: nil)
}
func imagePickerController(_ picker : UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
dismiss(animated: true, completion: nil)
if let originalImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
if originalImage.size.width > originalImage.size.height {
if let lastImage = imageView.image {
previousImage.append(lastImage)
}
imageView.image = originalImage
imageView.isHidden = false
cropView.isHidden = false
doneButton.isHidden = true
print("imageview width: \(imageView.frame.width)")
print("image width: \(imageView.image!.size.width)")
print("imageview height: \(imageView.frame.height)")
} else {
let ac = UIAlertController(title: "Select Different Image", message: "Please select an image that was taken in landscape (horizontal) position!", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(ac, animated: true, completion: nil)
}
}
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
@IBAction func cropPressed(_ sender: Any) {
guard let image = self.imageView.image else {
return
}
let cgImage = self.getCGImageWithCorrectOrientation(image)
let croppableImage = UIImage(cgImage: cgImage, scale: image.scale, orientation: .up)
let cropRect = CGRect(x: cropView.frame.minX - imageView.imageFrame().minX, y: cropView.frame.minY - imageView.imageFrame().minY, width: cropView.frame.width, height: cropView.frame.height)
let croppedImage = imageCropHandler.sharedInstance.cropImage(croppableImage, toRect: cropRect, viewWidth: imageView.frame.width, viewHeight: imageView.frame.height)
if let lastImage = imageView.image {
previousImage.append(lastImage)
}
imageView.image = croppedImage
scrollView.zoomScale = 1
doneButton.isHidden = false
}
func getCGImageWithCorrectOrientation(_ image : UIImage) -> CGImage {
if (image.imageOrientation == UIImage.Orientation.up) {
return image.cgImage!;
}
var transform : CGAffineTransform = CGAffineTransform.identity;
switch (image.imageOrientation) {
case UIImage.Orientation.right, UIImage.Orientation.rightMirrored:
transform = transform.translatedBy(x: 0, y: image.size.height);
transform = transform.rotated(by: CGFloat(-1.0 * .pi/2));
break;
case UIImage.Orientation.left, UIImage.Orientation.leftMirrored:
transform = transform.translatedBy(x: image.size.width, y: 0);
transform = transform.rotated(by: .pi/2);
break;
case UIImage.Orientation.down, UIImage.Orientation.downMirrored:
transform = transform.translatedBy(x: image.size.width, y: image.size.height);
transform = transform.rotated(by: .pi);
break;
default:
break;
}
switch (image.imageOrientation) {
case UIImage.Orientation.rightMirrored, UIImage.Orientation.leftMirrored:
transform = transform.translatedBy(x: image.size.height, y: 0);
transform = transform.scaledBy(x: -1, y: 1);
break;
case UIImage.Orientation.downMirrored, UIImage.Orientation.upMirrored:
transform = transform.translatedBy(x: image.size.width, y: 0);
transform = transform.scaledBy(x: -1, y: 1);
break;
default:
break;
}
let contextWidth : Int;
let contextHeight : Int;
switch (image.imageOrientation) {
case UIImage.Orientation.left, UIImage.Orientation.leftMirrored,
UIImage.Orientation.right, UIImage.Orientation.rightMirrored:
contextWidth = (image.cgImage?.height)!;
contextHeight = (image.cgImage?.width)!;
break;
default:
contextWidth = (image.cgImage?.width)!;
contextHeight = (image.cgImage?.height)!;
break;
}
let context : CGContext = CGContext(data: nil, width: contextWidth, height: contextHeight, bitsPerComponent: image.cgImage!.bitsPerComponent, bytesPerRow: image.cgImage!.bytesPerRow, space: image.cgImage!.colorSpace!, bitmapInfo: image.cgImage!.bitmapInfo.rawValue)!;
context.concatenate(transform);
context.draw(image.cgImage!, in: CGRect(x: 0, y: 0, width: CGFloat(contextWidth), height: CGFloat(contextHeight)));
let cgImage = context.makeImage();
return cgImage!;
}
@IBAction func newPhotoPressed(_ sender: Any) {
let ac = UIAlertController(title: "Choose Event Picture", message: "Please choose a photo from your device!", preferredStyle: .actionSheet)
ac.addAction(UIAlertAction(title: "Choose Image from Library", style: .default, handler: { (action) in
self.showPicker()
}))
ac.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
present(ac, animated: true)
}
@IBAction func undoPressed(_ sender: Any) {
if previousImage.count == 0 {
let ac = UIAlertController(title: "No Previous Actions", message: "There are no actions to undo.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(ac, animated: true, completion: nil)
} else {
imageView.image = previousImage.last
let imageRatio = (imageView.image!.size.height) / (imageView.image!.size.width)
if imageRatio == 9/23 {
doneButton.isHidden = false
} else {
doneButton.isHidden = true
}
let imageIndex = previousImage.count - 1
previousImage.remove(at: imageIndex)
}
}
@IBAction func donePressed(_ sender: Any) {
NotificationCenter.default.post(Notification(name: Notification.Name("Event Image Chosen"), object: nil, userInfo: ["Chosen Image" : imageView.image!]))
}
}
//extending the UIImageView
extension UIImageView {
// MARK: - Methods
func imageFrame() -> CGRect {
let imageViewSize = self.frame.size
let imageSize = self.image!.size
let scaleW = imageViewSize.width / imageSize.width
let scaleH = imageViewSize.height / imageSize.height
let aspect = min(scaleW, scaleH)
var imageRect = CGRect(x: 0, y: 0, width: (imageSize.width * aspect), height: (imageSize.height * aspect))
imageRect.origin.x = (imageViewSize.width - imageRect.size.width) / 2
imageRect.origin.y = (imageViewSize.height - imageRect.size.height) / 2
imageRect.origin.x += self.frame.origin.x
imageRect.origin.y += self.frame.origin.y
return imageRect;
}
}
//makes the cropper unclickable
class CropAreaView: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return false
}
}
解决方案
推荐阅读
- video - ffmpeg -to 标志在处理相同文件和不同时间范围时并不总是正确识别
- json - 将 1 对多 json 转换为 csv
- python-3.x - 如何为不使用熊猫的个人账户创建具有平均每月、每季度提款金额的新列?
- javascript - 如何解决我的网站缺少谷歌分析数据的问题
- ios - 将标签信息存入历史表 | 斯威夫特 | Xcode
- android - 在不同的活动中注入 ViewModelFactory
- ios - segue后如何修复新的视图显示?
- angular - Angular Service 未将值传递给后端 - 标头错误问题
- php - 按总值对多维数组进行排序
- c# - 使用类生成 SQL 插入语句