WinterGram/submodules/TelegramPresentationData/Sources/WinterGramBadge.swift

105 lines
4.3 KiB
Swift

import Foundation
import UIKit
import Display
import AppBundle
import TelegramCore
import TelegramUIPreferences
private let winterGramBadgeCacheLock = NSLock()
private var winterGramComposedBadgeCache: [UInt32: UIImage] = [:]
private func winterGramColorKey(_ color: UIColor) -> UInt32 {
var r: CGFloat = 0.0, g: CGFloat = 0.0, b: CGFloat = 0.0, a: CGFloat = 0.0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
func channel(_ v: CGFloat) -> UInt32 { return UInt32(max(0.0, min(1.0, v)) * 255.0) }
return (channel(r) << 16) | (channel(g) << 8) | channel(b)
}
public func winterGramComposedBadge(backplateColor: UIColor) -> UIImage? {
let key = winterGramColorKey(backplateColor)
winterGramBadgeCacheLock.lock()
if let cached = winterGramComposedBadgeCache[key] {
winterGramBadgeCacheLock.unlock()
return cached
}
winterGramBadgeCacheLock.unlock()
guard let backplate = UIImage(bundleImageName: "WntGramBackplateShape"), let snowflake = UIImage(bundleImageName: "WntGramSnowflakeShape") else {
return nil
}
let size = CGSize(width: 36.0, height: 36.0)
let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { _ in
backplate.withTintColor(backplateColor, renderingMode: .alwaysOriginal).draw(in: CGRect(origin: .zero, size: size))
let snowflakeSize = size.width * 756.0 / 1024.0
let snowflakeOffset = size.width * 134.0 / 1024.0
snowflake.withTintColor(.white, renderingMode: .alwaysOriginal).draw(in: CGRect(x: snowflakeOffset, y: snowflakeOffset, width: snowflakeSize, height: snowflakeSize))
}
winterGramBadgeCacheLock.lock()
winterGramComposedBadgeCache[key] = image
winterGramBadgeCacheLock.unlock()
return image
}
public func winterGramBadgeBackplateColor(theme: PresentationTheme) -> UIColor {
return theme.list.itemAccentColor.withMultipliedBrightnessBy(0.82)
}
private var winterGramComposedBadgeCacheV2: [String: UIImage] = [:]
private func winterGramLayerImage(source: String) -> UIImage? {
if let url = WinterGramBadgeManager.shared.localAssetFileURL(forSource: source), let image = UIImage(contentsOfFile: url.path) {
return image
}
return UIImage(bundleImageName: source)
}
public func winterGramComposedBadge(for badge: WinterGramBadgeDef, canvas: Double, themeColor: UIColor, size: CGSize) -> UIImage? {
let canvasValue = canvas > 0.0 ? canvas : 1024.0
let version = WinterGramBadgeManager.shared.manifest.version
let key = "\(badge.id)|\(version)|\(winterGramColorKey(themeColor))|\(Int(size.width))x\(Int(size.height))"
winterGramBadgeCacheLock.lock()
if let cached = winterGramComposedBadgeCacheV2[key] {
winterGramBadgeCacheLock.unlock()
return cached
}
winterGramBadgeCacheLock.unlock()
let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { _ in
for layer in badge.layers {
if layer.isLottie {
continue
}
guard let layerImage = winterGramLayerImage(source: layer.source) else {
continue
}
let rect = CGRect(
x: layer.x / canvasValue * size.width,
y: layer.y / canvasValue * size.height,
width: layer.width / canvasValue * size.width,
height: layer.height / canvasValue * size.height
)
switch layer.tint {
case .theme:
layerImage.withTintColor(themeColor, renderingMode: .alwaysOriginal).draw(in: rect)
case let .hex(value):
layerImage.withTintColor(UIColor(rgb: value), renderingMode: .alwaysOriginal).draw(in: rect)
case .original:
layerImage.draw(in: rect)
}
}
}
winterGramBadgeCacheLock.lock()
winterGramComposedBadgeCacheV2[key] = image
winterGramBadgeCacheLock.unlock()
return image
}
public func winterGramBadgeImage(for peer: EnginePeer, theme: PresentationTheme) -> UIImage? {
guard let badge = WinterGramBadgeManager.shared.badge(for: peer) else {
return nil
}
let manifest = WinterGramBadgeManager.shared.manifest
return winterGramComposedBadge(for: badge, canvas: manifest.canvas, themeColor: winterGramBadgeBackplateColor(theme: theme), size: CGSize(width: 36.0, height: 36.0))
}