Swiftgram/submodules/SettingsUI/Sources/BlurredImageNode.swift
2019-08-17 20:31:41 +03:00

135 lines
3.5 KiB
Swift

import Foundation
import UIKit
import SwiftSignalKit
import AsyncDisplayKit
import Accelerate
import ImageBlur
private class BlurLayer: CALayer {
private static let blurRadiusKey = "blurRadius"
@NSManaged var blurRadius: CGFloat
private var fromBlurRadius: CGFloat?
var presentationRadius: CGFloat {
if let radius = self.fromBlurRadius {
if let layer = presentation() {
return layer.blurRadius
} else {
return radius
}
} else {
return self.blurRadius
}
}
override class func needsDisplay(forKey key: String) -> Bool {
if key == blurRadiusKey {
return true
}
return super.needsDisplay(forKey: key)
}
open override func action(forKey event: String) -> CAAction? {
if event == BlurLayer.blurRadiusKey {
self.fromBlurRadius = nil
if let action = super.action(forKey: "opacity") as? CABasicAnimation {
self.fromBlurRadius = (presentation() ?? self).blurRadius
action.keyPath = event
action.fromValue = self.fromBlurRadius
return action
}
}
return super.action(forKey: event)
}
func draw(_ image: UIImage) {
self.contents = image.cgImage
self.contentsScale = image.scale
self.contentsGravity = .resizeAspectFill
}
func render(in context: CGContext, for layer: CALayer) {
layer.render(in: context)
}
}
class BlurView: UIView {
override class var layerClass : AnyClass {
return BlurLayer.self
}
private var blurLayer: BlurLayer {
return self.layer as! BlurLayer
}
var image: UIImage?
private let queue: Queue = {
return Queue(name: nil, qos: .userInteractive)
}()
open var blurRadius: CGFloat {
set { self.blurLayer.blurRadius = newValue }
get { return self.blurLayer.blurRadius }
}
public override init(frame: CGRect) {
super.init(frame: frame)
self.isUserInteractionEnabled = false
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.isUserInteractionEnabled = false
}
private func async(on queue: DispatchQueue, actions: @escaping () -> Void) {
queue.async(execute: actions)
}
private func sync(on queue: DispatchQueue, actions: () -> Void) {
queue.sync(execute: actions)
}
private func draw(_ image: UIImage, blurRadius: CGFloat) {
self.queue.async { [weak self] in
if let strongSelf = self, let blurredImage = blurredImage(image, radius: blurRadius) {
Queue.mainQueue().sync {
strongSelf.blurLayer.draw(blurredImage)
}
}
}
}
override func display(_ layer: CALayer) {
let blurRadius = self.blurLayer.presentationRadius
if let image = self.image {
self.draw(image, blurRadius: blurRadius)
}
}
}
final class BlurredImageNode: ASDisplayNode {
var image: UIImage? {
didSet {
self.blurView.image = self.image
self.blurView.layer.setNeedsDisplay()
}
}
var blurView: BlurView {
return (self.view as? BlurView)!
}
override init() {
super.init()
self.setViewBlock({
return BlurView()
})
}
}