aboutsummaryrefslogtreecommitdiff
path: root/third_party/gif_decoder
diff options
context:
space:
mode:
authorAlan Newberger <alann@google.com>2014-12-03 10:47:03 -0800
committerAlan Newberger <alann@google.com>2014-12-03 10:47:03 -0800
commit617200ae32e6671631846ae0f840115c4463c8d4 (patch)
tree17fb77eadd24974e99a5b1a44df32f5ea81f1665 /third_party/gif_decoder
parent9dbd132bec874fdb47231ffe45d4df2b1ae05764 (diff)
parenta311d4835cdede5757e203d52a1bb5e707cfd989 (diff)
downloadglide-617200ae32e6671631846ae0f840115c4463c8d4.tar.gz
Merge tag 'v3.4.0' of https://github.com/bumptech/glide into ub-camera-haleakala
Change-Id: Ic290a947323184bfd15576a781bceb88258a5dd1
Diffstat (limited to 'third_party/gif_decoder')
-rw-r--r--third_party/gif_decoder/build.gradle22
-rw-r--r--third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java77
-rw-r--r--third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java29
3 files changed, 61 insertions, 67 deletions
diff --git a/third_party/gif_decoder/build.gradle b/third_party/gif_decoder/build.gradle
deleted file mode 100644
index 8834279f..00000000
--- a/third_party/gif_decoder/build.gradle
+++ /dev/null
@@ -1,22 +0,0 @@
-apply plugin: 'com.android.library'
-apply plugin: 'robolectric'
-
-dependencies {
- androidTestCompile 'com.android.support:support-v4:19.1.0'
- androidTestCompile 'org.hamcrest:hamcrest-core:1.3'
- androidTestCompile 'org.hamcrest:hamcrest-library:1.3'
- androidTestCompile 'junit:junit:4.11'
- androidTestCompile 'org.mockito:mockito-all:1.9.5'
- androidTestCompile 'org.robolectric:robolectric:2.4-SNAPSHOT'
-}
-
-android {
- compileSdkVersion 19
- buildToolsVersion '19.1.0'
-
- defaultConfig {
- applicationId 'com.bumptech.glide.gifdecoder'
- minSdkVersion 10
- targetSdkVersion 19
- }
-}
diff --git a/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java b/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java
index 92dc3bfc..c4b4281d 100644
--- a/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java
+++ b/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifDecoder.java
@@ -98,6 +98,11 @@ public class GifDecoder {
private static final int INITIAL_FRAME_POINTER = -1;
+ // We can't tell if a gif has transparency to decode a partial frame on top of a previous frame, or if the final
+ // frame will actually have transparent pixels, so we must always use a format that supports transparency. We can't
+ // use ARGB_4444 because of framework issues drawing onto ARGB_4444 Bitmaps using Canvas.
+ private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
+
// Global File Header values and parsing flags.
// Active color table.
private int[] act;
@@ -123,7 +128,6 @@ public class GifDecoder {
private BitmapProvider bitmapProvider;
private Bitmap previousImage;
private boolean savePrevious;
- private Bitmap.Config config;
private int status;
/**
@@ -135,8 +139,8 @@ public class GifDecoder {
* Returns an {@link Bitmap} with exactly the given dimensions and config, or null if no such {@link Bitmap}
* could be obtained.
*
- * @param width The width of the desired {@link android.graphics.Bitmap}.
- * @param height The height of the desired {@link android.graphics.Bitmap}.
+ * @param width The width in pixels of the desired {@link android.graphics.Bitmap}.
+ * @param height The height in pixels of the desired {@link android.graphics.Bitmap}.
* @param config The {@link android.graphics.Bitmap.Config} of the desired {@link android.graphics.Bitmap}.
*/
public Bitmap obtain(int width, int height, Bitmap.Config config);
@@ -164,10 +168,6 @@ public class GifDecoder {
return data;
}
- public void setPreferredConfig(Bitmap.Config config) {
- this.config = config;
- }
-
/**
* Returns the current status of the decoder.
*
@@ -202,7 +202,7 @@ public class GifDecoder {
}
/**
- * Gets display duration for the upcoming frame.
+ * Gets display duration for the upcoming frame in ms.
*/
public int getNextDelay() {
if (header.frameCount <= 0 || framePointer < 0) {
@@ -248,46 +248,59 @@ public class GifDecoder {
*
* @return Bitmap representation of frame.
*/
- public Bitmap getNextFrame() {
+ public synchronized Bitmap getNextFrame() {
if (header.frameCount <= 0 || framePointer < 0) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "unable to decode frame, frameCount=" + header.frameCount + " framePointer=" + framePointer);
+ }
status = STATUS_FORMAT_ERROR;
}
if (status == STATUS_FORMAT_ERROR || status == STATUS_OPEN_ERROR) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Unable to decode frame, status=" + status);
+ }
return null;
}
status = STATUS_OK;
- GifFrame frame = header.frames.get(framePointer);
+ GifFrame currentFrame = header.frames.get(framePointer);
+ GifFrame previousFrame = null;
+ int previousIndex = framePointer - 1;
+ if (previousIndex >= 0) {
+ previousFrame = header.frames.get(previousIndex);
+ }
// Set the appropriate color table.
- if (frame.lct == null) {
+ if (currentFrame.lct == null) {
act = header.gct;
} else {
- act = frame.lct;
- if (header.bgIndex == frame.transIndex) {
+ act = currentFrame.lct;
+ if (header.bgIndex == currentFrame.transIndex) {
header.bgColor = 0;
}
}
int save = 0;
- if (frame.transparency) {
- save = act[frame.transIndex];
+ if (currentFrame.transparency) {
+ save = act[currentFrame.transIndex];
// Set transparent color if specified.
- act[frame.transIndex] = 0;
+ act[currentFrame.transIndex] = 0;
}
if (act == null) {
- Log.w(TAG, "No Valid Color Table");
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "No Valid Color Table");
+ }
// No color table defined.
status = STATUS_FORMAT_ERROR;
return null;
}
// Transfer pixel data to image.
- Bitmap result = setPixels(framePointer);
+ Bitmap result = setPixels(currentFrame, previousFrame);
// Reset the transparent pixel in the color table
- if (frame.transparency) {
- act[frame.transIndex] = save;
+ if (currentFrame.transparency) {
+ act[currentFrame.transIndex] = save;
}
return result;
@@ -408,13 +421,8 @@ public class GifDecoder {
/**
* Creates new frame image from current data (and previous frames as specified by their disposition codes).
*/
- private Bitmap setPixels(int frameIndex) {
- GifFrame currentFrame = header.frames.get(frameIndex);
- GifFrame previousFrame = null;
- int previousIndex = frameIndex - 1;
- if (previousIndex >= 0) {
- previousFrame = header.frames.get(previousIndex);
- }
+ private Bitmap setPixels(GifFrame currentFrame, GifFrame previousFrame) {
+
int width = header.width;
int height = header.height;
@@ -676,21 +684,10 @@ public class GifDecoder {
return n;
}
- private Bitmap.Config getPreferredConfig() {
- // We can't tell if a gif has transparency to decode a partial frame on top of a previous frame, or if the final
- // frame will actually have transparent pixels, so we must always use a format that supports transparency.
- if (config == Bitmap.Config.RGB_565 || config == Bitmap.Config.ARGB_4444) {
- return Bitmap.Config.ARGB_4444;
- } else {
- return Bitmap.Config.ARGB_8888;
- }
- }
-
private Bitmap getNextBitmap() {
- Bitmap.Config targetConfig = getPreferredConfig();
- Bitmap result = bitmapProvider.obtain(header.width, header.height, targetConfig);
+ Bitmap result = bitmapProvider.obtain(header.width, header.height, BITMAP_CONFIG);
if (result == null) {
- result = Bitmap.createBitmap(header.width, header.height, targetConfig);
+ result = Bitmap.createBitmap(header.width, header.height, BITMAP_CONFIG);
}
setAlpha(result);
return result;
diff --git a/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java b/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java
index 286a5602..cf61531c 100644
--- a/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java
+++ b/third_party/gif_decoder/src/main/java/com/bumptech/glide/gifdecoder/GifHeaderParser.java
@@ -1,5 +1,7 @@
package com.bumptech.glide.gifdecoder;
+import static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR;
+
import android.util.Log;
import java.nio.BufferUnderflowException;
@@ -7,8 +9,6 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
-import static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR;
-
/**
* A class responsible for creating {@link com.bumptech.glide.gifdecoder.GifHeader}s from data representing animated
* gifs.
@@ -16,6 +16,11 @@ import static com.bumptech.glide.gifdecoder.GifDecoder.STATUS_FORMAT_ERROR;
public class GifHeaderParser {
public static final String TAG = "GifHeaderParser";
+ // The minimum frame delay in hundredths of a second.
+ static final int MIN_FRAME_DELAY = 3;
+ // The default frame delay in hundredths of a second for GIFs with frame delays less than the minimum.
+ static final int DEFAULT_FRAME_DELAY = 10;
+
private static final int MAX_BLOCK_SIZE = 256;
// Raw data read working array.
private final byte[] block = new byte[MAX_BLOCK_SIZE];
@@ -37,6 +42,11 @@ public class GifHeaderParser {
return this;
}
+ public void clear() {
+ rawData = null;
+ header = null;
+ }
+
private void reset() {
rawData = null;
Arrays.fill(block, (byte) 0);
@@ -147,7 +157,12 @@ public class GifHeaderParser {
}
header.currentFrame.transparency = (packed & 1) != 0;
// Delay in milliseconds.
- header.currentFrame.delay = readShort() * 10;
+ int delayInHundredthsOfASecond = readShort();
+ // TODO: consider allowing -1 to indicate show forever.
+ if (delayInHundredthsOfASecond < MIN_FRAME_DELAY) {
+ delayInHundredthsOfASecond = DEFAULT_FRAME_DELAY;
+ }
+ header.currentFrame.delay = delayInHundredthsOfASecond * 10;
// Transparent color index
header.currentFrame.transIndex = read();
// Block terminator
@@ -275,7 +290,9 @@ public class GifHeaderParser {
tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
}
} catch (BufferUnderflowException e) {
- Log.w(TAG, "Format Error Reading Color Table", e);
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Format Error Reading Color Table", e);
+ }
header.status = STATUS_FORMAT_ERROR;
}
@@ -321,7 +338,9 @@ public class GifHeaderParser {
n += count;
}
} catch (Exception e) {
- Log.w(TAG, "Error Reading Block n: " + n + " count: " + count + " blockSize: " + blockSize, e);
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Error Reading Block n: " + n + " count: " + count + " blockSize: " + blockSize, e);
+ }
header.status = STATUS_FORMAT_ERROR;
}
}