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

时间:2015-08-17 00:58:07

标签: ios swift

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

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

14 个答案:

答案 0 :(得分:61)

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

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
    }

答案 1 :(得分:17)

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

  

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

如果有人有想法如何使景观,肖像和广场处理更好,请告诉我。

答案 2 :(得分:13)

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

答案 3 :(得分:6)

这是答案,归功于@awolf(Cropping an UIImage)。完美地处理比例和方向。只需在要裁剪的图像上调用此方法,然后传递裁剪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

如果您希望裁剪矩形居中,只需进行简单的数学计算即可。

imageView

另一个注意事项:如果您使用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) 的边界作为裁剪框,则可以获得裁剪后的图像

from pynput.keyboard import Key,Controller import time

keyboard = Controller()

time.sleep(60)

# 1
keyboard.press(Key.enter)
keyboard.release(Key.enter)

# 2
i = 0
while i < 4:
    keyboard.press(Key.tab)
    keyboard.release(Key.tab)
    i = i + 1;

# 3
i= 0
while i < 3:
    keyboard.press(Key.enter)
    keyboard.release(Key.enter)
    i = i + 1;

# 4
i = 0
while i < 4:
    with keyboard.pressed(Key.shift):
        keyboard.press(Key.tab)
        keyboard.release(Key.tab)
        i = i + 1;

答案 4 :(得分:3)

走向科尔的道具

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
}

答案 5 :(得分: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)

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

答案 6 :(得分:2)

您可以使用以下方式裁剪:

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

答案 7 :(得分:1)

改变这个:

masklayer.frame = ImgView.frame

对此:

masklayer.frame = ImgView.bounds

答案 8 :(得分:1)

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

Test

答案 9 :(得分:1)

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

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

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

答案 10 :(得分:1)

或进行UImage扩展

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

        return UIImage(cgImage: cgImage)
    }
}

答案 11 :(得分:0)

您还可以使用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)

答案 12 :(得分:0)

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

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

贷记Stretching, Redrawing and Positioning with contentMode

答案 13 :(得分:0)

我想出了一个代码,不管原始视频帧的大小如何,该代码都可以提供理想的裁剪长宽比(改编自@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
    }

希望有帮助!