diff options
author | Sam Judd <judds@google.com> | 2014-10-21 19:31:46 -0700 |
---|---|---|
committer | Sam Judd <judds@google.com> | 2014-10-21 19:31:46 -0700 |
commit | 4fcb6cd5b3dbd7ecc58d3e3dcb7a3d8304e54a16 (patch) | |
tree | 4b4fca82227416189be4f66af5b9c01d420eb5de /third_party | |
parent | 39f12e09c7273b13604184e523846c1ef18ff311 (diff) | |
download | glide-4fcb6cd5b3dbd7ecc58d3e3dcb7a3d8304e54a16.tar.gz |
Set minimum and default frame delays.
Fixes #205.
Diffstat (limited to 'third_party')
5 files changed, 140 insertions, 9 deletions
diff --git a/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/GifHeaderParserTest.java b/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/GifHeaderParserTest.java index 0cd0a7af..654b8cef 100644 --- a/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/GifHeaderParserTest.java +++ b/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/GifHeaderParserTest.java @@ -79,6 +79,72 @@ public class GifHeaderParserTest { assertNotNull(header.frames.get(0)); } + private static ByteBuffer writeHeaderWithGceAndFrameDelay(short frameDelay) { + final int lzwMinCodeSize = 2; + ByteBuffer buffer = ByteBuffer.allocate( + GifBytesTestUtil.HEADER_LENGTH + + GifBytesTestUtil.GRAPHICS_CONTROL_EXTENSION_LENGTH + + GifBytesTestUtil.IMAGE_DESCRIPTOR_LENGTH + + GifBytesTestUtil.getImageDataSize(lzwMinCodeSize) + ).order(ByteOrder.LITTLE_ENDIAN); + GifBytesTestUtil.writeHeaderAndLsd(buffer, 1, 1, false, 0); + GifBytesTestUtil.writeGraphicsControlExtension(buffer, frameDelay); + GifBytesTestUtil.writeImageDescriptor(buffer, 0, 0, 1, 1, false /*hasLct*/, 0); + GifBytesTestUtil.writeFakeImageData(buffer, lzwMinCodeSize); + return buffer; + } + + @Test + public void testCanParseFrameDelay() { + final short frameDelay = 50; + ByteBuffer buffer = writeHeaderWithGceAndFrameDelay(frameDelay); + + parser.setData(buffer.array()); + GifHeader header = parser.parseHeader(); + GifFrame frame = header.frames.get(0); + + // Convert delay in 100ths of a second to ms. + assertEquals(frameDelay * 10, frame.delay); + } + + @Test + public void testSetsDefaultFrameDelayIfFrameDelayIsZero() { + ByteBuffer buffer = writeHeaderWithGceAndFrameDelay((short) 0); + + parser.setData(buffer.array()); + GifHeader header = parser.parseHeader(); + GifFrame frame = header.frames.get(0); + + // Convert delay in 100ths of a second to ms. + assertEquals(GifHeaderParser.DEFAULT_FRAME_DELAY * 10, frame.delay); + } + + @Test + public void testSetsDefaultFrameDelayIfFrameDelayIsLessThanMinimum() { + final short frameDelay = GifHeaderParser.MIN_FRAME_DELAY - 1; + ByteBuffer buffer = writeHeaderWithGceAndFrameDelay(frameDelay); + + parser.setData(buffer.array()); + GifHeader header = parser.parseHeader(); + GifFrame frame = header.frames.get(0); + + // Convert delay in 100ths of a second to ms. + assertEquals(GifHeaderParser.DEFAULT_FRAME_DELAY * 10, frame.delay); + } + + @Test + public void testObeysFrameDelayIfFrameDelayIsAtMinimum() { + final short frameDelay = GifHeaderParser.MIN_FRAME_DELAY; + ByteBuffer buffer = writeHeaderWithGceAndFrameDelay(frameDelay); + + parser.setData(buffer.array()); + GifHeader header = parser.parseHeader(); + GifFrame frame = header.frames.get(0); + + // Convert delay in 100ths of a second to ms. + assertEquals(frameDelay * 10, frame.delay); + } + @Test public void testSetsFrameLocalColorTableToNullIfNoColorTable() { final int lzwMinCodeSize = 2; diff --git a/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtil.java b/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtil.java index e389deed..b6f3140e 100644 --- a/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtil.java +++ b/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtil.java @@ -10,6 +10,8 @@ public class GifBytesTestUtil { public static final int HEADER_LENGTH = 13; // Length in bytes. public static final int IMAGE_DESCRIPTOR_LENGTH = 10; + // Length in bytes. + public static final int GRAPHICS_CONTROL_EXTENSION_LENGTH = 8; public static int getColorTableLength(int numColors) { return 3 * numColors; @@ -104,6 +106,29 @@ public class GifBytesTestUtil { out.put((byte) 0); } + public static void writeGraphicsControlExtension(ByteBuffer out, int delayTime) { + verifyRemaining(out, GRAPHICS_CONTROL_EXTENSION_LENGTH); + verifyShortValues(delayTime); + + // Extension inducer (constant). + out.put((byte) 0x21); + // Graphic control label (constant). + out.put((byte) 0xF9); + // Block size (constant). + out.put((byte) 0x04); + // Packed (disposal method, user input, transparent color flag) + out.put((byte) 0x00); + + // Frame delay in 100ths of a second. + out.putShort((short) delayTime); + + // Transparent color index. + out.put((byte) 0x00); + + // Block terminator (constant). + out.put((byte) 0x00); + } + private static void verifyRemaining(ByteBuffer buffer, int expected) { if (buffer.remaining() < expected) { throw new IllegalArgumentException("Must have at least " + expected + " bytes to write"); diff --git a/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtilTest.java b/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtilTest.java index 88106ea6..b393265f 100644 --- a/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtilTest.java +++ b/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtilTest.java @@ -19,7 +19,7 @@ public class GifBytesTestUtilTest { byte[] expected = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00, 0x08, 0x00, 0x10, 0x20, 0x00, 0x00}; - assertArrayEquals(expected, buffer.array()); + assertEquals(expected, buffer); } @Test @@ -30,7 +30,7 @@ public class GifBytesTestUtilTest { byte[] expected = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x00, 0x08, 0x00, 0x10, (byte) 0xA4, 0x00, 0x00}; - assertArrayEquals(expected, buffer.array()); + assertEquals(expected, buffer); } @Test @@ -53,7 +53,7 @@ public class GifBytesTestUtilTest { 0x00 }; - assertArrayEquals(expected, buffer.array()); + assertEquals(expected, buffer); } @Test @@ -81,7 +81,7 @@ public class GifBytesTestUtilTest { packedField }; - assertArrayEquals(expected, buffer.array()); + assertEquals(expected, buffer); } @Test @@ -102,8 +102,7 @@ public class GifBytesTestUtilTest { }; - assertArrayEquals("expected=" + Arrays.toString(expected) + " received=" + Arrays.toString(buffer.array()), - expected, buffer.array()); + assertEquals(expected, buffer); } @Test @@ -113,6 +112,37 @@ public class GifBytesTestUtilTest { byte[] expected = new byte[] { 0x02, 0x01, 0x01, 0x00 }; - assertArrayEquals(expected, buffer.array()); + assertEquals(expected, buffer); + } + + @Test + public void testWritesGraphicsControlExtension() { + short delay = 20; + ByteBuffer buffer = ByteBuffer.allocate(GifBytesTestUtil.GRAPHICS_CONTROL_EXTENSION_LENGTH); + byte[] expected = new byte[] { + // Extension inducer. + 0x21, + // Graphic control label. + (byte) 0xF9, + // Block size. + 0x04, + // Packed byte. + 0x00, + // Frame delay. + 0x00, + 0x14, + // Transparent color index. + 0x00, + // block terminator. + 0x00 + }; + + GifBytesTestUtil.writeGraphicsControlExtension(buffer, delay); + assertEquals(expected, buffer); + } + + private static void assertEquals(byte[] expected, ByteBuffer buffer) { + assertArrayEquals("expected=" + Arrays.toString(expected) + " received=" + Arrays.toString(buffer.array()), + expected, buffer.array()); } } 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..ac634ca6 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 @@ -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) { 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..126a799c 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 @@ -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]; @@ -147,7 +152,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 |