All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bumptech.glide.integration.gifencoder.ReEncodingGifResourceEncoder Maven / Gradle / Ivy

There is a newer version: 5.0.0-rc01
Show newest version
package com.bumptech.glide.integration.gifencoder;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import com.bumptech.glide.gifdecoder.GifDecoder;
import com.bumptech.glide.gifdecoder.GifHeader;
import com.bumptech.glide.gifdecoder.GifHeaderParser;
import com.bumptech.glide.gifdecoder.StandardGifDecoder;
import com.bumptech.glide.gifencoder.AnimatedGifEncoder;
import com.bumptech.glide.load.EncodeStrategy;
import com.bumptech.glide.load.Option;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.UnitTransformation;
import com.bumptech.glide.load.resource.bitmap.BitmapResource;
import com.bumptech.glide.load.resource.gif.GifBitmapProvider;
import com.bumptech.glide.load.resource.gif.GifDrawable;
import com.bumptech.glide.util.ByteBufferUtil;
import com.bumptech.glide.util.LogTime;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;

/**
 * An {@link com.bumptech.glide.load.ResourceEncoder} that can write
 * {@link com.bumptech.glide.load.resource.gif.GifDrawable} to cache.
 */
public class ReEncodingGifResourceEncoder implements ResourceEncoder {

  private static final String KEY_ENCODE_TRANSFORMATION =
      "com.bumptech.glide.load.resource.gif.GifResourceEncoder.EncodeTransformation";
   /**
   * A boolean option that, if set to true, causes the fully transformed
   * GIF to be written to cache.
   *
   * 

Warning - encoding GIFs is slow and often produces larger and less efficient GIFs than * the originals. Re-encoding may be worth it to decrease the size of very large GIFs.

* *

Defaults to false.

*/ public static final Option ENCODE_TRANSFORMATION = Option.disk(KEY_ENCODE_TRANSFORMATION, false, new Option.CacheKeyUpdater() { @Override public void update(byte[] keyBytes, Boolean value, MessageDigest messageDigest) { if (value) { messageDigest.update(keyBytes); } } }); private static final Factory FACTORY = new Factory(); private static final String TAG = "GifEncoder"; private final GifDecoder.BitmapProvider provider; private Context context; private final BitmapPool bitmapPool; private final Factory factory; public ReEncodingGifResourceEncoder(Context context, BitmapPool bitmapPool) { this(context, bitmapPool, FACTORY); } // Visible for testing. ReEncodingGifResourceEncoder(Context context, BitmapPool bitmapPool, Factory factory) { this.context = context; this.bitmapPool = bitmapPool; provider = new GifBitmapProvider(bitmapPool); this.factory = factory; } @Override public EncodeStrategy getEncodeStrategy(Options options) { Boolean encodeTransformation = options.get(ENCODE_TRANSFORMATION); return encodeTransformation != null && encodeTransformation ? EncodeStrategy.TRANSFORMED : EncodeStrategy.SOURCE; } @Override public boolean encode(Resource resource, File file, Options options) { GifDrawable drawable = resource.get(); Transformation transformation = drawable.getFrameTransformation(); boolean isTransformed = !(transformation instanceof UnitTransformation); if (isTransformed && options.get(ENCODE_TRANSFORMATION)) { return encodeTransformedToFile(drawable, file); } else { return writeDataDirect(drawable.getBuffer(), file); } } private boolean encodeTransformedToFile(GifDrawable drawable, File file) { long startTime = LogTime.getLogTime(); OutputStream os = null; boolean success = false; try { os = new BufferedOutputStream(new FileOutputStream(file)); success = encodeTransformedToStream(drawable, os); os.close(); } catch (IOException e) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "Failed to encode GIF", e); } } finally { if (os != null) { try { os.close(); } catch (IOException e) { // Ignored. } } } if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Re-encoded GIF with " + drawable.getFrameCount() + " frames and " + drawable.getBuffer().limit() + " bytes in " + LogTime.getElapsedMillis(startTime) + " ms"); } return success; } private boolean encodeTransformedToStream(GifDrawable drawable, OutputStream os) { Transformation transformation = drawable.getFrameTransformation(); GifDecoder decoder = decodeHeaders(drawable.getBuffer()); AnimatedGifEncoder encoder = factory.buildEncoder(); if (!encoder.start(os)) { return false; } for (int i = 0; i < decoder.getFrameCount(); i++) { Bitmap currentFrame = decoder.getNextFrame(); Resource transformedResource = getTransformedFrame(currentFrame, transformation, drawable); try { if (!encoder.addFrame(transformedResource.get())) { return false; } int currentFrameIndex = decoder.getCurrentFrameIndex(); int delay = decoder.getDelay(currentFrameIndex); encoder.setDelay(delay); decoder.advance(); } finally { transformedResource.recycle(); } } return encoder.finish(); } private boolean writeDataDirect(ByteBuffer data, File file) { try { ByteBufferUtil.toFile(data, file); } catch (IOException e) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Failed to write GIF data", e); } return false; } return true; } private GifDecoder decodeHeaders(ByteBuffer data) { GifHeaderParser parser = factory.buildParser(); parser.setData(data); GifHeader header = parser.parseHeader(); GifDecoder decoder = factory.buildDecoder(provider); decoder.setData(header, data); decoder.advance(); return decoder; } private Resource getTransformedFrame(Bitmap currentFrame, Transformation transformation, GifDrawable drawable) { // TODO: what if current frame is null? Resource bitmapResource = factory.buildFrameResource(currentFrame, bitmapPool); Resource transformedResource = transformation.transform( context, bitmapResource, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); if (!bitmapResource.equals(transformedResource)) { bitmapResource.recycle(); } return transformedResource; } // Visible for testing. static class Factory { public GifDecoder buildDecoder(GifDecoder.BitmapProvider bitmapProvider) { return new StandardGifDecoder(bitmapProvider); } public GifHeaderParser buildParser() { return new GifHeaderParser(); } public AnimatedGifEncoder buildEncoder() { return new AnimatedGifEncoder(); } public Resource buildFrameResource(Bitmap bitmap, BitmapPool bitmapPool) { return new BitmapResource(bitmap, bitmapPool); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy