Thursday, 30 August 2018

Using Glide, how can I go over each frame of GifDrawable, as Bitmap?

Background

In a live wallpaper, I have a Canvas instance that I wish to draw GIF/WEBP content into, which was loaded via Glide.

The problem

Glide seems to be optimized to work only with normal UI (Views). It has some basic functions, but the most important ones for what I'm trying to do seems to be private.

What I've found

I use official Glide library for GIF loading, and GlideWebpDecoder for WEBP loading.

The basic call to load each of those, is as such:

GIF:

    GlideApp.with(this).asGif()
            .load("https://res.cloudinary.com/demo/image/upload/bored_animation.gif")
            .into(object : SimpleTarget<GifDrawable>() {
                override fun onResourceReady(resource: GifDrawable, transition: Transition<in GifDrawable>?) {
                    //example of usage:
                    imageView.setImageDrawable(resource)
                    resource.start()
                }
            })

WEBP:

        GlideApp.with(this).asDrawable()
                .load("https://res.cloudinary.com/demo/image/upload/fl_awebp/bored_animation.webp")
//                .optionalTransform(WebpDrawable::class.java, WebpDrawableTransformation(CircleCrop()))
                .into(object : SimpleTarget<Drawable>() {
                    override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
                        //example of usage:
                        imageView.setImageDrawable(resource)
                        if (resource is Animatable) {
                            (resource as Animatable).start()
                        }
                    }
                })

Now, remember I don't really have an ImageView, and instead I only have a Canvas, which I get via surfaceHolder.lockCanvas() call.

                    resource.callback = object : Drawable.Callback {
                        override fun invalidateDrawable(who: Drawable) {
                            Log.d("AppLog", "frame ${resource.frameIndex}/${resource.frameCount}")
                        }

                    }

However, when I try to fetch the Bitmap to be used for the current frame, I fail to find the correct function.

I tried this for example (and this is only an example, to see if it can work with canvas):

    val bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)

    ...
    resource.draw(canvas)

But it doesn't seem to draw the content into the bitmap, and I think it's because its draw function has these lines of code:

  @Override
  public void draw(@NonNull Canvas canvas) {
    if (isRecycled) {
      return;
    }

    if (applyGravity) {
      Gravity.apply(GRAVITY, getIntrinsicWidth(), getIntrinsicHeight(), getBounds(), getDestRect());
      applyGravity = false;
    }

    Bitmap currentFrame = state.frameLoader.getCurrentFrame();
    canvas.drawBitmap(currentFrame, null, getDestRect(), getPaint());
  }

Yet the getDestRect() returns a 0-sized rectangle, which I can't find how to modify : it's also private, and I don't see anything that changes it.

The questions

  1. Suppose I got the Drawable I wish to use (GIF/WEBP), how can I get each of the frames it can produce, and draw it into a canvas?

  2. Can I also set the scaling type somehow, just like on ImageView (center-crop, fit-center, center-inside...) ?

  3. Is there perhaps a better alternative to this? Maybe suppose I have a GIF/WEBP animation file, does Glide allow me to just use its decoder?



from Using Glide, how can I go over each frame of GifDrawable, as Bitmap?

No comments:

Post a Comment