damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

KFImageModel.swift (3745B)


      1 //
      2 //  KFImageModel.swift
      3 //  damus
      4 //
      5 //  Created by Oleg Abalonski on 1/11/23.
      6 //
      7 
      8 import UIKit
      9 import Kingfisher
     10 
     11 class KFImageModel: ObservableObject {
     12     
     13     let url: URL?
     14     let fallbackUrl: URL?
     15     let processor: ImageProcessor
     16     let serializer: CacheSerializer
     17     
     18     @Published var refreshID = ""
     19     
     20     init(url: URL?, fallbackUrl: URL?, maxByteSize: Int, downsampleSize: CGSize) {
     21         self.url = url
     22         self.fallbackUrl = fallbackUrl
     23         self.processor = CustomImageProcessor(maxSize: maxByteSize, downsampleSize: downsampleSize)
     24         self.serializer = CustomCacheSerializer(maxSize: maxByteSize, downsampleSize: downsampleSize)
     25     }
     26     
     27     func refresh() -> Void {
     28         DispatchQueue.main.async {
     29             self.refreshID = UUID().uuidString
     30         }
     31     }
     32     
     33     func cache(_ image: UIImage, forKey key: String) -> Void {
     34         KingfisherManager.shared.cache.store(image, forKey: key, processorIdentifier: processor.identifier) { _ in
     35             self.refresh()
     36         }
     37     }
     38     
     39     func downloadFailed() -> Void {
     40         guard let url = url, let fallbackUrl = fallbackUrl else { return }
     41         
     42         DispatchQueue.global(qos: .background).async {
     43             KingfisherManager.shared.downloader.downloadImage(with: fallbackUrl) { result in
     44                 
     45                 var fallbackImage: UIImage {
     46                     switch result {
     47                     case .success(let imageLoadingResult):
     48                         return imageLoadingResult.image
     49                     case .failure(let error):
     50                         print(error)
     51                         return UIImage()
     52                     }
     53                 }
     54                 
     55                 self.cache(fallbackImage, forKey: url.absoluteString)
     56             }
     57         }
     58     }
     59 }
     60 
     61 struct CustomImageProcessor: ImageProcessor {
     62     
     63     let maxSize: Int
     64     let downsampleSize: CGSize
     65     
     66     let identifier = "com.damus.customimageprocessor"
     67     
     68     func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
     69         
     70         switch item {
     71         case .image(_):
     72             // This case will never run
     73             return DefaultImageProcessor.default.process(item: item, options: options)
     74         case .data(let data):
     75             
     76             // Handle large image size
     77             if data.count > maxSize {
     78                 return KingfisherWrapper.downsampledImage(data: data, to: downsampleSize, scale: options.scaleFactor)
     79             }
     80             
     81             // Handle SVG image
     82             if let dataString = String(data: data, encoding: .utf8),
     83                 let svg = SVG(dataString) {
     84                 
     85                     let render = UIGraphicsImageRenderer(size: svg.size)
     86                     let image = render.image { context in
     87                         svg.draw(in: context.cgContext)
     88                     }
     89 
     90                     return image.kf.scaled(to: options.scaleFactor)
     91             }
     92             
     93             return DefaultImageProcessor.default.process(item: item, options: options)
     94         }
     95     }
     96 }
     97 
     98 struct CustomCacheSerializer: CacheSerializer {
     99     
    100     let maxSize: Int
    101     let downsampleSize: CGSize
    102 
    103     func data(with image: Kingfisher.KFCrossPlatformImage, original: Data?) -> Data? {
    104         return DefaultCacheSerializer.default.data(with: image, original: original)
    105     }
    106 
    107     func image(with data: Data, options: Kingfisher.KingfisherParsedOptionsInfo) -> Kingfisher.KFCrossPlatformImage? {
    108         if data.count > maxSize {
    109             return KingfisherWrapper.downsampledImage(data: data, to: downsampleSize, scale: options.scaleFactor)
    110         }
    111 
    112         return DefaultCacheSerializer.default.image(with: data, options: options)
    113     }
    114 }