Last active
July 27, 2020 15:02
-
-
Save bteapot/8d4896f30dd7a2d50f169f50f23b68bc to your computer and use it in GitHub Desktop.
UIImage extension for generating two-letter avatars with reproducible color.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import UIKit | |
extension UIFont { | |
func with(traits: UIFontDescriptor.SymbolicTraits) -> UIFont { | |
if let fontDescriptor = self.fontDescriptor.withSymbolicTraits(traits) { | |
return UIFont(descriptor: fontDescriptor, size: 0) | |
} else { | |
return self | |
} | |
} | |
func with(weight: UIFont.Weight) -> UIFont { | |
let fontDescriptor = self.fontDescriptor.addingAttributes([ | |
.traits: [ | |
UIFontDescriptor.TraitKey.weight: weight, | |
], | |
]) | |
return UIFont(descriptor: fontDescriptor, size: 0) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import UIKit | |
extension UIImage { | |
class func avatar( | |
id: Int = 0, | |
text: String?, | |
size: CGSize, | |
saturation: CGFloat = 0.40, | |
brightness: CGFloat = 0.80, | |
font: UIFont? = nil, | |
corners: CGFloat = 0, | |
placeholder: UIImage? | |
) -> UIImage? { | |
// есть текст? | |
guard let text = text, text.isEmpty == false else { | |
return placeholder | |
} | |
// вычислим инициалы | |
let words: [String] = text.components(separatedBy: CharacterSet.whitespacesAndNewlines.union(.punctuationCharacters)) | |
let first: [String] = words.compactMap({ $0.first }).map(String.init) | |
let initials = { () -> String in | |
switch first.count { | |
case 2...: return first[0] + first[1] | |
case 1: return String(first[0].prefix(2)) | |
default: return "" | |
} | |
}().uppercased() | |
// пусто? | |
guard initials.isEmpty == false else { | |
return placeholder | |
} | |
// хэш | |
let hash: UInt = UInt(bitPattern: (String(id) + initials).hashValue) | |
// оттенок | |
let hue = CGFloat(hash % 360) / 360 | |
// цвета | |
let backgroundColor = | |
UIColor( | |
hue: hue, | |
saturation: saturation, | |
brightness: brightness, | |
alpha: 1 | |
) | |
let textColor = | |
UIColor( | |
hue: 0, | |
saturation: 0, | |
brightness: brightness > 0.8 ? 0.2 : 1.0, | |
alpha: 1 | |
) | |
// шрифт | |
let font: UIFont = font ?? UIFont.systemFont(ofSize: floor(size.height / 2), weight: .regular).with(traits: .traitCondensed) | |
// нарисуем и отдадим картинку | |
return UIGraphicsImageRenderer(size: size).image { context in | |
// фон | |
backgroundColor.setFill() | |
UIBezierPath(roundedRect: CGRect(origin: .zero, size: size), cornerRadius: corners).fill() | |
// текст | |
let attributedText = NSAttributedString(string: initials, attributes: [ | |
.font: font, | |
.foregroundColor: textColor, | |
]) | |
let options: NSStringDrawingOptions = [.usesLineFragmentOrigin] | |
let textSize = attributedText.boundingRect(with: .zero, options: options, context: nil).size | |
let textRect = CGRect(x: (size.width - textSize.width) / 2, y: (size.height - textSize.height) / 2, width: textSize.width, height: textSize.height) | |
attributedText.draw(with: textRect, options: options, context: nil) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment