Class GifDrawable

java.lang.Object
android.graphics.drawable.Drawable
pl.droidsonroids.gif.GifDrawable
All Implemented Interfaces:
Animatable, MediaController.MediaPlayerControl

public class GifDrawable
extends Drawable
implements Animatable, MediaController.MediaPlayerControl
A Drawable which can be used to hold GIF images, especially animations. Basic GIF metadata can also be examined.
  • Field Details

    • mPaint

      protected final Paint mPaint
      Paint used to draw on a Canvas
  • Constructor Details

    • GifDrawable

      public GifDrawable​(@NonNull Resources res, @RawRes @DrawableRes int id) throws Resources.NotFoundException, IOException
      Creates drawable from resource.
      Parameters:
      res - Resources to read from
      id - resource id (raw or drawable)
      Throws:
      Resources.NotFoundException - if the given ID does not exist.
      IOException - when opening failed
      NullPointerException - if res is null
    • GifDrawable

      public GifDrawable​(@NonNull AssetManager assets, @NonNull String assetName) throws IOException
      Creates drawable from asset.
      Parameters:
      assets - AssetManager to read from
      assetName - name of the asset
      Throws:
      IOException - when opening failed
      NullPointerException - if assets or assetName is null
    • GifDrawable

      public GifDrawable​(@NonNull String filePath) throws IOException
      Constructs drawable from given file path.
      Only metadata is read, no graphic data is decoded here. In practice can be called from main thread. However it will violate StrictMode policy if disk reads detection is enabled.
      Parameters:
      filePath - path to the GIF file
      Throws:
      IOException - when opening failed
      NullPointerException - if filePath is null
    • GifDrawable

      public GifDrawable​(@NonNull File file) throws IOException
      Equivalent to GifDrawable(file.getPath())}
      Parameters:
      file - the GIF file
      Throws:
      IOException - when opening failed
      NullPointerException - if file is null
    • GifDrawable

      public GifDrawable​(@NonNull InputStream stream) throws IOException
      Creates drawable from InputStream. InputStream must support marking, IllegalArgumentException will be thrown otherwise.
      Parameters:
      stream - stream to read from
      Throws:
      IOException - when opening failed
      IllegalArgumentException - if stream does not support marking
      NullPointerException - if stream is null
    • GifDrawable

      public GifDrawable​(@NonNull AssetFileDescriptor afd) throws IOException
      Creates drawable from AssetFileDescriptor. Convenience wrapper for GifDrawable(FileDescriptor)
      Parameters:
      afd - source
      Throws:
      NullPointerException - if afd is null
      IOException - when opening failed
    • GifDrawable

      public GifDrawable​(@NonNull FileDescriptor fd) throws IOException
      Creates drawable from FileDescriptor
      Parameters:
      fd - source
      Throws:
      IOException - when opening failed
      NullPointerException - if fd is null
    • GifDrawable

      public GifDrawable​(@NonNull byte[] bytes) throws IOException
      Creates drawable from byte array.
      It can be larger than size of the GIF data. Bytes beyond GIF terminator are not accessed.
      Parameters:
      bytes - raw GIF bytes
      Throws:
      IOException - if bytes does not contain valid GIF data
      NullPointerException - if bytes are null
    • GifDrawable

      public GifDrawable​(@NonNull ByteBuffer buffer) throws IOException
      Creates drawable from ByteBuffer. Only direct buffers are supported. Buffer can be larger than size of the GIF data. Bytes beyond GIF terminator are not accessed.
      Parameters:
      buffer - buffer containing GIF data
      Throws:
      IOException - if buffer does not contain valid GIF data or is indirect
      NullPointerException - if buffer is null
    • GifDrawable

      public GifDrawable​(@Nullable ContentResolver resolver, @NonNull Uri uri) throws IOException
      Creates drawable from Uri which is resolved using resolver. ContentResolver.openAssetFileDescriptor(android.net.Uri, String) is used to open an Uri.
      Parameters:
      uri - GIF Uri, cannot be null.
      resolver - resolver used to query uri, can be null for file:// scheme Uris
      Throws:
      IOException - if resolution fails or destination is not a GIF.
    • GifDrawable

      protected GifDrawable​(@NonNull InputSource inputSource, @Nullable GifDrawable oldDrawable, @Nullable ScheduledThreadPoolExecutor executor, boolean isRenderingTriggeredOnDraw, @NonNull GifOptions options) throws IOException
      Creates drawable from InputSource.
      Parameters:
      inputSource - The InputSource concrete subclass used to construct GifDrawable.
      oldDrawable - The old drawable that will be reused to save the memory. Can be null.
      executor - The executor for rendering tasks. Can be null.
      isRenderingTriggeredOnDraw - True if rendering of the next frame is scheduled after drawing current one, false otherwise.
      options - Options controlling various GIF parameters.
      Throws:
      IOException - if input source is invalid.
  • Method Details

    • recycle

      public void recycle()
      Frees any memory allocated native way. Operation is irreversible. After this call, nothing will be drawn. This method is idempotent, subsequent calls have no effect. Like Bitmap.recycle() this is an advanced call and is invoked implicitly by finalizer.
    • isRecycled

      public boolean isRecycled()
      Returns:
      true if drawable is recycled
    • invalidateSelf

      public void invalidateSelf()
      Overrides:
      invalidateSelf in class Drawable
    • getIntrinsicHeight

      public int getIntrinsicHeight()
      Overrides:
      getIntrinsicHeight in class Drawable
    • getIntrinsicWidth

      public int getIntrinsicWidth()
      Overrides:
      getIntrinsicWidth in class Drawable
    • setAlpha

      public void setAlpha​(@IntRange(from=0L,to=255L) int alpha)
      Specified by:
      setAlpha in class Drawable
    • setColorFilter

      public void setColorFilter​(@Nullable ColorFilter cf)
      Specified by:
      setColorFilter in class Drawable
    • getOpacity

      public int getOpacity()
      Specified by:
      getOpacity in class Drawable
      Returns:
      either PixelFormat.TRANSPARENT or PixelFormat.OPAQUE depending on current Paint and GifOptions.setInIsOpaque(boolean) used to construct this Drawable
    • start

      public void start()
      Starts the animation. Does nothing if GIF is not animated. This method is thread-safe.
      Specified by:
      start in interface Animatable
      Specified by:
      start in interface MediaController.MediaPlayerControl
    • reset

      public void reset()
      Causes the animation to start over. If rewinding input source fails then state is not affected. This method is thread-safe.
    • stop

      public void stop()
      Stops the animation. Does nothing if GIF is not animated. This method is thread-safe.
      Specified by:
      stop in interface Animatable
    • isRunning

      public boolean isRunning()
      Specified by:
      isRunning in interface Animatable
    • getComment

      @Nullable public String getComment()
      Returns GIF comment
      Returns:
      comment or null if there is no one defined in file
    • getLoopCount

      public int getLoopCount()
      Returns loop count previously read from GIF's application extension block. Defaults to 1 if there is no such extension.
      Returns:
      loop count, 0 means that animation is infinite
    • setLoopCount

      public void setLoopCount​(@IntRange(from=0L,to=65535L) int loopCount)
      Sets loop count of the animation. Loop count must be in range <0 ,65535>
      Parameters:
      loopCount - loop count, 0 means infinity
    • toString

      @NonNull public String toString()
      Overrides:
      toString in class Object
      Returns:
      basic description of the GIF including size and number of frames
    • getNumberOfFrames

      public int getNumberOfFrames()
      Returns:
      number of frames in GIF, at least one
    • getError

      @NonNull public GifError getError()
      Retrieves last error which is also the indicator of current GIF status.
      Returns:
      current error or GifError.NO_ERROR if there was no error or drawable is recycled
    • createFromResource

      @Nullable public static GifDrawable createFromResource​(@NonNull Resources res, @RawRes @DrawableRes int resourceId)
      An GifDrawable(Resources, int) wrapper but returns null instead of throwing exception if creation fails.
      Parameters:
      res - resources to read from
      resourceId - resource id
      Returns:
      correct drawable or null if creation failed
    • setSpeed

      public void setSpeed​(@FloatRange(from=0.0,fromInclusive=false) float factor)
      Sets new animation speed factor.
      Note: If animation is in progress (draw(Canvas)) was already called) then effects will be visible starting from the next frame. Duration of the currently rendered frame is not affected.
      Parameters:
      factor - new speed factor, eg. 0.5f means half speed, 1.0f - normal, 2.0f - double speed
      Throws:
      IllegalArgumentException - if factor<=0
    • pause

      public void pause()
      Equivalent of stop()
      Specified by:
      pause in interface MediaController.MediaPlayerControl
    • getDuration

      public int getDuration()
      Retrieves duration of one loop of the animation. If there is no data (no Graphics Control Extension blocks) 0 is returned. Note that one-frame GIFs can have non-zero duration defined in Graphics Control Extension block, use getNumberOfFrames() to determine if there is one or more frames.
      Specified by:
      getDuration in interface MediaController.MediaPlayerControl
      Returns:
      duration of of one loop the animation in milliseconds. Result is always multiple of 10.
    • getCurrentPosition

      public int getCurrentPosition()
      Retrieves elapsed time from the beginning of a current loop of animation. If there is only 1 frame or drawable is recycled 0 is returned.
      Specified by:
      getCurrentPosition in interface MediaController.MediaPlayerControl
      Returns:
      elapsed time from the beginning of a loop in ms
    • seekTo

      public void seekTo​(@IntRange(from=0L,to=2147483647L) int position)
      Seeks animation to given absolute position (within given loop) and refreshes the canvas.
      If position is greater than duration of the loop of animation (or whole animation if there is no loop) then animation will be sought to the end, no exception will be thrown.
      NOTE: all frames from current (or first one if seeking backward) to desired one must be rendered sequentially to perform seeking. It may take a lot of time if number of such frames is large. Method is thread-safe. Decoding is performed in background thread and drawable is invalidated automatically afterwards.
      Specified by:
      seekTo in interface MediaController.MediaPlayerControl
      Parameters:
      position - position to seek to in milliseconds
      Throws:
      IllegalArgumentException - if position<0
    • seekToBlocking

      public void seekToBlocking​(@IntRange(from=0L,to=2147483647L) int position)
      Like seekTo(int) but performs operation synchronously on current thread
      Parameters:
      position - position to seek to in milliseconds
      Throws:
      IllegalArgumentException - if position<0
    • seekToFrame

      public void seekToFrame​(@IntRange(from=0L,to=2147483647L) int frameIndex)
      Like seekTo(int) but uses index of the frame instead of time. If frameIndex exceeds number of frames, seek stops at the end, no exception is thrown.
      Parameters:
      frameIndex - index of the frame to seek to (zero based)
      Throws:
      IllegalArgumentException - if frameIndex<0
    • seekToFrameAndGet

      public Bitmap seekToFrameAndGet​(@IntRange(from=0L,to=2147483647L) int frameIndex)
      Like seekToFrame(int) but performs operation synchronously and returns that frame.
      Parameters:
      frameIndex - index of the frame to seek to (zero based)
      Returns:
      frame at desired index
      Throws:
      IndexOutOfBoundsException - if frameIndex<0
    • seekToPositionAndGet

      public Bitmap seekToPositionAndGet​(@IntRange(from=0L,to=2147483647L) int position)
      Like seekTo(int) but performs operation synchronously and returns that frame.
      Parameters:
      position - position to seek to in milliseconds
      Returns:
      frame at desired position
      Throws:
      IndexOutOfBoundsException - if position<0
    • isPlaying

      public boolean isPlaying()
      Equivalent of isRunning()
      Specified by:
      isPlaying in interface MediaController.MediaPlayerControl
      Returns:
      true if animation is running
    • getBufferPercentage

      public int getBufferPercentage()
      Used by MediaPlayer for secondary progress bars. There is no buffer in GifDrawable, so buffer is assumed to be always full.
      Specified by:
      getBufferPercentage in interface MediaController.MediaPlayerControl
      Returns:
      always 100
    • canPause

      public boolean canPause()
      Checks whether pause is supported.
      Specified by:
      canPause in interface MediaController.MediaPlayerControl
      Returns:
      always true, even if there is only one frame
    • canSeekBackward

      public boolean canSeekBackward()
      Checks whether seeking backward can be performed.
      Specified by:
      canSeekBackward in interface MediaController.MediaPlayerControl
      Returns:
      true if GIF has at least 2 frames
    • canSeekForward

      public boolean canSeekForward()
      Checks whether seeking forward can be performed.
      Specified by:
      canSeekForward in interface MediaController.MediaPlayerControl
      Returns:
      true if GIF has at least 2 frames
    • getAudioSessionId

      public int getAudioSessionId()
      Used by MediaPlayer. GIFs contain no sound, so 0 is always returned.
      Specified by:
      getAudioSessionId in interface MediaController.MediaPlayerControl
      Returns:
      always 0
    • getFrameByteCount

      public int getFrameByteCount()
      Returns the minimum number of bytes that can be used to store pixels of the single frame. Returned value is the same for all the frames since it is based on the size of GIF screen.

      This method should not be used to calculate the memory usage of the bitmap. Instead see getAllocationByteCount().

      Returns:
      the minimum number of bytes that can be used to store pixels of the single frame
    • getAllocationByteCount

      public long getAllocationByteCount()
      Returns size of the memory needed to store pixels of this object. It counts possible length of all frame buffers. Returned value may be lower than amount of actually allocated memory if GIF uses dispose to previous method but frame requiring it has never been needed yet. Returned value does not change during runtime.
      Returns:
      possible size of the memory needed to store pixels of this object
    • getMetadataAllocationByteCount

      public long getMetadataAllocationByteCount()
      Returns the maximum possible size of the allocated memory used to store pixels and metadata of this object. It counts length of all frame buffers. Returned value does not change over time.
      Returns:
      maximum possible size of the allocated memory needed to store metadata of this object
    • getInputSourceByteCount

      public long getInputSourceByteCount()
      Returns length of the input source obtained at the opening time or -1 if length cannot be determined. Returned value does not change during runtime. If GifDrawable is constructed from InputStream -1 is always returned. In case of byte array and ByteBuffer length is always known. In other cases length -1 can be returned if length cannot be determined.
      Returns:
      number of bytes backed by input source or -1 if it is unknown
    • getPixels

      public void getPixels​(@NonNull int[] pixels)
      Returns in pixels[] a copy of the data in the current frame. Each value is a packed int representing a Color.
      Parameters:
      pixels - the array to receive the frame's colors
      Throws:
      ArrayIndexOutOfBoundsException - if the pixels array is too small to receive required number of pixels
    • getPixel

      public int getPixel​(@IntRange(from=0L) int x, @IntRange(from=0L) int y)
      Returns the Color at the specified location. Throws an exception if x or y are out of bounds (negative or >= to the width or height respectively). The returned color is a non-premultiplied ARGB value.
      Parameters:
      x - The x coordinate (0...width-1) of the pixel to return
      y - The y coordinate (0...height-1) of the pixel to return
      Returns:
      The argb Color at the specified coordinate
      Throws:
      IllegalArgumentException - if x, y exceed the drawable's bounds
      IllegalStateException - if drawable is recycled
    • onBoundsChange

      protected void onBoundsChange​(Rect bounds)
      Overrides:
      onBoundsChange in class Drawable
    • draw

      public void draw​(@NonNull Canvas canvas)
      Reads and renders new frame if needed then draws last rendered frame.
      Specified by:
      draw in class Drawable
      Parameters:
      canvas - canvas to draw into
    • getPaint

      @NonNull public final Paint getPaint()
      Returns:
      the paint used to render this drawable
    • getAlpha

      public int getAlpha()
      Overrides:
      getAlpha in class Drawable
    • setFilterBitmap

      public void setFilterBitmap​(boolean filter)
      Overrides:
      setFilterBitmap in class Drawable
    • setDither

      public void setDither​(boolean dither)
      Overrides:
      setDither in class Drawable
    • addAnimationListener

      public void addAnimationListener​(@NonNull AnimationListener listener)
      Adds a new animation listener
      Parameters:
      listener - animation listener to be added, not null
      Throws:
      NullPointerException - if listener is null
    • removeAnimationListener

      public boolean removeAnimationListener​(AnimationListener listener)
      Removes an animation listener
      Parameters:
      listener - animation listener to be removed
      Returns:
      true if listener collection has been modified
    • getColorFilter

      public ColorFilter getColorFilter()
      Overrides:
      getColorFilter in class Drawable
    • getCurrentFrame

      public Bitmap getCurrentFrame()
      Retrieves a copy of currently buffered frame.
      Returns:
      current frame
    • setTintList

      public void setTintList​(ColorStateList tint)
      Overrides:
      setTintList in class Drawable
    • setTintMode

      public void setTintMode​(@Nullable PorterDuff.Mode tintMode)
      Overrides:
      setTintMode in class Drawable
    • onStateChange

      protected boolean onStateChange​(int[] stateSet)
      Overrides:
      onStateChange in class Drawable
    • isStateful

      public boolean isStateful()
      Overrides:
      isStateful in class Drawable
    • setVisible

      public boolean setVisible​(boolean visible, boolean restart)
      Sets whether this drawable is visible. If rendering of next frame is scheduled on draw current one (the default) then this method only calls through to the super class's implementation.
      Otherwise (if GifDrawableInit.setRenderingTriggeredOnDraw(boolean) was used with true) when the drawable becomes invisible, it will pause its animation. A subsequent change to visible with restart set to true will restart the animation from the first frame. If restart is false, the animation will resume from the most recent frame.
      Overrides:
      setVisible in class Drawable
      Parameters:
      visible - true if visible, false otherwise
      restart - when visible and rendering is triggered on draw, true to force the animation to restart from the first frame
      Returns:
      true if the new visibility is different than its previous state
    • getCurrentFrameIndex

      public int getCurrentFrameIndex()
      Returns zero-based index of recently rendered frame in given loop or -1 when drawable is recycled.
      Returns:
      index of recently rendered frame or -1 when drawable is recycled
    • getCurrentLoop

      public int getCurrentLoop()
      Returns zero-based index of currently played animation loop. If animation is infinite or drawable is recycled 0 is returned.
      Returns:
      index of currently played animation loop
    • isAnimationCompleted

      public boolean isAnimationCompleted()
      Returns whether all animation loops has ended. If drawable is recycled false is returned.
      Returns:
      true if all animation loops has ended
    • getFrameDuration

      public int getFrameDuration​(@IntRange(from=0L) int index)
      Returns duration of the given frame (in milliseconds). If there is no data (no Graphics Control Extension blocks or drawable is recycled) 0 is returned.
      Parameters:
      index - index of the frame
      Returns:
      duration of the given frame in milliseconds
      Throws:
      IndexOutOfBoundsException - if index < 0 or index >= number of frames
    • setCornerRadius

      public void setCornerRadius​(@FloatRange(from=0.0) float cornerRadius)
      Sets the corner radius to be applied when drawing the bitmap. Note that changing corner radius will cause replacing current Paint shader by BitmapShader. Transform set by setTransform(Transform) will also be replaced.
      Parameters:
      cornerRadius - corner radius or 0 to remove rounding
    • getCornerRadius

      @FloatRange(from=0.0) public float getCornerRadius()
      Returns:
      The corner radius applied when drawing this drawable. 0 when drawable is not rounded.
    • setTransform

      public void setTransform​(@Nullable Transform transform)
      Specify a Transform implementation to customize how the GIF's current Bitmap is drawn.
      Parameters:
      transform - new Transform or null to remove current one
    • getTransform

      @Nullable public Transform getTransform()
      Returns:
      The current Transform implementation that customizes how the GIF's current Bitmap is drawn or null if nothing has been set.