Fix hitches due to AttachmentView not using pre-prepared images
This commit is contained in:
parent
6f18d46037
commit
2d8e2f0824
|
@ -9,7 +9,7 @@
|
|||
import UIKit
|
||||
|
||||
struct ImageGrayscalifier {
|
||||
static let queue = DispatchQueue(label: "ImageGrayscalifier", qos: .default)
|
||||
static let queue = DispatchQueue(label: "ImageGrayscalifier", qos: .userInitiated)
|
||||
|
||||
private static let context = CIContext()
|
||||
private static let cache = NSCache<NSURL, UIImage>()
|
||||
|
@ -24,6 +24,17 @@ struct ImageGrayscalifier {
|
|||
}
|
||||
}
|
||||
|
||||
static func convert(url: URL?, image: UIImage) -> UIImage? {
|
||||
if let url,
|
||||
let cached = cache.object(forKey: url as NSURL) {
|
||||
return cached
|
||||
}
|
||||
guard let cgImage = image.cgImage else {
|
||||
return nil
|
||||
}
|
||||
return doConvert(CIImage(cgImage: cgImage), url: url)
|
||||
}
|
||||
|
||||
static func convert(url: URL?, data: Data) -> UIImage? {
|
||||
if let url = url,
|
||||
let cached = cache.object(forKey: url as NSURL) {
|
||||
|
|
|
@ -75,10 +75,8 @@ class AttachmentView: GIFImageView {
|
|||
gifPlaybackModeChanged()
|
||||
|
||||
if isGrayscale != Preferences.shared.grayscaleImages {
|
||||
ImageGrayscalifier.queue.async {
|
||||
self.displayImage()
|
||||
}
|
||||
}
|
||||
|
||||
if getBadges().isEmpty != Preferences.shared.showAttachmentBadges {
|
||||
createBadgesView(getBadges())
|
||||
|
@ -189,53 +187,59 @@ class AttachmentView: GIFImageView {
|
|||
|
||||
func loadImage() {
|
||||
let attachmentURL = attachment.url
|
||||
attachmentRequest = ImageCache.attachments.get(attachmentURL) { [weak self] (data, _) in
|
||||
guard let self = self, let data = data else { return }
|
||||
attachmentRequest = ImageCache.attachments.get(attachmentURL) { [weak self] (data, image) in
|
||||
guard let self = self,
|
||||
self.attachment.url == attachmentURL else {
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.attachmentRequest = nil
|
||||
}
|
||||
if self.attachment.url.pathExtension == "gif" {
|
||||
self.source = .gifData(attachmentURL, data)
|
||||
let controller = GIFController(gifData: data)
|
||||
DispatchQueue.main.async {
|
||||
controller.attach(to: self)
|
||||
|
||||
if attachmentURL.pathExtension == "gif",
|
||||
let data {
|
||||
self.source = .gifData(attachmentURL, data, image)
|
||||
if self.autoplayGifs {
|
||||
let controller = GIFController(gifData: data)
|
||||
controller.attach(to: self)
|
||||
controller.startAnimating()
|
||||
}
|
||||
}
|
||||
|
||||
if !self.autoplayGifs {
|
||||
self.displayImage()
|
||||
}
|
||||
|
||||
} else {
|
||||
self.source = .imageData(attachmentURL, data)
|
||||
self.displayImage()
|
||||
}
|
||||
} else if let image {
|
||||
self.source = .image(attachmentURL, image)
|
||||
self.displayImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loadVideo() {
|
||||
if let previewURL = self.attachment.previewURL {
|
||||
attachmentRequest = ImageCache.attachments.get(previewURL, completion: { [weak self] (data, _ )in
|
||||
guard let self = self, let data = data else { return }
|
||||
attachmentRequest = ImageCache.attachments.get(previewURL, completion: { [weak self] (_, image) in
|
||||
guard let self, let image else { return }
|
||||
DispatchQueue.main.async {
|
||||
self.attachmentRequest = nil
|
||||
self.source = .imageData(previewURL, data)
|
||||
self.source = .image(previewURL, image)
|
||||
self.displayImage()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
let attachmentURL = self.attachment.url
|
||||
AttachmentView.queue.async {
|
||||
AttachmentView.queue.async { [weak self] in
|
||||
let asset = AVURLAsset(url: attachmentURL)
|
||||
let generator = AVAssetImageGenerator(asset: asset)
|
||||
generator.appliesPreferredTrackTransform = true
|
||||
guard let image = try? generator.copyCGImage(at: .zero, actualTime: nil) else { return }
|
||||
self.source = .cgImage(attachmentURL, image)
|
||||
UIImage(cgImage: image).prepareForDisplay { [weak self] image in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self, let image else { return }
|
||||
self.source = .image(attachmentURL, image)
|
||||
self.displayImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let playImageView = UIImageView(image: UIImage(systemName: "play.circle.fill"))
|
||||
playImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
@ -276,9 +280,11 @@ class AttachmentView: GIFImageView {
|
|||
let generator = AVAssetImageGenerator(asset: asset)
|
||||
generator.appliesPreferredTrackTransform = true
|
||||
guard let image = try? generator.copyCGImage(at: .zero, actualTime: nil) else { return }
|
||||
DispatchQueue.main.async {
|
||||
self.source = .cgImage(attachmentURL, image)
|
||||
self.displayImage()
|
||||
}
|
||||
}
|
||||
|
||||
let gifvView = GifvAttachmentView(asset: asset, gravity: .resizeAspectFill)
|
||||
self.gifvView = gifvView
|
||||
|
@ -295,33 +301,51 @@ class AttachmentView: GIFImageView {
|
|||
])
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func displayImage() {
|
||||
isGrayscale = Preferences.shared.grayscaleImages
|
||||
|
||||
let image: UIImage?
|
||||
|
||||
switch source {
|
||||
case nil:
|
||||
image = nil
|
||||
self.image = nil
|
||||
|
||||
case let .imageData(url, data), let .gifData(url, data):
|
||||
case let .image(url, sourceImage):
|
||||
if isGrayscale {
|
||||
image = ImageGrayscalifier.convert(url: url, data: data)
|
||||
ImageGrayscalifier.queue.async { [weak self] in
|
||||
let grayscale = ImageGrayscalifier.convert(url: url, image: sourceImage)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.image = grayscale
|
||||
}
|
||||
}
|
||||
} else {
|
||||
image = UIImage(data: data)
|
||||
self.image = sourceImage
|
||||
}
|
||||
|
||||
case let .gifData(url, _, sourceImage):
|
||||
if isGrayscale,
|
||||
let sourceImage {
|
||||
ImageGrayscalifier.queue.async { [weak self] in
|
||||
let grayscale = ImageGrayscalifier.convert(url: url, image: sourceImage)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.image = grayscale
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.image = sourceImage
|
||||
}
|
||||
|
||||
case let .cgImage(url, cgImage):
|
||||
if isGrayscale {
|
||||
image = ImageGrayscalifier.convert(url: url, cgImage: cgImage)
|
||||
ImageGrayscalifier.queue.async { [weak self] in
|
||||
let grayscale = ImageGrayscalifier.convert(url: url, cgImage: cgImage)
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.image = grayscale
|
||||
}
|
||||
}
|
||||
} else {
|
||||
image = UIImage(cgImage: cgImage)
|
||||
}
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.image = image
|
||||
}
|
||||
}
|
||||
|
||||
private func createBadgesView(_ badges: Badges) {
|
||||
|
@ -409,8 +433,8 @@ class AttachmentView: GIFImageView {
|
|||
|
||||
fileprivate extension AttachmentView {
|
||||
enum Source {
|
||||
case imageData(URL, Data)
|
||||
case gifData(URL, Data)
|
||||
case image(URL, UIImage)
|
||||
case gifData(URL, Data, UIImage?)
|
||||
case cgImage(URL, CGImage)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue