使用Swift裁剪图像并将其放在中心位置

3hvapo4f  于 2022-09-19  发布在  Swift
关注(0)|答案(15)|浏览(221)

在SWIFT编程中,如何裁剪图像并将其放在中心位置?

这就是我到目前为止得到的..。我已经成功地裁剪了图像,但我想在之后把它放在中间

ImgView.image = OrigImage
var masklayer = CAShapeLayer()
masklayer.frame = ImgView.frame
masklayer.path = path.CGPath
masklayer.fillColor = UIColor.whiteColor().CGColor
masklayer.backgroundColor = UIColor.clearColor().CGColor

ImgView.layer.mask = masklayer

UIGraphicsBeginImageContext(ImgView.bounds.size);
ImgView.layer.renderInContext(UIGraphicsGetCurrentContext())
var image = UIGraphicsGetImageFromCurrentImageContext()
ImgView.image = image
UIGraphicsEndImageContext();

更新:

let rect: CGRect = CGRectMake(path.bounds.minX, path.bounds.minY, path.bounds.width, path.bounds.height)

// Create bitmap image from context using the rect
let imageRef: CGImageRef = CGImageCreateWithImageInRect(image.CGImage, rect)
ImgView.bounds = rect
ImgView.image = UIImage(CGImage: imageRef)

我能够通过获取路径边界和大小并更改我的ImageView的边界来使其居中。:)

6uxekuva

6uxekuva1#

要获得裁剪的居中位置,可以将高度和宽度的差异减半。然后,您可以在检查图像的方向(哪个部分较长)后为新的宽度和高度指定边界

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

    let contextImage: UIImage = UIImage(CGImage: image.CGImage)!

    let contextSize: CGSize = contextImage.size

    var posX: CGFloat = 0.0
    var posY: CGFloat = 0.0
    var cgwidth: CGFloat = CGFloat(width)
    var cgheight: CGFloat = CGFloat(height)

    // See what size is longer and create the center off of that
    if contextSize.width > contextSize.height {
        posX = ((contextSize.width - contextSize.height) / 2)
        posY = 0
        cgwidth = contextSize.height
        cgheight = contextSize.height
    } else {
        posX = 0
        posY = ((contextSize.height - contextSize.width) / 2)
        cgwidth = contextSize.width
        cgheight = contextSize.width
    }

    let rect: CGRect = CGRectMake(posX, posY, cgwidth, cgheight)

    // Create bitmap image from context using the rect
    let imageRef: CGImageRef = CGImageCreateWithImageInRect(contextImage.CGImage, rect)

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

    return image
}

我在website上找到了大部分这些信息,如果你想进一步阅读的话。

针对SWIFT 4更新

func cropToBounds(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 cgwidth: CGFloat = CGFloat(width)
        var cgheight: CGFloat = CGFloat(height)

        // See what size is longer and create the center off of that
        if contextSize.width > contextSize.height {
            posX = ((contextSize.width - contextSize.height) / 2)
            posY = 0
            cgwidth = contextSize.height
            cgheight = contextSize.height
        } else {
            posX = 0
            posY = ((contextSize.height - contextSize.width) / 2)
            cgwidth = contextSize.width
            cgheight = contextSize.width
        }

        let rect: CGRect = CGRect(x: posX, y: posY, width: cgwidth, height: cgheight)

        // Create bitmap image from context using the rect
        let imageRef: CGImage = cgimage.cropping(to: rect)!

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

        return image
    }
b1payxdu

b1payxdu2#

被接受的答案只对我来说是正确的。我需要更灵活的裁剪机制,所以我写了一个扩展,如下所示:
导入UIKit

extension UIImage {

func crop(to:CGSize) -> UIImage {

    guard let cgimage = self.cgImage else { return self }

    let contextImage: UIImage = UIImage(cgImage: cgimage)

    guard let newCgImage = contextImage.cgImage else { return self }

    let contextSize: CGSize = contextImage.size

    //Set to square
    var posX: CGFloat = 0.0
    var posY: CGFloat = 0.0
    let cropAspect: CGFloat = to.width / to.height

    var cropWidth: CGFloat = to.width
    var cropHeight: CGFloat = to.height

    if to.width > to.height { //Landscape
        cropWidth = contextSize.width
        cropHeight = contextSize.width / cropAspect
        posY = (contextSize.height - cropHeight) / 2
    } else if to.width < to.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 self}

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

    UIGraphicsBeginImageContextWithOptions(to, false, self.scale)
    cropped.draw(in: CGRect(x: 0, y: 0, width: to.width, height: to.height))
    let resized = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return resized ?? self
  }
}

您可以这样使用它:

let size = CGSize(width: 300, height: 200)
let image = UIImage(named: "my_great_photo")?.crop(size)

如果谁有想法如何使风景,肖像和广场处理得更好一点,让我知道。

cbjzeqam

cbjzeqam3#

你可以试试这个答案。它是用斯威夫特3写的。

extension UIImage {
  func crop(to:CGSize) -> UIImage {
    guard let cgimage = self.cgImage else { return self }

    let contextImage: UIImage = UIImage(cgImage: cgimage)

    let contextSize: CGSize = contextImage.size

    //Set to square
    var posX: CGFloat = 0.0
    var posY: CGFloat = 0.0
    let cropAspect: CGFloat = to.width / to.height

    var cropWidth: CGFloat = to.width
    var cropHeight: CGFloat = to.height

    if to.width > to.height { //Landscape
        cropWidth = contextSize.width
        cropHeight = contextSize.width / cropAspect
        posY = (contextSize.height - cropHeight) / 2
    } else if to.width < to.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
    let imageRef: CGImage = contextImage.cgImage!.cropping(to: rect)!

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

    cropped.draw(in: CGRect(x : 0, y : 0, width : to.width, height : to.height))

    return cropped
  }
}
vwoqyblh

vwoqyblh4#

这就是答案,归功于@awolf(裁剪UIImage)。完美地处理比例和方向。只需在要裁剪的图像上调用此方法,并传入裁剪后的CGRect,而无需担心大小或方向。请随意检查cgImage是否为零,而不是像我在这里所做的那样强行打开它。

extension UIImage {
    func croppedInRect(rect: CGRect) -> UIImage {
        func rad(_ degree: Double) -> CGFloat {
            return CGFloat(degree / 180.0 * .pi)
        }

        var rectTransform: CGAffineTransform
        switch imageOrientation {
        case .left:
            rectTransform = CGAffineTransform(rotationAngle: rad(90)).translatedBy(x: 0, y: -self.size.height)
        case .right:
            rectTransform = CGAffineTransform(rotationAngle: rad(-90)).translatedBy(x: -self.size.width, y: 0)
        case .down:
            rectTransform = CGAffineTransform(rotationAngle: rad(-180)).translatedBy(x: -self.size.width, y: -self.size.height)
        default:
            rectTransform = .identity
        }
        rectTransform = rectTransform.scaledBy(x: self.scale, y: self.scale)

        let imageRef = self.cgImage!.cropping(to: rect.applying(rectTransform))
        let result = UIImage(cgImage: imageRef!, scale: self.scale, orientation: self.imageOrientation)
        return result
    }
}

如果你想要裁剪矩形居中,只需做简单的数学运算。沿着……的路线

let x = (image.width - croppingFrame.width) / 2

另请注意:如果您正在使用嵌入到scrollView中的imageView,则还有一个额外的步骤,您必须考虑缩放因素。假设您的imageView跨越了scrollView的整个内容视图,并且您使用scrollView的边界作为裁剪框架,则裁剪后的图像可以如下所示

let ratio = imageView.image!.size.height / scrollView.contentSize.height
let origin = CGPoint(x: scrollView.contentOffset.x * ratio, y: scrollView.contentOffset.y * ratio)
let size = CGSize(width: scrollView.bounds.size.width * ratio, let height: scrollView.bounds.size.height * ratio)
let cropFrame = CGRect(origin: origin, size: size)
let croppedImage = imageView.image!.croppedInRect(rect: cropFrame)
57hvy0tb

57hvy0tb5#

科尔的道具

SWIFT 3

func crop(image: UIImage, withWidth width: Double, andHeight height: Double) -> UIImage? {

    if 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 cgwidth: CGFloat = CGFloat(width)
        var cgheight: CGFloat = CGFloat(height)

        // See what size is longer and create the center off of that
        if contextSize.width > contextSize.height {
            posX = ((contextSize.width - contextSize.height) / 2)
            posY = 0
            cgwidth = contextSize.height
            cgheight = contextSize.height
        } else {
            posX = 0
            posY = ((contextSize.height - contextSize.width) / 2)
            cgwidth = contextSize.width
            cgheight = contextSize.width
        }

        let rect: CGRect = CGRect(x: posX, y: posY, width: cgwidth, height: cgheight)

        // Create bitmap image from context using the rect
        var croppedContextImage: CGImage? = nil
        if let contextImage = contextImage.cgImage {
            if let croppedImage = contextImage.cropping(to: rect) {
                croppedContextImage = croppedImage
            }
        }

        // Create a new image based on the imageRef and rotate back to the original orientation
        if let croppedImage:CGImage = croppedContextImage {
            let image: UIImage = UIImage(cgImage: croppedImage, scale: image.scale, orientation: image.imageOrientation)
            return image
        }

    }

    return nil
}
zujrkrfu

zujrkrfu6#

SWIFT 3工作示例

extension UIImage {

    func crop(to:CGSize) -> UIImage {
        guard let cgimage = self.cgImage else { return self }

        let contextImage: UIImage = UIImage(cgImage: cgimage)

        let contextSize: CGSize = contextImage.size

        //Set to square
        var posX: CGFloat = 0.0
        var posY: CGFloat = 0.0
        let cropAspect: CGFloat = to.width / to.height

        var cropWidth: CGFloat = to.width
        var cropHeight: CGFloat = to.height

        if to.width > to.height { //Landscape
            cropWidth = contextSize.width
            cropHeight = contextSize.width / cropAspect
            posY = (contextSize.height - cropHeight) / 2
        } else if to.width < to.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
        let imageRef: CGImage = contextImage.cgImage!.cropping(to: rect)!

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

        UIGraphicsBeginImageContextWithOptions(to, true, self.scale)
        cropped.draw(in: CGRect(x: 0, y: 0, width: to.width, height: to.height))
        let resized = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return resized!
    }
}
e1xvtsh3

e1xvtsh37#

您只需使用以下命令进行裁剪:

let croppedImage = yourImage.cgImage.cropping(to:rect)
puruo6ea

puruo6ea8#

在SWIFT 4.1中,我将简单地执行以下操作:

imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 20

贷方至Stretching, Redrawing and Positioning with contentMode

yk9xbfzb

yk9xbfzb9#

我想出了一个代码,它将提供所需的裁剪长宽比,而不考虑原始视频帧大小(改编自@Cole的答案):

func cropImage(uncroppedImage: UIImage, cropWidth: CGFloat, cropHeight: CGFloat) -> UIImage {

        let contextImage: UIImage = UIImage(cgImage: uncroppedImage.cgImage!)

        let contextSize: CGSize = contextImage.size
        var cropX: CGFloat = 0.0
        var cropY: CGFloat = 0.0
        var cropRatio: CGFloat = CGFloat(cropWidth/cropHeight)
        var originalRatio: CGFloat = contextSize.width/contextSize.height
        var scaledCropHeight: CGFloat = 0.0
        var scaledCropWidth: CGFloat = 0.0

        // See what size is longer and set crop rect parameters
        if originalRatio > cropRatio {

            scaledCropHeight = contextSize.height
            scaledCropWidth = (contextSize.height/cropHeight) * cropWidth
            cropX = (contextSize.width - scaledCropWidth) / 2
            cropY = 0

        } else {
            scaledCropWidth = contextSize.width
            scaledCropHeight = (contextSize.width/cropWidth) * cropHeight
            cropY = (contextSize.height / scaledCropHeight) / 2
            cropX = 0
        }

        let rect: CGRect = CGRect(x: cropX, y: cropY, width: scaledCropWidth, height: scaledCropHeight)

        // Create bitmap image from context using the rect
        let imageRef: CGImage = contextImage.cgImage!.cropping(to: rect)!

        // Create a new image based on the imageRef and rotate back to the original orientation

        let croppedImage: UIImage = UIImage(cgImage: imageRef, scale: uncroppedImage.scale, orientation: uncroppedImage.imageOrientation)

        return croppedImage
    }

希望它能帮上忙!

imzjd6km

imzjd6km10#

被接受的答案对我不起作用,所以我试着写我自己的。以下是我工作的一个效果:

import UIKit

extension UIImage {

    func cropedToRatio(ratio: CGFloat) -> UIImage? {
        let newImageWidth = size.height * ratio

        let cropRect = CGRect(x: ((size.width - newImageWidth) / 2.0) * scale,
                              y: 0.0,
                              width: newImageWidth * scale,
                              height: size.height * scale)

        guard let cgImage = cgImage else {
            return nil
        }
        guard let newCgImage = cgImage.cropping(to: cropRect) else {
            return nil
        }

        return UIImage(cgImage: newCgImage, scale: scale, orientation: imageOrientation)
    }
}

此函数将裁剪图像与给定的比例进行比较。它保持了图像的比例。裁剪后的图像始终是原始图像的中心。

doinxwow

doinxwow11#

您还可以非常简单地将相关的ImageView从Storyboard置于“Aspect Fill”模式,并将其添加到代码中:

imageView.layer.masksToBounds = true
imageView.clipsToBounds = true
efzxgjgh

efzxgjgh12#

或创建UImage扩展名

extension UIImage {
    func cropped(boundingBox: CGRect) -> UIImage? {
        guard let cgImage = self.cgImage?.cropping(to: boundingBox) else {
            return nil
        }

        return UIImage(cgImage: cgImage)
    }
}
vmpqdwk3

vmpqdwk313#

更改这一点:

masklayer.frame = ImgView.frame

对此:

masklayer.frame = ImgView.bounds
oo7oh9g9

oo7oh9g914#

您还可以使用AlamoFire和AlamoFireImage来裁剪您的图像。

https://github.com/Alamofire/AlamofireImage

使用CocoaPods pod 'AlamofireImage'安装

用途:

let image = UIImage(named: "unicorn")!
let size = CGSize(width: 100.0, height: 100.0)
// Scale image to size disregarding aspect ratio
let scaledImage = image.af_imageScaled(to: size)
let aspectScaledToFitImage = image.af_imageAspectScaled(toFit: size)

// Scale image to fill specified size while maintaining aspect ratio
let aspectScaledToFillImage = image.af_imageAspectScaled(toFill: size)
zaq34kh6

zaq34kh615#

SWIFT 5

extension UIImage {
    /// A function who takes in a uiimage and crops it to its largest square value
    /// - Returns: The cropped image. Nil if the data could not be extracted from the UIImage
    internal func croppedToSquare() -> UIImage? {
        guard let sourceImageData = self.cgImage else {
            return nil
        }

        let shortestSide = min(self.size.width, self.size.height)

        // Determines the x,y coordinate of the top-left corner of the cropped photo
        /// The distance from the leading edge of the original photo to the leading edge of the cropped photo (should be 0 for photos in portrait orientation)
        let xOffset = (self.size.width - shortestSide) / 2
        /// The distance from the top edge of the original photo to the top edge of the cropped photo (should be 0 for photos in landscape orientation)
        let yOffset = (self.size.height - shortestSide) / 2

        /// A boolean which indicates if the image data is a rotation (reflections don't matter) of the uiimage. If so, they x and y coordinates should be transposed.
        let axesAreFlipped = self.imageOrientation == .left || self.imageOrientation == .right
        /// The square to crop the image through, with the x, y coordinate describing the top left corner of the square
        let cropMask = CGRect(x: axesAreFlipped ? yOffset : xOffset, y: axesAreFlipped ? xOffset : yOffset, width: shortestSide, height: shortestSide).integral

        guard let newImageData = sourceImageData.cropping(to: cropMask) else {
            return nil
        }

        return UIImage(cgImage: newImageData, scale: self.imageRendererFormat.scale, orientation: self.imageOrientation)
    }
}

此函数的工作原理是从给定的UIImage中提取CGImage数据,然后找到照片左上角的坐标。从这个坐标开始,绘制一个等边的矩形(边长是原始图像的最短边)。

请注意,CGImage数据描述的是UIImage中 Package 的原始照片的数据,而不是UIImage默认情况下实际显示的数据。因此,需要检查图像的原始方向以确定是否需要反转x和y值。

相关问题