Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose Cached Files #80

Closed
shanus opened this issue Apr 3, 2015 · 15 comments
Closed

Expose Cached Files #80

shanus opened this issue Apr 3, 2015 · 15 comments

Comments

@shanus
Copy link

shanus commented Apr 3, 2015

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.

@plamenko
Copy link
Contributor

plamenko commented Apr 3, 2015

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:

  1. The image may have been found in memory cache, so there is no need to engage with disk cache at all.
  2. Disk cache may evict the file on its own discretion at any time, and therefore passing that file name around would not be safe (Even if the other app would be able to access your app's internal storage which I doubt).

@plamenko plamenko closed this as completed Apr 3, 2015
@shanus
Copy link
Author

shanus commented Apr 3, 2015

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.

@plamenko
Copy link
Contributor

plamenko commented Apr 3, 2015

Alright, it shouldn't be hard to add isCached methods.

@leelei
Copy link

leelei commented Apr 6, 2015

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

@plamenko
Copy link
Contributor

plamenko commented Apr 6, 2015

@leelei Fresco was not built with that big images in mind.

@leelei
Copy link

leelei commented Apr 7, 2015

That's why I just need to download , get image path

@vincentjames501
Copy link

@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();
}

@plamenko
Copy link
Contributor

plamenko commented Apr 8, 2015

You need to subscribe to the datasource. See http://frescolib.org/docs/datasources-datasubscribers.html#_

@plamenko plamenko changed the title Feature Request to Expose Cached Files Expose Cached Files Apr 17, 2015
@shanus
Copy link
Author

shanus commented Jul 3, 2015

Any updates on this issue? Do you have an idea of when the calls might be implemented?

@danhantao
Copy link

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());

@tyronen
Copy link
Contributor

tyronen commented Aug 27, 2015

Added in 0.7.0.

@tyronen tyronen closed this as completed Aug 27, 2015
@ThePedestrian
Copy link

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!

@krmao
Copy link

krmao commented Sep 11, 2015

 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

@AllenVork
Copy link

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.

@tyronen
Copy link
Contributor

tyronen commented May 23, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants