coil-kt / coil

Image loading for Android and Compose Multiplatform.
https://coil-kt.github.io/coil/
Apache License 2.0
10.67k stars 647 forks source link

Get the image file from a preloaded image #100

Closed adrielcafe closed 2 years ago

adrielcafe commented 5 years ago

Is your feature request related to a problem? Please describe. I'm looking for a way to get the image file from a preloaded image, but seems Coil lacks this feature at the moment.

Describe the solution you'd like On Glide I do:

val preloadedImageFile = Glide
    .with(context)
    .downloadOnly()
    .load(imageUrl)
    .submit()
    .get()

Would be nice if we have at least one of these options in Coil:

Coil.getFile(imageUrl)

Coil.load(context, imageUrl) {
    target(object : FileTarget {
        override fun onSuccess(result: File) {

        }
    })
}
colinrtwhite commented 4 years ago

Hmm I'm not sure it makes sense to add this to Coil. Coil is intentionally built to only support Drawables as the result of loading an image. Most load operations don't have a file we can return (Uris, resources, bitmaps). Also, since Coil is backed by OkHttp isn't not possible to get access to the underlying disk cache.

DeepPSingh commented 4 years ago

Hi @colinrtwhite I am also looking for something similar. My use case is if image gets deleted from server then I need to delete just that image from device local cache. But currently I can't find a way to just fetch that particular image from cache.

Is there a way we can check if an image is already cached or not? Does Coil supports deleting selected file from cache? If yes then how can I achieve it?

colinrtwhite commented 4 years ago

@DeepPSingh Coil relies on OkHttp for its disk cache. Unfortunately, the cache isn't set up for easy access, however you could probably access its files using Cache.urls() and Cache.key(). That'll let you iterate over the current files in the disk cache. You can get the default Coil Cache instance using CoilUtils.createDefaultCache.

colinrtwhite commented 4 years ago

Closing this since I don't think this is likely to be added for 1.0 as it would require reworking Targets.

onlymash commented 4 years ago
glide.downloadOnly().load(url)
    .into(object : CustomTarget<File>() {
         override fun onLoadCleared(placeholder: Drawable?) {}
         override fun onResourceReady(
            resource: File,
            transition: Transition<in File>?) {
            subsamplingScaleImageView.setImage(ImageSource.uri(resource.toUri()))
       }
     })

I need it too. SubsamplingScaleImageView can display large image without compression. Users can also save image from the cache to avoid downloading again

saket commented 3 years ago

+1 for this. Any chances this can be re-opened? Displaying large images through coil is a bit of a pain right now because libraries like SubsamplingScaleImageView only take in files instead of Drawables.

I tried accessing OkHttp's cache directly, but the code is very fragile:

val coilCache = CoilUtils.createDefaultCache(context)
val file = File(coilCache.directory, "${Cache.key(imageUrl.toHttpUrl())}.1")
colinrtwhite commented 3 years ago

Sounds good, reopening this for discussion. Now that Coil is a little more settled this is something I'd like to add to Coil, however adding it has the following challenges:

Ultimately I think we might need to add an ImageLoader.cache method that gives Coil knowledge of the cache, however that solution isn't great since the cache passed to ImageLoader.cache could be different from the actual cache used by the OkHttpClient.

Maybe we could add CoilUtils.getCacheFile(cache: Cache, url: HttpUrl): File? until we figure out a better solution?

saket commented 3 years ago

Yep, I agree that coil will need to own its cache in order to control the lifecycle of cached images. Otherwise, I imagine the files can be evicted while they're shown on the UI.

Having a nifty function that retrieves cache files would be a good stop-gap in the meantime!

colinrtwhite commented 3 years ago

It's actually fine if image files are evicted while on screen (Glide and Picasso allow this too). Once they're decoded the file can be safely evicted. If I recall correctly Glide doesn't guarantee the lifetime of the File it returns, however it does bump the returned File to the top of the LRU cache. I think if we can bump the file then we'll probably be ok since we'll have parity with Glide.

saket commented 3 years ago

Once they're decoded the file can be safely evicted

TIL.

I think if we can bump the file then we'll probably be ok since we'll have parity with Glide.

This sounds great!

mikaelzero commented 3 years ago

I tried one way

https://github.com/mikaelzero/mojito/blob/master/coilimageloader/src/main/java/net/mikaelzero/coilimageloader/CoilImageLoader.kt

brianguertin commented 3 years ago

+1 for this. Any chances this can be re-opened? Displaying large images through coil is a bit of a pain right now because libraries like SubsamplingScaleImageView only take in files instead of Drawables.

I tried accessing OkHttp's cache directly, but the code is very fragile:

val coilCache = CoilUtils.createDefaultCache(context)
val file = File(coilCache.directory, "${Cache.key(imageUrl.toHttpUrl())}.1")

I came here looking for way to use Coil with SubsamplingScaleImageView, and your solution is working for me :)

As long as the disk cache is big enough to hold everything currently on screen, i think this will be okay.

colinrtwhite commented 2 years ago

I've just published 2.0.0-alpha01 which makes the disk cache public. It's experimental and subject to change, but you can get access to the image's file like so:

context.imageLoader.diskCache?.get(url)?.use { snapshot ->
    val imageFile = snapshot.data.toFile()
    // Read or copy the file. You **must** close the snapshot (`use` closes the snapshot)
    // or it'll prevent writing to that entry until your app is killed.
}

The new disk cache also has support for editing/removing entries. Check it out!

saket commented 2 years ago

Looks good, thanks @colinrtwhite!

colinrtwhite commented 2 years ago

Closing this out as the new disk cache is available in a stable release (though marked with @ExperimentalCoilApi) in 2.0.0.

EGFireball commented 7 months ago

@colinrtwhite Hello. The project we are working on with the team I am part of has a complicated functionality with big image gallery, positioned in different Channels, which can have subchannels, the Subchannels can have their own Subchannels, etc.(F.E. You have a Picture of World Oceans, you click on it and receive big amount of Ocean pictures from different places in the World, you choose one of them and you receive more detailed collection of pictures for the given place). We would like to be able to download and store the images in Cache for Subchannels in Advance when the User opens the Parent channel and this to happen hidden from him. Glide does this by downloadOnly

Glide .with(context) .downloadOnly() .load(imageUrl) .submit() .get()

The whole point is better UX - the images not to start appearing when the user opens the page of the Gallery, rather they to already be there because they are already stored in the cache. Can you add this for future versions?