Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rounding UIImage and adding a border

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 want them to be rounded and with a border. So I found a way to round UIImage and I found the way to add a border to UIImage, but border doesn't seem to add (I'm not actually having the image on the screen, maybe that is the problem?).

I used this answer https://stackoverflow.com/a/29047372/4665643 with a slight modification for border. Namely:

imageView.layer.borderWidth = 1.5
imageView.layer.borderColor = UIColor.whiteColor().CGColor
imageView.clipsToBounds = true

But my image on the map doesn't have any border. Any suggestions ?

like image 866
Olexiy Burov Avatar asked Jan 25 '16 04:01

Olexiy Burov


2 Answers

imageView.layer.masksToBounds = true
imageView.layer.borderWidth = 1.5
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.cornerRadius = imageView.bounds.width / 2

Try this.

like image 133
keval Avatar answered Oct 12 '22 16:10

keval


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)

enter image description here

like image 30
Leo Dabus Avatar answered Oct 12 '22 15:10

Leo Dabus