Cropping image with Swift and put it on center position

后端 未结 14 1104
心在旅途
心在旅途 2020-12-01 00:32

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

This is what I\'ve got so far ... I\'ve successfully crop the image but I want t

相关标签:
14条回答
  • 2020-12-01 01:12

    Or make UImage extension

    extension UIImage {
        func cropped(boundingBox: CGRect) -> UIImage? {
            guard let cgImage = self.cgImage?.cropping(to: boundingBox) else {
                return nil
            }
    
            return UIImage(cgImage: cgImage)
        }
    }
    
    0 讨论(0)
  • 2020-12-01 01:16

    You can try this answer. It is written in 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
      }
    }
    
    0 讨论(0)
  • 2020-12-01 01:16

    Change this:

    masklayer.frame = ImgView.frame
    

    To this:

    masklayer.frame = ImgView.bounds
    
    0 讨论(0)
  • 2020-12-01 01:17

    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

    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.

    0 讨论(0)
  • 2020-12-01 01:17

    Props to Cole

    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
    }
    
    0 讨论(0)
  • 2020-12-01 01:19

    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 CGRect without worrying about scale or orientation. Feel free to check whether cgImage is nil instead of force unwrapping it like I did here.

    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 imageView embedded in a scrollView, there is one additional step, you have to take the zoom factor into account. Assuming your imageView spans the entire content view of the scrollView, and you use the bounds of the scrollView as the cropping frame, the cropped image can be obtained as

    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)
    
    0 讨论(0)
提交回复
热议问题