aboutsummaryrefslogtreecommitdiff
path: root/third_party/gif_decoder/src/androidTest/java/com/bumptech/glide/gifdecoder/test/GifBytesTestUtil.java
blob: 97c3d4fae01f611bb2f3a0679866f7a40c1e1f04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package com.bumptech.glide.gifdecoder.test;

import java.nio.ByteBuffer;

/**
 * Utils for writing the bytes of various parts of GIFs to byte buffers.
 */
public class GifBytesTestUtil {
    // Length in bytes.
    public static final int HEADER_LENGTH = 13;
    // Length in bytes.
    public static final int IMAGE_DESCRIPTOR_LENGTH = 10;

    public static void writeFakeImageData(ByteBuffer out, int lzwMinCodeSize) {
        // 1 for lzwMinCodeSize, 1 for length, 1 for min content, 1 for block terminator.
        verifyRemaining(out, 4);
        verifyShortValues(lzwMinCodeSize);

        out.put((byte) lzwMinCodeSize);
        // Block length.
        out.put((byte) 0x01);
        // Block content.
        out.put((byte) 0x01);
        // End of block.
        out.put((byte) 0x00);
    }

    public static void writeImageDescriptor(ByteBuffer out, int imageLeft, int imageTop, int imageWidth,
            int imageHeight) {
        verifyRemaining(out, IMAGE_DESCRIPTOR_LENGTH);
        verifyShortValues(imageLeft, imageTop, imageWidth, imageHeight);

        // Image separator
        out.put((byte) 0x2C);

        out.putShort((short) imageLeft).putShort((short) imageTop).putShort((short) imageWidth)
                .putShort((short) imageHeight);
    }

    public static void writeHeaderAndLsd(ByteBuffer out, int width, int height, boolean hasGct, int gctSize) {
        verifyRemaining(out, HEADER_LENGTH);
        verifyShortValues(width, height);

        // GIF
        out.put((byte) 0x47).put((byte) 0x49).put((byte) 0x46);
        // Version - 89a.
        out.put((byte) 0x38).put((byte) 0x39).put((byte) 0x61);

        /** LSD (Logical Screen Descriptor) **/
          // Width.
        out.putShort((short) width);
        // Height.
        out.putShort((short) height);
        // Packed GCT (Global Color Table) flag + color resolution + sort flag + size of GCT.
        // GCT flag (false) - most significant bit.
        byte gctFlag = (byte) ((hasGct ? 1 : 0) << 7);
        // Color resolution - next three bits.
        byte colorResolution = 1 << 5;
        // Sort flag - next bit;
        byte sortFlag = 0 << 4;
        // exponent of size of color table, size = 2^(1 + exponent) - least significant 3 bits.
        byte size = (byte) gctSize;

        byte packed = (byte) (gctFlag | colorResolution | sortFlag | size);
        out.put(packed);

        // Background color index.
        out.put((byte) 0);

        // Pixel aspect ratio.
        out.put((byte) 0);
    }

    private static void verifyRemaining(ByteBuffer buffer, int expected) {
        if (buffer.remaining() < expected) {
            throw new IllegalArgumentException("Must have at least " + expected + " bytes to write");
        }
    }

    private static void verifyShortValues(int... shortValues) {
        for (int dimen : shortValues) {
            if (dimen > Short.MAX_VALUE || dimen < 0) {
                throw new IllegalArgumentException("Must pass in non-negative short dimensions, not: " + dimen);
            }
        }
    }
}