如何在不拉伸的情况下快速裁剪宽幅图像

问题描述 投票:1回答:1

我在裁剪照片时遇到麻烦,照片的大小必须与宽幅格式相同。例如,我使用iPad前置摄像头拍照,其分辨率为960w,1280h,我需要将其裁剪为875w,570h。我尝试了here中的某些方法,但是它们都拉伸了图像或没有达到我想要的大小。

这是我尝试的第一种方法:

func cropToBounds(image: UIImage, width: Double, height: Double) -> UIImage {

    let cgimage = image.cgImage!
    let contextImage: UIImage = UIImage(cgImage: cgimage)
    guard let newCgImage = contextImage.cgImage else { return contextImage }
    let contextSize: CGSize = contextImage.size
    var posX: CGFloat = 0.0
    var posY: CGFloat = 0.0
    let cropAspect: CGFloat = CGFloat(width / height)

    var cropWidth: CGFloat = CGFloat(width)
    var cropHeight: CGFloat = CGFloat(height)

    if width > height { //Landscape
        cropWidth = contextSize.width
        cropHeight = contextSize.width / cropAspect
        posY = (contextSize.height - cropHeight) / 2
    } else if width < height { //Portrait
        cropHeight = contextSize.height
        cropWidth = contextSize.height * cropAspect
        posX = (contextSize.width - cropWidth) / 2
    } else { //Square
        if contextSize.width >= contextSize.height { //Square on landscape (or square)
            cropHeight = contextSize.height
            cropWidth = contextSize.height * cropAspect
            posX = (contextSize.width - cropWidth) / 2
        }else{ //Square on portrait
            cropWidth = contextSize.width
            cropHeight = contextSize.width / cropAspect
            posY = (contextSize.height - cropHeight) / 2
        }
    }

    let rect: CGRect = CGRect(x: posX, y: posY, width: cropWidth, height: cropHeight)

    // Create bitmap image from context using the rect
    guard let imageRef: CGImage = newCgImage.cropping(to: rect) else { return contextImage}

    // Create a new image based on the imageRef and rotate back to the original orientation
    let cropped: UIImage = UIImage(cgImage: imageRef, scale: image.scale, orientation: image.imageOrientation)

    print(image.scale)
    UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, 0.0)
    cropped.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
    let resized = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()


    return resized ?? image
}

这总是拉伸图像。

我曾考虑过尝试缩小自己想要的尺寸,所以我尝试了:

func cropImage(image: UIImage, width: Double, height: Double)->UIImage{

    let cgimage = image.cgImage!
    let contextImage: UIImage = UIImage(cgImage: cgimage)
    let contextSize: CGSize = contextImage.size
    var posX: CGFloat = 0.0
    var posY: CGFloat = 0.0
    var recWidth : CGFloat = CGFloat(width)
    var recHeight : CGFloat = CGFloat(height)

    if width > height { //Landscape
         posY = (contextSize.height - recHeight) / 2
    }
    else { //Square

        posX = (contextSize.width - recWidth) / 2

    }

    let rect: CGRect = CGRect(x: posX, y: posY, width: recWidth, height: recHeight)
    let imageRef:CGImage = cgimage.cropping(to: rect)!
    print(imageRef.width)
    print(imageRef.height)
    let croppedimage:UIImage = UIImage(cgImage: imageRef, scale: image.scale, orientation: image.imageOrientation)
    print(croppedimage.size)



    return croppedimage
}

但是这导致图像与我想要的图像相反,即570w,875h。因此,我考虑过反转值,但是如果这样做,我将获得605w,570h。也许问题出在我如何获得图像的X和Y位置?

编辑

这是在Leo Dabus的帮助下,我现在正在做的事情:

extension UIImage {
  func cropped(to size: CGSize) -> UIImage? {
    guard let cgImage = cgImage?
        .cropping(to: .init(origin: .init(x: (self.size.width-size.width)/2,
                                          y: (self.size.height-size.height)/2),
                            size: size)) else { return nil }
    let format = imageRendererFormat
    return UIGraphicsImageRenderer(size: size, format: format).image {
        _ in
        UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
            .draw(in: .init(origin: .zero, size: size))
    }

 }
}

这就是我所说的:

let foto = UIImage(data: imageData)!
let size = CGSize(width: 875.0, height: 570.0)
let cropedPhoto = foto.cropped(to: size)

imageData来自前置摄像头的捕获。

这是我的捕获代码:

@objc func takePhoto(_ sender: Any?) {
    let videoOrientation = AVCaptureVideoOrientation.portrait
    stillImageOutput!.connection(with: .video)?.videoOrientation = videoOrientation

    let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
    let gesture = previewView.gestureRecognizers
    previewView.removeGestureRecognizer(gesture![0])
}

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    guard let imageData = photo.fileDataRepresentation()
        else { return }                        
}
ios swift image crop swift4.2
1个回答
0
投票

您只需要获取原始尺寸宽度减去目标尺寸宽度,然后除以2并设置裁剪原点x值即可。接下来,对高度进行相同的操作并设置y位置。然后只需使用裁剪的cgImage初始化一个新的UIImage:

extension UIImage {
    func cropped(to size: CGSize) -> UIImage? {
        guard let cgImage = cgImage?
            .cropping(to: .init(origin: .init(x: (self.size.width-size.width)/2,
                                              y: (self.size.height-size.height)/2),
                                size: size)) else { return nil }
        return UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
    }
}

let imageURL = URL(string: "https://www.comendochucruteesalsicha.com.br/wp-content/uploads/2016/09/IMG_5356-960x1280.jpg")!
let image = UIImage(data: try! Data(contentsOf: imageURL))!

let squared = image.cropped(to: .init(width: 875, height: 570))

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.