Как сделать эллипс / круговой UIImage с прозрачным фоном?

Это код, который я использую

extension UIImage {        
    var ellipseMasked: UIImage? {
        guard let cgImage = cgImage else { return nil }
        let rect = CGRect(origin: .zero, size: size)

        return UIGraphicsImageRenderer(size: size, format: imageRendererFormat)
            .image{ _ in
                UIBezierPath(ovalIn: rect).addClip()
                UIImage(cgImage: cgImage, scale: scale, orientation: imageOrientation)
            .draw(in: rect)
        }
    }
}

Это изображение, которое я получил

Цвет фона - черный. Как сделать фон прозрачным? Я пробовал разные способы, но пока не заработал.

2 ответа

Решение

Вы можете создать подкласс UIImageView и замаскировать его CALayer вместо обрезки самого изображения:

extension CAShapeLayer {
    convenience init(path: UIBezierPath) {
        self.init()
        self.path = path.cgPath
    }
}

class EllipsedView: UIImageView {
    override func layoutSubviews() {
        super.layoutSubviews()
        layer.mask = CAShapeLayer(path: .init(ovalIn: bounds))
    }
}

let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"https://stackru.com/images/ef9dfaef8c3bec7e67a69584eb37fe5a3e115132.jpg")!))!
let iv = EllipsedView(image: profilePicture)

редактировать / обновлять

Если вам нужно закрепить UIImage сам вы можете сделать это следующим образом:

extension UIImage {
    var ellipseMasked: UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        defer { UIGraphicsEndImageContext() }
        UIBezierPath(ovalIn: .init(origin: .zero, size: size)).addClip()
        draw(in: .init(origin: .zero, size: size))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

Для iOS10+ вы можете использовать UIGraphicsImageRenderer.

extension UIImage {
    var ellipseMasked: UIImage {
        let rect = CGRect(origin: .zero, size: size)
        let format = imageRendererFormat
        format.opaque = false
        return UIGraphicsImageRenderer(size: size, format: format).image{ _ in
            UIBezierPath(ovalIn: rect).addClip()
            draw(in: rect)
        }
    }
}

let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"https://stackru.com/images/ef9dfaef8c3bec7e67a69584eb37fe5a3e115132.jpg")!))!
profilePicture.ellipseMasked

Вот два решения с использованием SwiftUI.

Это решение можно использовать для обрезки формы изображения по кругу.

      Image("imagename").resizable()
    .clipShape(Circle())
    .scaledToFit()

Это решение можно использовать, чтобы получить на изображении больше затмения или овальной формы.

      Image("imagename").resizable()
    .cornerRadius(100)
    .scaledToFit()
    .padding()
Другие вопросы по тегам