onevcat / Kingfisher

A lightweight, pure-Swift library for downloading and caching images from the web.
MIT License
23.4k stars 2.66k forks source link

AVIF Support #2189

Open lschaupp opened 10 months ago

lschaupp commented 10 months ago

Any news about AVIF support?

freemansion commented 6 months ago

Our project currently heavily uses Kingfisher, but we struggle loading images in AVIF format. Any plans to introduce support of AVIF? Does anybody found workaround?

onevcat commented 6 months ago

Hi,

As I tried, it seems that the default image processor is already supporting AVIF with UIImageView extension, so I guess you can just give the URL of an AVIF image to Kingfisher and it should just work. See the example in action:

截屏2024-04-30 19 30 21

As I tried under iOS 16 and iOS 17, both seems working fine.

Do you have a case (maybe any earlier iOS versions?) that it does not work?


If the default one does not work in some cases, it is still very easy to integrating any existing AVIF decoder to Kingfisher. Take the avif.swift as example, after importing, you can add these to your project to load an AVIF image:

struct KingfisherAVIFProcessor: ImageProcessor {
    var identifier: String = "KingfisherAVIF"

    func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
        switch item {
        case .data(let data):
            return AVIFDecoder.decode(data)
        case .image(let image):
            return image
        }
    }
}

struct KingfisherAVIFSerializer: CacheSerializer {
    func data(with image: Kingfisher.KFCrossPlatformImage, original: Data?) -> Data? {
        return try? AVIFEncoder.encode(image: image, quality: 50)
    }

    func image(with data: Data, options: Kingfisher.KingfisherParsedOptionsInfo) -> Kingfisher.KFCrossPlatformImage? {
        return AVIFDecoder.decode(data)
    }
}

And use it as:

imageView.kf.setImage(
  with: url, 
  options: [
    .processor(KingfisherAVIFProcessor()), 
    .cacheSerializer(KingfisherAVIFSerializer())
  ]
)
freemansion commented 6 months ago

hey @onevcat , thanks for the quick reply! You're right, it works fine in most cases. I forgot to mention, that it doesn't works on iOS 15. I've checked on iPhone 13 mini, iOS 15.4. But anyway, thanks a lot sharing a workaround, much appreciated!

onevcat commented 6 months ago

thanks for the quick reply! You're right, it works fine in most cases. I forgot to mention, that it doesn't works on iOS 15. I've checked on iPhone 13 mini, iOS 15.4.

For that case, maybe I can recommend to apply the DefaultImageProcessor first, and then if it returns nil, use the method from AVIF specified decoder:

struct KingfisherAVIFProcessor: ImageProcessor {
    var identifier: String = "KingfisherAVIF"

    func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
        switch item {
        case .data(let data):
            return DefaultImageProcessor.default.process(item: item, options: options) ?? AVIFDecoder.decode(data)
        case .image(let image):
            return image
        }
    }
}

Then it is possible for you to get the system default implementation if the system can decode the image. Otherwise if for older systems, fallback to the AVIF specified decoders.

freemansion commented 6 months ago

yeah, keeping default image processor make sense. thanks for sharing thoughts!

lschaupp commented 3 months ago

What about animated AVIF? (e.g. something like GIFs)