简体   繁体   中英

Glide - Save GIF to File

Sidenote - although some of my examples are in Kotlin, answers in either Java or Kotlin are helpful.

I'm creating a GIF keyboard using the Commit Content API . To do this, I need to be able to create .gif files.

I'm using Glide to fetch the images from the internet and display them in a list inside of a recyclerview .

For each image Glide downloads, I have to create a File object with the data of that image.

I see two methods that could accomplish this objective.

1] Create a listener that overrides onResourceReady like so. The problem with this method is that I don't know how to convert a GifDrawable to a .gif file because all the Stack Overflow posts talk about how to convert a Drawable to a file:

    Glide.with(context)
            .asGif()
            .load(items[position])
            .listener(object : RequestListener<GifDrawable> {
                override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<GifDrawable>?, isFirstResource: Boolean): Boolean {
                    Log.d("VED-APP","Glide Load Failed")
                    return false
                }

                override fun onResourceReady(resource: GifDrawable?, model: Any?, target: Target<GifDrawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                    //I need code to convert the GifDrawable to a File

                    return false
                }

            })
            .into(holder.imageView)

2] Load the image to a ByteArray or something similar. Example Java code, taken from the post Glide - download and resize GIF into a file , could look like this. The problem with this code is that

A] .into(width,height) is deprecated

B] there is no .toBytes method

C] I don't want to specify the dimensions of my GIF - I'd just like to use the original size. (Or, at the very least, I'd like to preserve the aspect ratio)

byte[] bytes = Glide.with(context)
                    .load(items[position])
                    .asGif()
                    .toBytes()
                    .into(250, 250)
                    .get();
file = new File(fileName);

FileOutputStream fileWriter = new FileOutputStream(file);
fileWriter.write(bytes);
fileWriter.flush();
fileWriter.close();

Can someone help me improve either of these two methods, or suggest a new way to convert a GIF to a file with Glide?

Update @Nhật Tôn's solution is probably better if you just need the URI for the content comit API.

I don't know if @Nhật Tôn's solution works. But, this is the solution I am using right now, which is based off of their solution. My solution is in Kotlin, but it can be easily converted to Java.

First, I load the image into the ImageView with the following code:

//items[position] is a string that represents a URL
Glide.with(context)
        .load(items[position])
        .into(holder.imageView)

Then I fetch the GifDrawable from the ImageView and write it to a File object.

val byteBuffer = (holder.imageView.drawable as GifDrawable).buffer
val gifFile = File(localDirectory, "test.gif")

val output = FileOutputStream(gifFile)
val bytes = ByteArray(byteBuffer.capacity())
(byteBuffer.duplicate().clear() as ByteBuffer).get(bytes)
output.write(bytes, 0 ,bytes.size)
output.close()

A potential problem with this solution is that the GifDrawable could be modified while it is being written to a file.

A fix to this is cloning the GifDrawable like so before writing it to a file:

val newGifDrawable = ((holder.imageView.drawable).constantState.newDrawable().mutate()) as GifDrawable

If you don't have to save all the gifs in one specific location and/or have to named the gif, I suggest you just use the gifs that Glide automatically cached for you.

So firstly, in your OnBindViewHolder method, just load the gif to your imageview as normal:

Glide.with(this)
            .load(items[position])
            .apply(new RequestOptions()
                    // This is to cache all versions of the gif, whether low-res or original size
                    .diskCacheStrategy(DiskCacheStrategy.ALL))
            .into(holder.imageView);

And use this method to get the uri anywhere you want:

Glide.with(this)
            // Actually it won't download another time if the file has been cached
            .download(items[position])
            .listener(new RequestListener<File>() {
                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<File> target, boolean isFirstResource) {
                    return false;
                }

                @Override
                public boolean onResourceReady(File resource, Object model, Target<File> target, DataSource dataSource, boolean isFirstResource) {
                    //Use this uri for the Commit Content API
                    Uri uri = Uri.fromFile(resource);
                    return false;
                }
            })
            .submit();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM