package pl.droidsonroids.gif; import android.support.annotation.IntRange; import android.support.annotation.Nullable; import java.io.IOException; import java.nio.Buffer; import pl.droidsonroids.gif.annotations.Beta; /** * Provides support for animated GIFs in OpenGL. * There are 2 possible usages: * <ol> * <li>Rendering GIF automatically according to its timing to internal frame buffer in the background thread, * and requesting frame to be copied to 2D texture when needed. See {@link #glTexImage2D(int, int)} and {@link #glTexImage2D(int, int)}</li> * <li>Manual frame advancing. See {@link #seekToFrame(int)} (int)}</li> * </ol> */ @Beta public class GifTexImage2D { private final GifInfoHandle mGifInfoHandle; /** * Constructs new GifTexImage2D. * Decoder thread is initially stopped, use {@link #startDecoderThread()} to start it. * * @param inputSource source * @param options null-ok; options controlling parameters like subsampling and opacity * @throws IOException when creation fails */ public GifTexImage2D(final InputSource inputSource, @Nullable GifOptions options) throws IOException { if (options == null) { options = new GifOptions(); } mGifInfoHandle = inputSource.open(); mGifInfoHandle.setOptions(options.inSampleSize, options.inIsOpaque); mGifInfoHandle.initTexImageDescriptor(); } /** * See {@link GifDrawable#getFrameDuration(int)} * * @param index index of the frame * @return duration of the given frame in milliseconds * @throws IndexOutOfBoundsException if {@code index < 0 || index >= <number of frames>} */ public int getFrameDuration(@IntRange(from = 0) int index) { return mGifInfoHandle.getFrameDuration(index); } /** * Seeks to given frame * * @param index index of the frame * @throws IndexOutOfBoundsException if {@code index < 0 || index >= <number of frames>} */ public void seekToFrame(@IntRange(from = 0) int index) { mGifInfoHandle.seekToFrameGL(index); } /** * @return number of frames in GIF, at least one */ public int getNumberOfFrames() { return mGifInfoHandle.getNumberOfFrames(); } /** * Equivalent of {@link android.opengl.GLES20#glTexImage2D(int, int, int, int, int, int, int, int, Buffer)}. * Where <code>Buffer</code> contains pixels of the current frame. * * @param level level-of-detail number * @param target target texture */ public void glTexImage2D(int target, int level) { mGifInfoHandle.glTexImage2D(target, level); } /** * Equivalent of {@link android.opengl.GLES20#glTexSubImage2D(int, int, int, int, int, int, int, int, Buffer)}. * Where <code>Buffer</code> contains pixels of the current frame. * * @param level level-of-detail number * @param target target texture */ public void glTexSubImage2D(int target, int level) { mGifInfoHandle.glTexSubImage2D(target, level); } /** * Creates frame buffer and starts decoding thread. Does nothing if already started. */ public void startDecoderThread() { mGifInfoHandle.startDecoderThread(); } /** * Stops decoder thread and releases frame buffer. Does nothing if already stopped. */ public void stopDecoderThread() { mGifInfoHandle.stopDecoderThread(); } /** * See {@link GifDrawable#recycle()}. Decoder thread is stopped automatically. */ public void recycle() { if (mGifInfoHandle != null) { mGifInfoHandle.recycle(); } } /** * @return width of the GIF canvas, 0 if recycled */ public int getWidth() { return mGifInfoHandle.getWidth(); } /** * @return height of the GIF canvas, 0 if recycled */ public int getHeight() { return mGifInfoHandle.getHeight(); } /** * See {@link GifDrawable#getDuration()} * * @return duration of of one loop the animation in milliseconds. Result is always multiple of 10. */ public int getDuration() { return mGifInfoHandle.getDuration(); } @Override @SuppressWarnings("ThrowFromFinallyBlock") protected final void finalize() throws Throwable { try { recycle(); } finally { super.finalize(); } } }