public GifFrameLoader( Glide glide, GifDecoder gifDecoder, int width, int height, Transformation<Bitmap> transformation, Bitmap firstFrame) { this( glide.getBitmapPool(), Glide.with(glide.getContext()), gifDecoder, null /*handler*/, getRequestBuilder(Glide.with(glide.getContext()), width, height), transformation, firstFrame); }
@Before public void setUp() { MockitoAnnotations.initMocks(this); gifHeader = Mockito.spy(new GifHeader()); when(parser.parseHeader()).thenReturn(gifHeader); when(parserPool.obtain(isA(ByteBuffer.class))).thenReturn(parser); when(decoderFactory.build(isA(GifDecoder.BitmapProvider.class), eq(gifHeader), isA(ByteBuffer.class), anyInt())) .thenReturn(gifDecoder); List<ImageHeaderParser> parsers = new ArrayList<ImageHeaderParser>(); parsers.add(new DefaultImageHeaderParser()); options = new Options(); decoder = new ByteBufferGifDecoder( RuntimeEnvironment.application, parsers, bitmapPool, new LruArrayPool(ARRAY_POOL_SIZE_BYTES), parserPool, decoderFactory); }
GifFrameLoader( Glide glide, GifDecoder gifDecoder, int width, int height, Transformation<Bitmap> transformation, Bitmap firstFrame) { this( glide.getBitmapPool(), Glide.with(glide.getContext()), gifDecoder, null /*handler*/, getRequestBuilder(Glide.with(glide.getContext()), width, height), transformation, firstFrame); }
/** * Constructor for GifDrawable. * * @param context A context. * @param frameTransformation An {@link com.bumptech.glide.load.Transformation} that can be * applied to each frame. * @param targetFrameWidth The desired width of the frames displayed by this drawable (the * width of the view or * {@link com.bumptech.glide.request.target.Target} * this drawable is being loaded into). * @param targetFrameHeight The desired height of the frames displayed by this drawable (the * height of the view or * {@link com.bumptech.glide.request.target.Target} * this drawable is being loaded into). * @param gifDecoder The decoder to use to decode GIF data. * @param firstFrame The decoded and transformed first frame of this GIF. * @see #setFrameTransformation(com.bumptech.glide.load.Transformation, android.graphics.Bitmap) */ public GifDrawable( Context context, GifDecoder gifDecoder, Transformation<Bitmap> frameTransformation, int targetFrameWidth, int targetFrameHeight, Bitmap firstFrame) { this( new GifState( new GifFrameLoader( // TODO(b/27524013): Factor out this call to Glide.get() Glide.get(context), gifDecoder, targetFrameWidth, targetFrameHeight, frameTransformation, firstFrame))); }
@Before public void setUp() { MockitoAnnotations.initMocks(this); gifHeader = Mockito.spy(new GifHeader()); when(parser.parseHeader()).thenReturn(gifHeader); when(parserPool.obtain(isA(ByteBuffer.class))).thenReturn(parser); when(decoderFactory.build(isA(GifDecoder.BitmapProvider.class), eq(gifHeader), isA(ByteBuffer.class), anyInt())) .thenReturn(gifDecoder); List<ImageHeaderParser> parsers = new ArrayList<>(); parsers.add(new DefaultImageHeaderParser()); options = new Options(); decoder = new ByteBufferGifDecoder( RuntimeEnvironment.application, parsers, bitmapPool, new LruArrayPool(ARRAY_POOL_SIZE_BYTES), parserPool, decoderFactory); }
@Test public void testReturnsNewDrawableFromConstantState() { Bitmap firstFrame = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); drawable = new GifDrawable( RuntimeEnvironment.application, mock(GifDecoder.class), transformation, 100, 100, firstFrame); assertNotNull(Preconditions.checkNotNull(drawable.getConstantState()).newDrawable()); assertNotNull( drawable.getConstantState().newDrawable(RuntimeEnvironment.application.getResources())); }
public GifFrameManager(Context context, GifDecoder decoder, Handler mainHandler, Transformation<Bitmap> transformation) { this.context = context; this.decoder = decoder; this.mainHandler = mainHandler; this.transformation = transformation; calculator = new MemorySizeCalculator(context); frameLoader = new GifFrameModelLoader(); frameResourceDecoder = new GifFrameResourceDecoder(); if (!decoder.isTransparent()) { // For non transparent gifs, we can beat the performance of our gif decoder for each frame by decoding jpegs // from disk. cacheDecoder = new StreamBitmapDecoder(context); encoder = new BitmapEncoder(Bitmap.CompressFormat.JPEG, 70); } else { // For transparent gifs, we would have to encode as pngs which is actually slower than our gif decoder so we // avoid writing frames to the disk cache entirely. cacheDecoder = NullCacheDecoder.get(); encoder = SkipCache.get(); } }
public void getNextFrame(FrameCallback cb) { decoder.advance(); // We don't want to blow out the entire memory cache with frames of gifs, so try to set some // maximum size beyond which we will always just decode one frame at a time. boolean skipCache = decoder.getDecodedFramesByteSizeSum() > calculator.getMemoryCacheSize() / 2; long targetTime = SystemClock.uptimeMillis() + (Math.min(MIN_FRAME_DELAY, decoder.getNextDelay())); next = new DelayTarget(decoder, cb, targetTime, mainHandler); Glide.with(context) .using(frameLoader, GifDecoder.class) .load(decoder) .as(Bitmap.class) .decoder(frameResourceDecoder) .cacheDecoder(cacheDecoder) .transform(transformation) .encoder(encoder) .skipMemoryCache(skipCache) .into(next); }
private static GenericRequestBuilder<GifDecoder, GifDecoder, Bitmap, Bitmap> getRequestBuilder(Context context, GifDecoder gifDecoder, int width, int height, BitmapPool bitmapPool) { GifFrameResourceDecoder frameResourceDecoder = new GifFrameResourceDecoder(bitmapPool); GifFrameModelLoader frameLoader = new GifFrameModelLoader(); Encoder<GifDecoder> sourceEncoder = NullEncoder.get(); return Glide.with(context) .using(frameLoader, GifDecoder.class) .load(gifDecoder) .as(Bitmap.class) .sourceEncoder(sourceEncoder) .decoder(frameResourceDecoder) .skipMemoryCache(true) .diskCacheStrategy(DiskCacheStrategy.NONE) .override(width, height); }
public GifState(GifHeader header, byte[] data, Context context, Transformation<Bitmap> frameTransformation, int targetWidth, int targetHeight, GifDecoder.BitmapProvider provider, BitmapPool bitmapPool, Bitmap firstFrame) { if (firstFrame == null) { throw new NullPointerException("The first frame of the GIF must not be null"); } gifHeader = header; this.data = data; this.bitmapPool = bitmapPool; this.firstFrame = firstFrame; this.context = context.getApplicationContext(); this.frameTransformation = frameTransformation; this.targetWidth = targetWidth; this.targetHeight = targetHeight; bitmapProvider = provider; }
private GifTextureResource decode(byte[] data, int width, int height, GifHeaderParser parser, GifDecoder decoder) { final GifHeader header = parser.parseHeader(); if (header.getNumFrames() <= 0 || header.getStatus() != GifDecoder.STATUS_OK) { // If we couldn't decode the GIF, we will end up with a frame count of 0. return null; } Bitmap firstFrame = decodeFirstFrame(decoder, header, data); if (firstFrame == null) { return null; } Transformation<Bitmap> unitTransformation = UnitTransformation.get(); GifTexture gifDrawable = new GifTexture(context, provider, bitmapPool, unitTransformation, width, height, header, data, firstFrame); return new GifTextureResource(gifDrawable); }
private boolean encodeTransformedToStream(GifDrawable drawable, OutputStream os) { Transformation<Bitmap> 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<Bitmap> 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 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; }
@SuppressWarnings("unchecked") @Before public void setUp() { MockitoAnnotations.initMocks(this); Application context = RuntimeEnvironment.application; ReEncodingGifResourceEncoder.Factory factory = mock(ReEncodingGifResourceEncoder.Factory.class); when(factory.buildDecoder(any(GifDecoder.BitmapProvider.class))).thenReturn(decoder); when(factory.buildParser()).thenReturn(parser); when(factory.buildEncoder()).thenReturn(gifEncoder); when(factory.buildFrameResource(any(Bitmap.class), any(BitmapPool.class))) .thenReturn(frameResource); // TODO Util.anyResource once Util is moved to testutil module (remove unchecked above!) when(frameTransformation.transform(anyContext(), any(Resource.class), anyInt(), anyInt())) .thenReturn(frameResource); when(gifDrawable.getFrameTransformation()).thenReturn(frameTransformation); when(gifDrawable.getBuffer()).thenReturn(ByteBuffer.allocate(0)); when(resource.get()).thenReturn(gifDrawable); encoder = new ReEncodingGifResourceEncoder(context, mock(BitmapPool.class), factory); options = new Options(); options.set(ReEncodingGifResourceEncoder.ENCODE_TRANSFORMATION, true); file = new File(context.getCacheDir(), "test"); }
private GifDrawableResource decode(ByteBuffer byteBuffer, int width, int height, GifHeaderParser parser) { long startTime = LogTime.getLogTime(); final GifHeader header = parser.parseHeader(); if (header.getNumFrames() <= 0 || header.getStatus() != GifDecoder.STATUS_OK) { // If we couldn't decode the GIF, we will end up with a frame count of 0. return null; } int sampleSize = getSampleSize(header, width, height); GifDecoder gifDecoder = gifDecoderFactory.build(provider, header, byteBuffer, sampleSize); gifDecoder.advance(); Bitmap firstFrame = gifDecoder.getNextFrame(); if (firstFrame == null) { return null; } Transformation<Bitmap> unitTransformation = UnitTransformation.get(); GifDrawable gifDrawable = new GifDrawable(context, gifDecoder, bitmapPool, unitTransformation, width, height, firstFrame); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Decoded GIF from stream in " + LogTime.getElapsedMillis(startTime)); } return new GifDrawableResource(gifDrawable); }
@Test public void testReturnsNullIfGifDecoderFailsToDecodeFirstFrame() { when(gifHeader.getNumFrames()).thenReturn(1); when(gifHeader.getStatus()).thenReturn(GifDecoder.STATUS_OK); when(gifDecoder.getNextFrame()).thenReturn(null); assertNull(decoder.decode(ByteBuffer.allocate(10), 100, 100, options)); }
@Test public void testReturnsNewDrawableFromConstantState() { Bitmap firstFrame = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); drawable = new GifDrawable(RuntimeEnvironment.application, mock(GifDecoder.class), bitmapPool, transformation, 100, 100, firstFrame); assertNotNull(drawable.getConstantState().newDrawable()); assertNotNull( drawable.getConstantState().newDrawable(RuntimeEnvironment.application.getResources())); }
@Test public void testLoopsForeverIfLoopCountIsLoopIntrinsicAndTotalIterationCountIsForever() { final int frameCount = 3; final int loopCount = 40; when(frameLoader.getLoopCount()).thenReturn(GifDecoder.TOTAL_ITERATION_COUNT_FOREVER); when(frameLoader.getFrameCount()).thenReturn(frameCount); drawable.setLoopCount(GifDrawable.LOOP_INTRINSIC); drawable.setVisible(true, true); drawable.start(); runLoops(loopCount, frameCount); verifyRanLoops(loopCount, frameCount); assertTrue("drawable should be still running", drawable.isRunning()); }
@SuppressWarnings("unchecked") @Before public void setUp() { MockitoAnnotations.initMocks(this); Application context = RuntimeEnvironment.application; ReEncodingGifResourceEncoder.Factory factory = mock(ReEncodingGifResourceEncoder.Factory.class); when(decoder.getNextFrame()).thenReturn(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)); when(factory.buildDecoder(any(GifDecoder.BitmapProvider.class))).thenReturn(decoder); when(factory.buildParser()).thenReturn(parser); when(factory.buildEncoder()).thenReturn(gifEncoder); when(factory.buildFrameResource(any(Bitmap.class), any(BitmapPool.class))) .thenReturn(frameResource); // TODO Util.anyResource once Util is moved to testutil module (remove unchecked above!) when(frameTransformation.transform(anyContext(), any(Resource.class), anyInt(), anyInt())) .thenReturn(frameResource); when(gifDrawable.getFrameTransformation()).thenReturn(frameTransformation); when(gifDrawable.getBuffer()).thenReturn(ByteBuffer.allocate(0)); when(resource.get()).thenReturn(gifDrawable); encoder = new ReEncodingGifResourceEncoder(context, mock(BitmapPool.class), factory); options = new Options(); options.set(ReEncodingGifResourceEncoder.ENCODE_TRANSFORMATION, true); file = new File(context.getCacheDir(), "test"); }
private GifDrawableResource decode( ByteBuffer byteBuffer, int width, int height, GifHeaderParser parser, Options options) { long startTime = LogTime.getLogTime(); final GifHeader header = parser.parseHeader(); if (header.getNumFrames() <= 0 || header.getStatus() != GifDecoder.STATUS_OK) { // If we couldn't decode the GIF, we will end up with a frame count of 0. return null; } Bitmap.Config config = options.get(GifOptions.DECODE_FORMAT) == DecodeFormat.PREFER_RGB_565 ? Bitmap.Config.RGB_565 : Bitmap.Config.ARGB_8888; int sampleSize = getSampleSize(header, width, height); GifDecoder gifDecoder = gifDecoderFactory.build(provider, header, byteBuffer, sampleSize); gifDecoder.setDefaultBitmapConfig(config); gifDecoder.advance(); Bitmap firstFrame = gifDecoder.getNextFrame(); if (firstFrame == null) { return null; } Transformation<Bitmap> unitTransformation = UnitTransformation.get(); GifDrawable gifDrawable = new GifDrawable(context, gifDecoder, unitTransformation, width, height, firstFrame); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Decoded GIF from stream in " + LogTime.getElapsedMillis(startTime)); } return new GifDrawableResource(gifDrawable); }
public GifDrawable getDrawable() { GifDecoder gifDecoder = new GifDecoder(bitmapPool); gifDecoder.setData(gifId, header, data); GifFrameManager frameManager = new GifFrameManager(context, gifDecoder, getFrameTransformation()); GifDrawable result = new GifDrawable(gifDecoder, frameManager); drawables.add(result); return result; }
GifFrameLoader(FrameCallback callback, GifDecoder gifDecoder, Handler handler, GenericRequestBuilder<GifDecoder, GifDecoder, Bitmap, Bitmap> requestBuilder) { if (handler == null) { handler = new Handler(Looper.getMainLooper(), new FrameLoaderCallback()); } this.callback = callback; this.gifDecoder = gifDecoder; this.handler = handler; this.requestBuilder = requestBuilder; }
GifTexture(GifState state) { if (state == null) { throw new NullPointerException("GifState must not be null"); } this.state = state; this.decoder = new GifDecoder(state.bitmapProvider); decoder.setData(state.gifHeader, state.data); frameLoader = new GifFrameLoader(state.context, this, decoder, state.targetWidth, state.targetHeight); }
GifTexture(GifDecoder decoder, GifFrameLoader frameLoader, Bitmap firstFrame, BitmapPool bitmapPool) { this.decoder = decoder; this.frameLoader = frameLoader; this.state = new GifState(null); state.bitmapPool = bitmapPool; state.firstFrame = firstFrame; }
public GifTextureResource decode(byte[] data, int width, int height) { final GifHeaderParser parser = parserPool.obtain(data); final GifDecoder decoder = decoderPool.obtain(provider); try { return decode(data, width, height, parser, decoder); } finally { parserPool.release(parser); decoderPool.release(decoder); } }
public GifDecoder buildDecoder(GifDecoder.BitmapProvider bitmapProvider) { return new StandardGifDecoder(bitmapProvider); }
public GifDecoder build(GifDecoder.BitmapProvider provider, GifHeader header, ByteBuffer data, int sampleSize) { return new StandardGifDecoder(provider, header, data, sampleSize); }