Nick Cardoso
Nick Cardoso

Reputation: 21763

Is there a way to force gif loaded with Glide to be non-animated

I have a set of images, loaded via Glide.

The NSFW ones are blurred using a glide (wasabeef) bitmap transformation, however some can be animated gifs, in which case the first frame is shown blurred, and then the animation starts looping (unblurred).

The following is what I have tried and does not work:

DrawableTypeRequest<String> builder = Glide.with(mImage.getContext()).load(...);

if (entry.isNsfw()) {
    builder.asBitmap();
}

builder.diskCacheStrategy(DiskCacheStrategy.SOURCE) //it's likely none of this is relevant
    .skipMemoryCache(true)
    .override(props.getWidth(), props.getHeight());

if (entry.isNsfw()) {
    //successfully blurs nsfw images, but still allows unblurred animation
    builder.dontAnimate().bitmapTransform(centreCrop, blur);
} else {
    builder.centerCrop();
}

builder.crossFade(500) //moving crossfade only into the sfw posts has no effect
       .into(mImage);

Also not working is intercepting the load:

builder.listener(new RequestListener<String, GlideDrawable>() {
    @Override
    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
        return false;
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
        if (entry.isNsfw()) {
            target.onResourceReady(resource, null); //If I add this and return true the image is static, but unblurred
            resource.stop(); //if this is called before target, it has no effect
            return true;
        }
        return false; //returning true without calling the target stops any of the images being set on the view
    }
});

How can I turn off the gif playback for individual images while still keeping the blur transformation?

Upvotes: 2

Views: 2858

Answers (2)

Nick Cardoso
Nick Cardoso

Reputation: 21763

In the end mixing a few of the steps I outlined in my question, fixed the issue. Animated NSFW gifs now display only the first frame, which is successfully blurred.

DrawableRequestBuilder<String> builder = Glide.with(ctx).load(...);
if (nsfw) {
    builder.bitmapTransform(new BlurTransformation(ctx, 8, 16), new CentreCrop(...));
} else {
    builder.centerCrop();
}
builder.listener(new RequestListener<String, GlideDrawable>() {
    ... //onException method
    @Override
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
        boolean handled = false;
        if (nsfw && resource.isAnimated()) {
            target.onResourceReady(new GlideBitmapDrawable(null, ((GifDrawable) resource).getFirstFrame()), null);
            handled = true; //glide now won't set the resource on the target itself
        }
        return handled;
    }
});
builder.crossFade(500).into(mImageView);

Upvotes: 2

Much Overflow
Much Overflow

Reputation: 3140

I have a set of images, loaded via Glide

From the above, I assume you are using RecyclerView to show these images and my answer is based on this assumption.

Try it with a custom Glide target of your own that stops the animation if NSFW like this

public class CustomTarget extends GlideDrawableImageViewTarget {

    private boolean isNSFW;

    public CustomTarget(ImageView view) {
        super(view);
    }

    public void setNSFW(boolean isNSFW){
        this.isNSFW = isNSFW;
    }

    @Override
    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {

        // this super call loads the image, sets it to the ImageView and starts
        // animating if it is Gif
        super.onResourceReady(resource, animation); 

        if(isNSFW){
            onStop(); // stop playing the animation if NSFW
        }
    }
}

And in your View Holder class, create and keep a reference to this target as you would do for other views

public class MyViewHolder extends RecyclerView.ViewHolder {

    ImageView myImageView;
    CustomTarget myCustomTarget;

    public MyViewHolder(View itemView) {
        super(itemView);
        myImageView = (ImageView) itemView.findViewById(R.id.myIv);
        myCustomTarget = new CustomTarget(myImageView);
    }
}

Then in onBindViewHolder do the following

public void onBindViewHolder(MyViewHolder holder, int position) {

    // get the current entry in your image set
    final Entry entry = entries.get(position); 

    // call this before loading the resource
    holder.myCustomTarget.setNSFW(entry.isNSFW()); 

    // No need to specify asGif()
    // Refer http://stackoverflow.com/a/34870817/3533289
    Glide.with(context)
            .load(entry.getURL())
            .into(holder.myCustomTarget);

}

I haven't tested this solution myself. But I hope it will give you an idea of how to tackle this issue.

Upvotes: 0

Related Questions