mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Autoremove improvements
This commit is contained in:
@@ -9,6 +9,7 @@ import AnimationUI
|
||||
import AppBundle
|
||||
import AccountContext
|
||||
import Emoji
|
||||
import Accelerate
|
||||
|
||||
private let deletedIcon = UIImage(bundleImageName: "Avatar/DeletedIcon")?.precomposed()
|
||||
private let phoneIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/PhoneIcon"), color: .white)
|
||||
@@ -30,6 +31,7 @@ private class AvatarNodeParameters: NSObject {
|
||||
let theme: PresentationTheme?
|
||||
let accountPeerId: EnginePeer.Id?
|
||||
let peerId: EnginePeer.Id?
|
||||
let colors: [UIColor]
|
||||
let letters: [String]
|
||||
let font: UIFont
|
||||
let icon: AvatarNodeIcon
|
||||
@@ -37,10 +39,11 @@ private class AvatarNodeParameters: NSObject {
|
||||
let hasImage: Bool
|
||||
let clipStyle: AvatarNodeClipStyle
|
||||
|
||||
init(theme: PresentationTheme?, accountPeerId: EnginePeer.Id?, peerId: EnginePeer.Id?, letters: [String], font: UIFont, icon: AvatarNodeIcon, explicitColorIndex: Int?, hasImage: Bool, clipStyle: AvatarNodeClipStyle) {
|
||||
init(theme: PresentationTheme?, accountPeerId: EnginePeer.Id?, peerId: EnginePeer.Id?, colors: [UIColor], letters: [String], font: UIFont, icon: AvatarNodeIcon, explicitColorIndex: Int?, hasImage: Bool, clipStyle: AvatarNodeClipStyle) {
|
||||
self.theme = theme
|
||||
self.accountPeerId = accountPeerId
|
||||
self.peerId = peerId
|
||||
self.colors = colors
|
||||
self.letters = letters
|
||||
self.font = font
|
||||
self.icon = icon
|
||||
@@ -52,18 +55,71 @@ private class AvatarNodeParameters: NSObject {
|
||||
}
|
||||
|
||||
func withUpdatedHasImage(_ hasImage: Bool) -> AvatarNodeParameters {
|
||||
return AvatarNodeParameters(theme: self.theme, accountPeerId: self.accountPeerId, peerId: self.peerId, letters: self.letters, font: self.font, icon: self.icon, explicitColorIndex: self.explicitColorIndex, hasImage: hasImage, clipStyle: self.clipStyle)
|
||||
return AvatarNodeParameters(theme: self.theme, accountPeerId: self.accountPeerId, peerId: self.peerId, colors: self.colors, letters: self.letters, font: self.font, icon: self.icon, explicitColorIndex: self.explicitColorIndex, hasImage: hasImage, clipStyle: self.clipStyle)
|
||||
}
|
||||
}
|
||||
|
||||
private let grayscaleColors: NSArray = [
|
||||
UIColor(rgb: 0xb1b1b1).cgColor, UIColor(rgb: 0xcdcdcd).cgColor
|
||||
private let grayscaleColors: [UIColor] = [
|
||||
UIColor(rgb: 0xb1b1b1), UIColor(rgb: 0xcdcdcd)
|
||||
]
|
||||
|
||||
private let savedMessagesColors: NSArray = [
|
||||
UIColor(rgb: 0x2a9ef1).cgColor, UIColor(rgb: 0x72d5fd).cgColor
|
||||
private let savedMessagesColors: [UIColor] = [
|
||||
UIColor(rgb: 0x2a9ef1), UIColor(rgb: 0x72d5fd)
|
||||
]
|
||||
|
||||
private func calculateColors(explicitColorIndex: Int?, peerId: EnginePeer.Id?, icon: AvatarNodeIcon, theme: PresentationTheme?) -> [UIColor] {
|
||||
let colorIndex: Int
|
||||
if let explicitColorIndex = explicitColorIndex {
|
||||
colorIndex = explicitColorIndex
|
||||
} else {
|
||||
if let peerId {
|
||||
if peerId.namespace == .max {
|
||||
colorIndex = -1
|
||||
} else {
|
||||
colorIndex = abs(Int(clamping: peerId.id._internalGetInt64Value()))
|
||||
}
|
||||
} else {
|
||||
colorIndex = -1
|
||||
}
|
||||
}
|
||||
|
||||
let colors: [UIColor]
|
||||
if icon != .none {
|
||||
if case .deletedIcon = icon {
|
||||
colors = grayscaleColors
|
||||
} else if case .phoneIcon = icon {
|
||||
colors = grayscaleColors
|
||||
} else if case .savedMessagesIcon = icon {
|
||||
colors = savedMessagesColors
|
||||
} else if case .repliesIcon = icon {
|
||||
colors = savedMessagesColors
|
||||
} else if case .editAvatarIcon = icon, let theme {
|
||||
colors = [theme.list.itemAccentColor.withAlphaComponent(0.1), theme.list.itemAccentColor.withAlphaComponent(0.1)]
|
||||
} else if case let .archivedChatsIcon(hiddenByDefault) = icon, let theme = theme {
|
||||
let backgroundColors: (UIColor, UIColor)
|
||||
if hiddenByDefault {
|
||||
backgroundColors = theme.chatList.unpinnedArchiveAvatarColor.backgroundColors.colors
|
||||
} else {
|
||||
backgroundColors = theme.chatList.pinnedArchiveAvatarColor.backgroundColors.colors
|
||||
}
|
||||
colors = [backgroundColors.1, backgroundColors.0]
|
||||
} else {
|
||||
colors = grayscaleColors
|
||||
}
|
||||
} else if colorIndex == -1 {
|
||||
if let theme {
|
||||
let backgroundColors = theme.chatList.unpinnedArchiveAvatarColor.backgroundColors.colors
|
||||
colors = [backgroundColors.1, backgroundColors.0]
|
||||
} else {
|
||||
colors = grayscaleColors
|
||||
}
|
||||
} else {
|
||||
colors = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count]
|
||||
}
|
||||
|
||||
return colors
|
||||
}
|
||||
|
||||
public enum AvatarNodeExplicitIcon {
|
||||
case phone
|
||||
}
|
||||
@@ -158,21 +214,21 @@ public final class AvatarEditOverlayNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
public final class AvatarNode: ASDisplayNode {
|
||||
public static let gradientColors: [NSArray] = [
|
||||
[UIColor(rgb: 0xff516a).cgColor, UIColor(rgb: 0xff885e).cgColor],
|
||||
[UIColor(rgb: 0xffa85c).cgColor, UIColor(rgb: 0xffcd6a).cgColor],
|
||||
[UIColor(rgb: 0x665fff).cgColor, UIColor(rgb: 0x82b1ff).cgColor],
|
||||
[UIColor(rgb: 0x54cb68).cgColor, UIColor(rgb: 0xa0de7e).cgColor],
|
||||
[UIColor(rgb: 0x4acccd).cgColor, UIColor(rgb: 0x00fcfd).cgColor],
|
||||
[UIColor(rgb: 0x2a9ef1).cgColor, UIColor(rgb: 0x72d5fd).cgColor],
|
||||
[UIColor(rgb: 0xd669ed).cgColor, UIColor(rgb: 0xe0a2f3).cgColor],
|
||||
public static let gradientColors: [[UIColor]] = [
|
||||
[UIColor(rgb: 0xff516a), UIColor(rgb: 0xff885e)],
|
||||
[UIColor(rgb: 0xffa85c), UIColor(rgb: 0xffcd6a)],
|
||||
[UIColor(rgb: 0x665fff), UIColor(rgb: 0x82b1ff)],
|
||||
[UIColor(rgb: 0x54cb68), UIColor(rgb: 0xa0de7e)],
|
||||
[UIColor(rgb: 0x4acccd), UIColor(rgb: 0x00fcfd)],
|
||||
[UIColor(rgb: 0x2a9ef1), UIColor(rgb: 0x72d5fd)],
|
||||
[UIColor(rgb: 0xd669ed), UIColor(rgb: 0xe0a2f3)],
|
||||
]
|
||||
|
||||
public var font: UIFont {
|
||||
didSet {
|
||||
if oldValue.pointSize != font.pointSize {
|
||||
if let parameters = self.parameters {
|
||||
self.parameters = AvatarNodeParameters(theme: parameters.theme, accountPeerId: parameters.accountPeerId, peerId: parameters.peerId, letters: parameters.letters, font: self.font, icon: parameters.icon, explicitColorIndex: parameters.explicitColorIndex, hasImage: parameters.hasImage, clipStyle: parameters.clipStyle)
|
||||
self.parameters = AvatarNodeParameters(theme: parameters.theme, accountPeerId: parameters.accountPeerId, peerId: parameters.peerId, colors: parameters.colors, letters: parameters.letters, font: self.font, icon: parameters.icon, explicitColorIndex: parameters.explicitColorIndex, hasImage: parameters.hasImage, clipStyle: parameters.clipStyle)
|
||||
}
|
||||
|
||||
if !self.displaySuspended {
|
||||
@@ -193,6 +249,29 @@ public final class AvatarNode: ASDisplayNode {
|
||||
private var state: AvatarNodeState = .empty
|
||||
|
||||
public var unroundedImage: UIImage?
|
||||
private var currentImage: UIImage?
|
||||
|
||||
public var badgeView: AvatarBadgeView? {
|
||||
didSet {
|
||||
if self.badgeView !== oldValue {
|
||||
if let badgeView = self.badgeView, let parameters = self.parameters {
|
||||
if parameters.hasImage {
|
||||
if let currentImage = self.currentImage {
|
||||
badgeView.update(content: .image(currentImage))
|
||||
}
|
||||
} else {
|
||||
let badgeColor: UIColor
|
||||
if parameters.colors.isEmpty {
|
||||
badgeColor = .white
|
||||
} else {
|
||||
badgeColor = parameters.colors[parameters.colors.count - 1]
|
||||
}
|
||||
badgeView.update(content: .color(badgeColor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let imageReady = Promise<Bool>(false)
|
||||
public var ready: Signal<Void, NoError> {
|
||||
@@ -217,6 +296,22 @@ public final class AvatarNode: ASDisplayNode {
|
||||
|
||||
self.imageNode.isLayerBacked = true
|
||||
self.addSubnode(self.imageNode)
|
||||
|
||||
self.imageNode.contentUpdated = { [weak self] image in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.currentImage = image
|
||||
|
||||
guard let badgeView = self.badgeView, let parameters = self.parameters else {
|
||||
return
|
||||
}
|
||||
|
||||
if parameters.hasImage, let image {
|
||||
badgeView.update(content: .image(image))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public func didLoad() {
|
||||
@@ -365,7 +460,7 @@ public final class AvatarNode: ASDisplayNode {
|
||||
self.editOverlayNode?.isHidden = true
|
||||
}
|
||||
|
||||
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer.id, letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true, clipStyle: clipStyle)
|
||||
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer.id, colors: calculateColors(explicitColorIndex: nil, peerId: peer.id, icon: icon, theme: theme), letters: peer.displayLetters, font: self.font, icon: icon, explicitColorIndex: nil, hasImage: true, clipStyle: clipStyle)
|
||||
} else {
|
||||
self.imageReady.set(.single(true))
|
||||
self.displaySuspended = false
|
||||
@@ -374,7 +469,18 @@ public final class AvatarNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
self.editOverlayNode?.isHidden = true
|
||||
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer?.id ?? EnginePeer.Id(0), letters: peer?.displayLetters ?? [], font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false, clipStyle: clipStyle)
|
||||
let colors = calculateColors(explicitColorIndex: nil, peerId: peer?.id ?? EnginePeer.Id(0), icon: icon, theme: theme)
|
||||
parameters = AvatarNodeParameters(theme: theme, accountPeerId: account.peerId, peerId: peer?.id ?? EnginePeer.Id(0), colors: colors, letters: peer?.displayLetters ?? [], font: self.font, icon: icon, explicitColorIndex: nil, hasImage: false, clipStyle: clipStyle)
|
||||
|
||||
if let badgeView = self.badgeView {
|
||||
let badgeColor: UIColor
|
||||
if colors.isEmpty {
|
||||
badgeColor = .white
|
||||
} else {
|
||||
badgeColor = colors[colors.count - 1]
|
||||
}
|
||||
badgeView.update(content: .color(badgeColor))
|
||||
}
|
||||
}
|
||||
if self.parameters == nil || self.parameters != parameters {
|
||||
self.parameters = parameters
|
||||
@@ -400,9 +506,9 @@ public final class AvatarNode: ASDisplayNode {
|
||||
|
||||
let parameters: AvatarNodeParameters
|
||||
if let icon = icon, case .phone = icon {
|
||||
parameters = AvatarNodeParameters(theme: nil, accountPeerId: nil, peerId: nil, letters: [], font: self.font, icon: .phoneIcon, explicitColorIndex: explicitIndex, hasImage: false, clipStyle: .round)
|
||||
parameters = AvatarNodeParameters(theme: nil, accountPeerId: nil, peerId: nil, colors: calculateColors(explicitColorIndex: explicitIndex, peerId: nil, icon: .phoneIcon, theme: nil), letters: [], font: self.font, icon: .phoneIcon, explicitColorIndex: explicitIndex, hasImage: false, clipStyle: .round)
|
||||
} else {
|
||||
parameters = AvatarNodeParameters(theme: nil, accountPeerId: nil, peerId: nil, letters: letters, font: self.font, icon: .none, explicitColorIndex: explicitIndex, hasImage: false, clipStyle: .round)
|
||||
parameters = AvatarNodeParameters(theme: nil, accountPeerId: nil, peerId: nil, colors: calculateColors(explicitColorIndex: explicitIndex, peerId: nil, icon: .none, theme: nil), letters: letters, font: self.font, icon: .none, explicitColorIndex: explicitIndex, hasImage: false, clipStyle: .round)
|
||||
}
|
||||
|
||||
self.displaySuspended = true
|
||||
@@ -433,8 +539,10 @@ public final class AvatarNode: ASDisplayNode {
|
||||
context.fill(bounds)
|
||||
}
|
||||
|
||||
let colorIndex: Int
|
||||
let colors: [UIColor]
|
||||
if let parameters = parameters as? AvatarNodeParameters {
|
||||
colors = parameters.colors
|
||||
|
||||
if case .round = parameters.clipStyle {
|
||||
context.beginPath()
|
||||
context.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height:
|
||||
@@ -445,59 +553,21 @@ public final class AvatarNode: ASDisplayNode {
|
||||
context.addPath(UIBezierPath(roundedRect: CGRect(x: 0.0, y: 0.0, width: bounds.size.width, height: bounds.size.height), cornerRadius: floor(bounds.size.width * 0.25)).cgPath)
|
||||
context.clip()
|
||||
}
|
||||
|
||||
if let explicitColorIndex = parameters.explicitColorIndex {
|
||||
colorIndex = explicitColorIndex
|
||||
} else {
|
||||
if let peerId = parameters.peerId {
|
||||
if peerId.namespace == .max {
|
||||
colorIndex = -1
|
||||
} else {
|
||||
colorIndex = abs(Int(clamping: peerId.id._internalGetInt64Value()))
|
||||
}
|
||||
} else {
|
||||
colorIndex = -1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
colorIndex = -1
|
||||
colors = grayscaleColors
|
||||
}
|
||||
|
||||
let colorsArray: NSArray
|
||||
let colorsArray: NSArray = colors.map(\.cgColor) as NSArray
|
||||
|
||||
var iconColor = UIColor.white
|
||||
if let parameters = parameters as? AvatarNodeParameters, parameters.icon != .none {
|
||||
if case .deletedIcon = parameters.icon {
|
||||
colorsArray = grayscaleColors
|
||||
} else if case .phoneIcon = parameters.icon {
|
||||
colorsArray = grayscaleColors
|
||||
} else if case .savedMessagesIcon = parameters.icon {
|
||||
colorsArray = savedMessagesColors
|
||||
} else if case .repliesIcon = parameters.icon {
|
||||
colorsArray = savedMessagesColors
|
||||
} else if case .editAvatarIcon = parameters.icon, let theme = parameters.theme {
|
||||
colorsArray = [theme.list.itemAccentColor.withAlphaComponent(0.1).cgColor, theme.list.itemAccentColor.withAlphaComponent(0.1).cgColor]
|
||||
} else if case let .archivedChatsIcon(hiddenByDefault) = parameters.icon, let theme = parameters.theme {
|
||||
let backgroundColors: (UIColor, UIColor)
|
||||
if case let .archivedChatsIcon(hiddenByDefault) = parameters.icon, let theme = parameters.theme {
|
||||
if hiddenByDefault {
|
||||
iconColor = theme.chatList.unpinnedArchiveAvatarColor.foregroundColor
|
||||
backgroundColors = theme.chatList.unpinnedArchiveAvatarColor.backgroundColors.colors
|
||||
} else {
|
||||
iconColor = theme.chatList.pinnedArchiveAvatarColor.foregroundColor
|
||||
backgroundColors = theme.chatList.pinnedArchiveAvatarColor.backgroundColors.colors
|
||||
}
|
||||
colorsArray = [backgroundColors.1.cgColor, backgroundColors.0.cgColor]
|
||||
} else {
|
||||
colorsArray = grayscaleColors
|
||||
}
|
||||
} else if colorIndex == -1 {
|
||||
if let parameters = parameters as? AvatarNodeParameters, let theme = parameters.theme {
|
||||
let colors = theme.chatList.unpinnedArchiveAvatarColor.backgroundColors.colors
|
||||
colorsArray = [colors.1.cgColor, colors.0.cgColor]
|
||||
} else {
|
||||
colorsArray = grayscaleColors
|
||||
}
|
||||
} else {
|
||||
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count]
|
||||
}
|
||||
|
||||
var locations: [CGFloat] = [1.0, 0.0]
|
||||
@@ -636,9 +706,9 @@ public func drawPeerAvatarLetters(context: CGContext, size: CGSize, round: Bool
|
||||
|
||||
let colorsArray: NSArray
|
||||
if colorIndex == -1 {
|
||||
colorsArray = grayscaleColors
|
||||
colorsArray = grayscaleColors.map(\.cgColor) as NSArray
|
||||
} else {
|
||||
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count]
|
||||
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count].map(\.cgColor) as NSArray
|
||||
}
|
||||
|
||||
var locations: [CGFloat] = [1.0, 0.0]
|
||||
@@ -707,9 +777,9 @@ public func generateAvatarImage(size: CGSize, icon: UIImage?, iconScale: CGFloat
|
||||
|
||||
let colorsArray: NSArray
|
||||
if colorIndex == -1 {
|
||||
colorsArray = grayscaleColors
|
||||
colorsArray = grayscaleColors.map(\.cgColor) as NSArray
|
||||
} else {
|
||||
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count]
|
||||
colorsArray = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count].map(\.cgColor) as NSArray
|
||||
}
|
||||
|
||||
var locations: [CGFloat] = [1.0, 0.0]
|
||||
@@ -734,3 +804,190 @@ public func generateAvatarImage(size: CGSize, icon: UIImage?, iconScale: CGFloat
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public final class AvatarBadgeView: UIImageView {
|
||||
enum OriginalContent: Equatable {
|
||||
case color(UIColor)
|
||||
case image(UIImage)
|
||||
|
||||
static func ==(lhs: OriginalContent, rhs: OriginalContent) -> Bool {
|
||||
switch lhs {
|
||||
case let .color(color):
|
||||
if case .color(color) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .image(lhsImage):
|
||||
if case let .image(rhsImage) = rhs {
|
||||
return lhsImage === rhsImage
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct Parameters: Equatable {
|
||||
var size: CGSize
|
||||
var text: String
|
||||
}
|
||||
|
||||
private var originalContent: OriginalContent?
|
||||
private var parameters: Parameters?
|
||||
|
||||
override public init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func update(content: OriginalContent) {
|
||||
if self.originalContent != content {
|
||||
self.originalContent = content
|
||||
self.update()
|
||||
}
|
||||
}
|
||||
|
||||
public func update(size: CGSize, text: String) {
|
||||
let parameters = Parameters(size: size, text: text)
|
||||
if self.parameters != parameters {
|
||||
self.parameters = parameters
|
||||
self.update()
|
||||
}
|
||||
}
|
||||
|
||||
private func update() {
|
||||
guard let originalContent = self.originalContent, let parameters = self.parameters else {
|
||||
return
|
||||
}
|
||||
|
||||
let blurredWidth = 16
|
||||
let blurredHeight = 16
|
||||
guard let blurredContext = DrawingContext(size: CGSize(width: CGFloat(blurredWidth), height: CGFloat(blurredHeight)), scale: 1.0, opaque: true) else {
|
||||
return
|
||||
}
|
||||
let blurredSize = CGSize(width: CGFloat(blurredWidth), height: CGFloat(blurredHeight))
|
||||
blurredContext.withContext { c in
|
||||
switch originalContent {
|
||||
case let .color(color):
|
||||
c.setFillColor(color.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(), size: blurredSize))
|
||||
case let .image(image):
|
||||
c.scaleBy(x: blurredSize.width / parameters.size.width, y: blurredSize.height / parameters.size.height)
|
||||
let offsetFactor: CGFloat = 1.0 - 0.7071
|
||||
let imageFrame = CGRect(origin: CGPoint(x: parameters.size.width - image.size.width + offsetFactor * parameters.size.width, y: parameters.size.height - image.size.height + offsetFactor * parameters.size.height), size: image.size)
|
||||
|
||||
UIGraphicsPushContext(c)
|
||||
image.draw(in: imageFrame)
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
}
|
||||
|
||||
var destinationBuffer = vImage_Buffer()
|
||||
destinationBuffer.width = UInt(blurredWidth)
|
||||
destinationBuffer.height = UInt(blurredHeight)
|
||||
destinationBuffer.data = blurredContext.bytes
|
||||
destinationBuffer.rowBytes = blurredContext.bytesPerRow
|
||||
|
||||
vImageBoxConvolve_ARGB8888(
|
||||
&destinationBuffer,
|
||||
&destinationBuffer,
|
||||
nil,
|
||||
0, 0,
|
||||
UInt32(15),
|
||||
UInt32(15),
|
||||
nil,
|
||||
vImage_Flags(kvImageEdgeExtend)
|
||||
)
|
||||
|
||||
let divisor: Int32 = 0x1000
|
||||
|
||||
let rwgt: CGFloat = 0.3086
|
||||
let gwgt: CGFloat = 0.6094
|
||||
let bwgt: CGFloat = 0.0820
|
||||
|
||||
let adjustSaturation: CGFloat = 1.9
|
||||
|
||||
let a = (1.0 - adjustSaturation) * rwgt + adjustSaturation
|
||||
let b = (1.0 - adjustSaturation) * rwgt
|
||||
let c = (1.0 - adjustSaturation) * rwgt
|
||||
let d = (1.0 - adjustSaturation) * gwgt
|
||||
let e = (1.0 - adjustSaturation) * gwgt + adjustSaturation
|
||||
let f = (1.0 - adjustSaturation) * gwgt
|
||||
let g = (1.0 - adjustSaturation) * bwgt
|
||||
let h = (1.0 - adjustSaturation) * bwgt
|
||||
let i = (1.0 - adjustSaturation) * bwgt + adjustSaturation
|
||||
|
||||
let satMatrix: [CGFloat] = [
|
||||
a, b, c, 0,
|
||||
d, e, f, 0,
|
||||
g, h, i, 0,
|
||||
0, 0, 0, 1
|
||||
]
|
||||
|
||||
var matrix: [Int16] = satMatrix.map { value in
|
||||
return Int16(value * CGFloat(divisor))
|
||||
}
|
||||
|
||||
vImageMatrixMultiply_ARGB8888(&destinationBuffer, &destinationBuffer, &matrix, divisor, nil, nil, vImage_Flags(kvImageDoNotTile))
|
||||
|
||||
guard let blurredImage = blurredContext.generateImage() else {
|
||||
return
|
||||
}
|
||||
|
||||
self.image = generateImage(parameters.size, rotatedContext: { size, context in
|
||||
UIGraphicsPushContext(context)
|
||||
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setBlendMode(.copy)
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setBlendMode(.sourceIn)
|
||||
|
||||
blurredImage.draw(in: CGRect(origin: CGPoint(), size: size), blendMode: .sourceIn, alpha: 1.0)
|
||||
|
||||
context.setBlendMode(.normal)
|
||||
|
||||
context.setFillColor(UIColor(white: 0.0, alpha: 0.05).cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
let string = NSAttributedString(string: parameters.text, font: Font.bold(floor(parameters.size.height * 0.48)), textColor: .white)
|
||||
let stringBounds = string.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil)
|
||||
string.draw(at: CGPoint(x: stringBounds.minX + floorToScreenPixels((size.width - stringBounds.width) / 2.0), y: stringBounds.minY + floorToScreenPixels((size.height - stringBounds.height) / 2.0)))
|
||||
|
||||
let lineWidth: CGFloat = 1.5
|
||||
let lineInset: CGFloat = 2.0
|
||||
let lineRadius: CGFloat = size.width * 0.5 - lineInset - lineWidth * 0.5
|
||||
context.setLineWidth(lineWidth)
|
||||
context.setStrokeColor(UIColor.white.cgColor)
|
||||
context.setLineCap(.round)
|
||||
|
||||
context.addArc(center: CGPoint(x: size.width * 0.5, y: size.height * 0.5), radius: lineRadius, startAngle: CGFloat.pi * 0.5, endAngle: -CGFloat.pi * 0.5, clockwise: false)
|
||||
context.strokePath()
|
||||
|
||||
|
||||
let sectionAngle: CGFloat = CGFloat.pi / 11.0
|
||||
|
||||
for i in 0 ..< 10 {
|
||||
if i % 2 == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
let startAngle = CGFloat.pi * 0.5 - CGFloat(i) * sectionAngle - sectionAngle * 0.1
|
||||
let endAngle = startAngle - sectionAngle * 0.8
|
||||
|
||||
context.addArc(center: CGPoint(x: size.width * 0.5, y: size.height * 0.5), radius: lineRadius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
|
||||
context.strokePath()
|
||||
}
|
||||
|
||||
//context.strokeEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 2.0 + lineWidth * 0.5, dy: 2.0 + lineWidth * 0.5))
|
||||
|
||||
UIGraphicsPopContext()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user