Rounding UIImage and adding a border

前端 未结 9 1150
青春惊慌失措
青春惊慌失措 2020-12-09 18:19

so I want to show some pictures as annotations on the map. In order to do that I need to add the image property of the MKAnnotationView. I\'m using the regular images but I

9条回答
  •  独厮守ぢ
    2020-12-09 18:32

    If you would like to add a border to your image you need to make sure you add some extra room to it otherwise your border will be placed in top of your image. The solution is to add twice the width of your stroke to your image's width and height.

    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) }
        func rounded(with color: UIColor, width: CGFloat) -> UIImage? {
            let bleed = breadthRect.insetBy(dx: -width, dy: -width)
            UIGraphicsBeginImageContextWithOptions(bleed.size, false, scale)
            defer { UIGraphicsEndImageContext() }
            guard let cgImage = cgImage?.cropping(to: CGRect(origin: CGPoint(
                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 }
            UIBezierPath(ovalIn: .init(origin: .zero, size: bleed.size)).addClip()
            var strokeRect =  breadthRect.insetBy(dx: -width/2, dy: -width/2)
            strokeRect.origin = .init(x: width/2, y: width/2)
            UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
                .draw(in: strokeRect.insetBy(dx: width/2, dy: width/2))
            color.set()
            let line: UIBezierPath = .init(ovalIn: strokeRect)
            line.lineWidth = width
            line.stroke()
            return UIGraphicsGetImageFromCurrentImageContext()
        }
    }
    

    For iOS10+ We can use UIGraphicsImageRenderer.

    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) }
        func rounded(with color: UIColor, width: CGFloat) -> UIImage? {
    
            guard let cgImage = cgImage?.cropping(to: .init(origin: .init(x: isLandscape ? ((size.width-size.height)/2).rounded(.down) : .zero, y: isPortrait ? ((size.height-size.width)/2).rounded(.down) : .zero), size: breadthSize)) else { return nil }
    
            let bleed = breadthRect.insetBy(dx: -width, dy: -width)
            let format = imageRendererFormat
            format.opaque = false
    
            return UIGraphicsImageRenderer(size: bleed.size, format: format).image { context in
                UIBezierPath(ovalIn: .init(origin: .zero, size: bleed.size)).addClip()
                var strokeRect =  breadthRect.insetBy(dx: -width/2, dy: -width/2)
                strokeRect.origin = .init(x: width/2, y: width/2)
                UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
                .draw(in: strokeRect.insetBy(dx: width/2, dy: width/2))
                context.cgContext.setStrokeColor(color.cgColor)
                let line: UIBezierPath = .init(ovalIn: strokeRect)
                line.lineWidth = width
                line.stroke()
            }
        }
    }
    

    Playground Testing:

    let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"http://i.stack.imgur.com/Xs4RX.jpg")!))!
    let pp = profilePicture.rounded(with: .red, width: 10)
    

提交回复
热议问题