It would be nice to have the ability to see if the image has already been cached to disk and/or memory. A simple call like
Fresco.existsInDiskCache(Uri uri) and Fresco.existsInMemoryCache(Uri uri)
Maybe a separate request but related is the ability to retrieve the cached resource from disk. The use case being that after we have retrieved the image the app may have a feature that allows the user to share the image. If we could access the local uri of the cached image then we can pass it to share intent.
May I ask why do you need to know whether the image is cached or not? I think in most cases this is not what you really need. I mean, this information on its own is useless, what's important is what do you intend to do after you would find out whether the image is cached or not.
For the second question, this is already possible. You can submit image request to the pipeline and the pipeline will return you the image. You can request encoded bytes (usually the bytes of the JPEG image) or decoded image (usually the Bitamp). In both cases you can tell the pipeline how deep it is allowed to go to satisfy your request. There are 4 levels: BITMAP_MEMORY_CACHE, ENCODED_MEMORY_CACHE, DISK_CACHE and FULL_FETCH.
So, if you ask pipeline for an encoded image, and specify DISK_CACHE with ImageRequestBuilder.setLowestPermittedRequestLevel, the pipeline will return you the JPEG bytes if the image is found anywhere up to disk cache, or null if the image is not found and a full-fetch would have to be performed.
Then, when the pipeline returns you the image bytes, save them to some temporary file and use that file.
We can't/won't expose the real file name in disk cache because:
The reason you may want to know if the image is in the cache or not is to be able to present to the user a status of how available the app is for offline use. For example, if you have a photo gallery of 80 images pulled from remotes urls it would be useful to display to the user that they have 65 images of 80 cached locally so they can view them even when they are not connected to a network. Of course they would be able to see that in the photogallery but that may be after the fact.
Another similar case is giving the user the ability to tap a button to download all images which prompts a sync adapter to pull the 80 images using your prefetching capability. We can easily do that part but we lose the ability to show the user that all of the images were successfully retrieved and not subsequently purged from the cache. Instead of having a callback and creating a data store recording which images are downloaded to have another view show progress (and which would later be out of date if the certain images were cleared from the cache). We could have a view check to see which images were in the cache and display the progress to the user.
There is value in knowing whether an image is present in the disk cache and thus persistable. It is also completely understood why you don't want to expose the file name per se and it sounds like that is not needed because we can use the method you propose above. However, knowing whether the image is is in the disk cache would be very useful. Maybe something you want to think about is making a flag on certain items so they will not be removed unless a hard flush of the cache is performed.
Alright, it shouldn't be hard to add isCached methods.
I have different size of image, when user click thumb image , it will be displaying huge images (it can be 15000px * 2000px), includes pinch to zoom, panning, rotation and animation support. So it can not be encoded, I need to just download it , get image path , use webview or SubsamplingScaleImageView to show . Use also can save the image to designated location
@leelei Fresco was not built with that big images in mind.
That's why I just need to download , get image path
@plamenko , I'm trying to do something similar to what you described in your first response as my use case is sharing the downloaded image, but because the getResult method is async, I'm getting null back immediately. I'm not seeing an easy way to get a handle on a stream to write to a temporary file. Can you please advise on how to get a stream/bytes/uri of the original file so I can store it to a temp location?
DataSource<CloseableReference<PooledByteBuffer>> dataSource = Fresco.getImagePipeline().fetchEncodedImage(ImageRequest.fromUri(imageUri), getActivity());
try {
CloseableReference<PooledByteBuffer> bytes = dataSource.getResult();
if (bytes != null) {
try {
PooledByteBuffer pooledByteBuffer = bytes.get();
File tempFile = File.createTempFile("t", "jpg");
CommonIOUtil.writeToFile(tempFile, pooledByteBuffer.getStream());
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(tempFile), animatable != null ? "image/gif" : "image/*");
getActivity().startActivity(intent);
} catch (IOException e) {
e.printStackTrace();
} finally {
CloseableReference.closeSafely(bytes);
}
}
} finally {
dataSource.close();
}
You need to subscribe to the datasource. See http://frescolib.org/docs/datasources-datasubscribers.html#_
Any updates on this issue? Do you have an idea of when the calls might be implemented?
ImageRequest imageRequest=ImageRequest.fromUri(uriString);
CacheKey cacheKey=DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(imageRequest);
BinaryResource resource = ImagePipelineFactory.getInstance().getMainDiskStorageCache().getResource(cacheKey);
File file=((FileBinaryResource)resource).getFile();
Log.i("TAG", file.getName());
Added in 0.7.0.
Hi,
Could someone please post sample code on how this task can be accomplished in 0.7.0 or above? I'm struggling to find the correct method to call to accomplish this.
Thanks!
public static boolean isImageDownloaded(Uri loadUri) {
if (loadUri == null) {
return false;
}
CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(loadUri));
return ImagePipelineFactory.getInstance().getMainDiskStorageCache().hasKey(cacheKey) || ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache().hasKey(cacheKey);
}
//return file or null
public static File getCachedImageOnDisk(Uri loadUri) {
File localFile = null;
if (loadUri != null) {
CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(loadUri));
if (ImagePipelineFactory.getInstance().getMainDiskStorageCache().hasKey(cacheKey)) {
BinaryResource resource = ImagePipelineFactory.getInstance().getMainDiskStorageCache().getResource(cacheKey);
localFile = ((FileBinaryResource) resource).getFile();
} else if (ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache().hasKey(cacheKey)) {
BinaryResource resource = ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache().getResource(cacheKey);
localFile = ((FileBinaryResource) resource).getFile();
}
}
return localFile;
}
@danhantao
fun getBitmap(uri: Uri, listener: OnBitmapFetchedListener) {
val request = ImageRequest.fromUri(uri)
val imagePipeline = Fresco.getImagePipeline()
val dataSource = imagePipeline.fetchEncodedImage(request, null)
val dataSubscriber = object : BaseDataSubscriber<CloseableReference<PooledByteBuffer>>() {
override fun onNewResultImpl(closeableReferenceDataSource: DataSource<CloseableReference<PooledByteBuffer>>) {
val imageReference = closeableReferenceDataSource.result
if (imageReference != null) {
try {
val image = imageReference.clone().get()
val inputStream = PooledByteBufferInputStream(image)
val imageFormat = ImageFormatChecker.getImageFormat(inputStream)
val bitmap = BitmapFactory.decodeStream(inputStream)
} catch (e: IOException) {
Log.e("ImageUtil", "error:$e")
} finally {
imageReference.close()
}
}
}
override fun onFailureImpl(closeableReferenceDataSource: DataSource<CloseableReference<PooledByteBuffer>>) {
Log.e("ImageUtil", "fail")
}
}
I'm using fetchEncodedImage to get the bitmap of a local file:
file:///storage/emulated/0/Download/Photo/1358684280697_kmh49z.gif
but it always goes the onFailureImpl(), I don't know why.
Most helpful comment
@danhantao