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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32041420/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:18:21  来源:igfitidea点击:

Cropping image with Swift and put it on center position

iosswift

提问by jhayvi

In Swift programming , how do you crop an image and put it on the center afterwards?

在 Swift 编程中,如何裁剪图像并在之后将其放在中心?

This is what I've got so far ... I've successfully crop the image but I want to put it on the center after

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

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();

UPDATE :

更新 :

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)

I was able to center it by getting the path.bound and size and change the bounds of my ImageView. :)

我能够通过获取 path.bound 和 size 并更改我的 ImageView 的边界来将其居中。:)

回答by Cole

To get a centered position for your crop, you can halve the difference of the height and width. Then you can assign the bounds for the new width and height after checking the orientation of the image (which part is longer)

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

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
}

I found most of this info over at this websitein case you wanted to read further.

我在这个网站上找到了大部分信息,以防你想进一步阅读。

Updated for Swift 4

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
    }

回答by Tanel Teemusk

The accepted answer only does squares for me. I needed a bit more flexible cropping mechanism so I wrote an extension as follows:

接受的答案只对我有用。我需要一个更灵活的裁剪机制,所以我写了一个扩展如下:

import UIKit

导入 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
  }
}

You can use it so:

你可以这样使用它:

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

If anyone has ideas how to make the landscape, portrait and square handling a bit better let me know.

如果有人对如何使风景、肖像和方形处理更好一点有想法,请告诉我。

回答by kishor0011

You can try this answer. It is written in swift 3.

你可以试试这个答案。它是用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)

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

    return cropped
  }
}

回答by JGuo

This is THE answer, credit to @awolf (Cropping an UIImage). Handles scale and orientation perfectly. Just call this method on the image you want to crop, and pass in the cropping CGRectwithout worrying about scale or orientation. Feel free to check whether cgImageis nil instead of force unwrapping it like I did here.

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

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
    }
}

If you want the cropping rect to be centered, just do simple math. Along the lines of

如果您希望裁剪矩形居中,只需做简单的数学运算即可。沿着

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

Another note: if you are working with imageViewembedded in a scrollView, there is one additional step, you have to take the zoom factor into account. Assuming your imageViewspans the entire content view of the scrollView, and you use the bounds of the scrollViewas the cropping frame, the cropped image can be obtained as

另一个注意事项:如果您正在使用imageView内嵌在 a 中scrollView,则还有一个额外的步骤,您必须考虑缩放系数。假设您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)

回答by Ramesh Tester

You can just crop using:

您可以使用以下方法进行裁剪:

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

回答by Brandon A

Props to Cole

给科尔的道具

Swift 3

斯威夫特 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
}

回答by BilalReffas

Working Swift 3 example

工作 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!
    }
}

回答by Kamil Harasimowicz

Accepted answer did not work for me, so I tried wrote my own. Here is an effect of my work:

接受的答案对我不起作用,所以我尝试自己写。这是我工作的效果:

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)
    }
}

This function crop image to given ratio. It keeps image scale. Cropped image is always center of original image.

此功能将图像裁剪为给定的比例。它保持图像比例。裁剪后的图像始终是原始图像的中心。

回答by iPera

Or make UImage extension

或者做 UImage 扩展

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

        return UIImage(cgImage: cgImage)
    }
}

回答by madx

In swift 4.1 I would do simply:

在 swift 4.1 中,我会简单地做:

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

Credits to Stretching, Redrawing and Positioning with contentMode

使用 contentMode进行拉伸、重绘和定位的功劳