Cut a UIImage into a circle

后端 未结 11 2260
面向向阳花
面向向阳花 2020-11-27 13:30

I want to cut a UIImage into a circle so that I can then use it as an annotation. Every answer on this site that I\'ve found describes creating an UIImage

相关标签:
11条回答
  • 2020-11-27 13:45

    Make sure to import QuarzCore if needed.

     func maskRoundedImage(image: UIImage, radius: CGFloat) -> UIImage {
            let imageView: UIImageView = UIImageView(image: image)
            let layer = imageView.layer
            layer.masksToBounds = true
            layer.cornerRadius = radius
            UIGraphicsBeginImageContext(imageView.bounds.size)
            layer.render(in: UIGraphicsGetCurrentContext()!)
            let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return roundedImage!
        }
    
    0 讨论(0)
  • 2020-11-27 13:47

    UIImage extension:

    extension UIImage {
    
        func circularImage(size size: CGSize?) -> UIImage {
            let newSize = size ?? self.size
    
            let minEdge = min(newSize.height, newSize.width)
            let size = CGSize(width: minEdge, height: minEdge)
    
            UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
            let context = UIGraphicsGetCurrentContext()
    
            self.drawInRect(CGRect(origin: CGPoint.zero, size: size), blendMode: .Copy, alpha: 1.0)
    
            CGContextSetBlendMode(context, .Copy)
            CGContextSetFillColorWithColor(context, UIColor.clearColor().CGColor)
    
            let rectPath = UIBezierPath(rect: CGRect(origin: CGPoint.zero, size: size))
            let circlePath = UIBezierPath(ovalInRect: CGRect(origin: CGPoint.zero, size: size))
            rectPath.appendPath(circlePath)
            rectPath.usesEvenOddFillRule = true
            rectPath.fill()
    
            let result = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            return result
        }
    
    }
    

    Usage:

    UIImageView:

    @IBDesignable class CircularImageView: UIImageView {
    
        override var image: UIImage? {
            didSet {
                super.image = image?.circularImage(size: nil)
            }
        }
    
    }
    

    UIButton:

    @IBDesignable class CircularImageButton: UIButton {
    
        override func setImage(image: UIImage?, forState state: UIControlState) {
            let circularImage = image?.circularImage(size: nil)
            super.setImage(circularImage, forState: state)
        }
    
    }
    
    0 讨论(0)
  • 2020-11-27 13:49

    Xcode 11 • Swift 5.1 or later

    edit/update: For iOS10+ We can use UIGraphicsImageRenderer. For older Swift syntax check edit history.

    extension UIImage {
        var isPortrait:  Bool    { size.height > size.width }
        var isLandscape: Bool    { size.width > size.height }
        var breadth:     CGFloat { min(size.width, size.height) }
        var breadthSize: CGSize  { .init(width: breadth, height: breadth) }
        var breadthRect: CGRect  { .init(origin: .zero, size: breadthSize) }
        var circleMasked: UIImage? {
            guard let cgImage = cgImage?
                .cropping(to: .init(origin: .init(x: isLandscape ? ((size.width-size.height)/2).rounded(.down) : 0,
                                                  y: isPortrait  ? ((size.height-size.width)/2).rounded(.down) : 0),
                                    size: breadthSize)) else { return nil }
            let format = imageRendererFormat
            format.opaque = false
            return UIGraphicsImageRenderer(size: breadthSize, format: format).image { _ in
                UIBezierPath(ovalIn: breadthRect).addClip()
                UIImage(cgImage: cgImage, scale: format.scale, orientation: imageOrientation)
                .draw(in: .init(origin: .zero, size: breadthSize))
            }
        }
    }
    

    Playground Testing

    let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"http://i.stack.imgur.com/Xs4RX.jpg")!))!
    profilePicture.circleMasked
    

    0 讨论(0)
  • 2020-11-27 13:54

    I managed to answer my own question by finding a use of BezierPath!

    if let xyz = UIImage(contentsOfFile: readPath) {
         var Rect: CGRect = CGRectMake(0, 0, xyz.size.width, xyz.size.height)
         var x = UIBezierPath(roundedRect: Rect, cornerRadius: 200).addClip()
    
         UIGraphicsBeginImageContextWithOptions(xyz.size, false, xyz.scale)
         xyz.drawInRect(Rect)
         var ImageNew = UIGraphicsGetImageFromCurrentImageContext()
         UIGraphicsEndImageContext()
         annotation.image = ImageNew
    }
    
    0 讨论(0)
  • 2020-11-27 13:55

    I am using RoundedImageView class, the problem facing is that when browse image from gallery the image not show in round or circle.. I simply change the properties of UIImageView/RoundedImageView -> view -> Content Mode -> Aspect Fillsee screenshot

    0 讨论(0)
  • 2020-11-27 14:01

    Swift 5.3, Xcode 12.2, Handles all imageOrientations

    Based on answer Leo Dabus

    Thanks, works perfectly! BUT only for images with imageOrientation .up or .down. For images with .right or .left orientation there are distortions in result. And from iPhone/iPad camera for original photos initially we get .right orientation.

    Code below takes into account imageOrientation property:

    extension UIImage {
    
        func cropToCircle() -> UIImage? {
        
            let isLandscape = size.width > size.height
            let isUpOrDownImageOrientation = [0,1,4,5].contains(imageOrientation.rawValue)
        
            let breadth: CGFloat = min(size.width, size.height)
            let breadthSize = CGSize(width: breadth, height: breadth)
            let breadthRect = CGRect(origin: .zero, size: breadthSize)
        
            let xOriginPoint = CGFloat(isLandscape ?
                                    (isUpOrDownImageOrientation ? ((size.width-size.height)/2).rounded(.down) : 0) :
                                    (isUpOrDownImageOrientation ? 0 : ((size.height-size.width)/2).rounded(.down)))
            let yOriginPoint = CGFloat(isLandscape ?
                                    (isUpOrDownImageOrientation ? 0 : ((size.width-size.height)/2).rounded(.down)) :
                                    (isUpOrDownImageOrientation ? ((size.height-size.width)/2).rounded(.down) : 0))
        
            guard let cgImage = cgImage?.cropping(to: CGRect(origin: CGPoint(x: xOriginPoint, y: yOriginPoint),
                                                         size: breadthSize)) else { return nil }
            let format = imageRendererFormat
            format.opaque = false
        
            return UIGraphicsImageRenderer(size: breadthSize, format: format).image {_ in
                UIBezierPath(ovalIn: breadthRect).addClip()
                UIImage(cgImage: cgImage, scale: format.scale, orientation: imageOrientation).draw(in: CGRect(origin: .zero, size: breadthSize))
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题