1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 // header, palette and trailer are parts of a valid 2x1 GIF image.
19 headerStr
= "GIF89a" +
20 "\x02\x00\x01\x00" + // width=2, height=1
21 "\x80\x00\x00" // headerFields=(a color table of 2 pixels), backgroundIndex, aspect
22 paletteStr
= "\x10\x20\x30\x40\x50\x60" // the color table, also known as a palette
26 // lzwEncode returns an LZW encoding (with 2-bit literals) of in.
27 func lzwEncode(in
[]byte) []byte {
29 w
:= lzw
.NewWriter(b
, lzw
.LSB
, 2)
30 if _
, err
:= w
.Write(in
); err
!= nil {
33 if err
:= w
.Close(); err
!= nil {
39 func TestDecode(t
*testing
.T
) {
40 // extra contains superfluous bytes to inject into the GIF, either at the end
41 // of an existing data sub-block (past the LZW End of Information code) or in
42 // a separate data sub-block. The 0x02 values are arbitrary.
43 const extra
= "\x02\x02\x02\x02"
45 testCases
:= []struct {
46 nPix
int // The number of pixels in the image data.
47 // If non-zero, write this many extra bytes inside the data sub-block
48 // containing the LZW end code.
50 // If non-zero, write an extra block of this many bytes.
54 {0, 0, 0, errNotEnough
},
55 {1, 0, 0, errNotEnough
},
57 // An extra data sub-block after the compressed section with 1 byte which we
60 // An extra data sub-block after the compressed section with 2 bytes. In
61 // this case we complain that there is too much data.
62 {2, 0, 2, errTooMuch
},
63 // Too much pixel data.
64 {3, 0, 0, errTooMuch
},
65 // An extra byte after LZW data, but inside the same data sub-block.
67 // Two extra bytes after LZW data, but inside the same data sub-block.
70 for _
, tc
:= range testCases
{
72 b
.WriteString(headerStr
)
73 b
.WriteString(paletteStr
)
74 // Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2
75 // then this should result in an invalid GIF image. First, write a
76 // magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags
77 // byte, and 2-bit LZW literals.
78 b
.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
80 enc
:= lzwEncode(make([]byte, tc
.nPix
))
81 if len(enc
)+tc
.extraExisting
> 0xff {
82 t
.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d: compressed length %d is too large",
83 tc
.nPix
, tc
.extraExisting
, tc
.extraSeparate
, len(enc
))
87 // Write the size of the data sub-block containing the LZW data.
88 b
.WriteByte(byte(len(enc
) + tc
.extraExisting
))
90 // Write the LZW data.
93 // Write extra bytes inside the same data sub-block where LZW data
94 // ended. Each arbitrarily 0x02.
95 b
.WriteString(extra
[:tc
.extraExisting
])
98 if tc
.extraSeparate
> 0 {
99 // Data sub-block size. This indicates how many extra bytes follow.
100 b
.WriteByte(byte(tc
.extraSeparate
))
101 b
.WriteString(extra
[:tc
.extraSeparate
])
103 b
.WriteByte(0x00) // An empty block signifies the end of the image data.
104 b
.WriteString(trailerStr
)
106 got
, err
:= Decode(b
)
107 if err
!= tc
.wantErr
{
108 t
.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d\ngot %v\nwant %v",
109 tc
.nPix
, tc
.extraExisting
, tc
.extraSeparate
, err
, tc
.wantErr
)
112 if tc
.wantErr
!= nil {
115 want
:= &image
.Paletted
{
118 Rect
: image
.Rect(0, 0, 2, 1),
119 Palette
: color
.Palette
{
120 color
.RGBA
{0x10, 0x20, 0x30, 0xff},
121 color
.RGBA
{0x40, 0x50, 0x60, 0xff},
124 if !reflect
.DeepEqual(got
, want
) {
125 t
.Errorf("nPix=%d, extraExisting=%d, extraSeparate=%d\ngot %v\nwant %v",
126 tc
.nPix
, tc
.extraExisting
, tc
.extraSeparate
, got
, want
)
131 func TestTransparentIndex(t
*testing
.T
) {
133 b
.WriteString(headerStr
)
134 b
.WriteString(paletteStr
)
135 for transparentIndex
:= 0; transparentIndex
< 3; transparentIndex
++ {
136 if transparentIndex
< 2 {
137 // Write the graphic control for the transparent index.
138 b
.WriteString("\x21\xf9\x04\x01\x00\x00")
139 b
.WriteByte(byte(transparentIndex
))
142 // Write an image with bounds 2x1, as per TestDecode.
143 b
.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
144 enc
:= lzwEncode([]byte{0x00, 0x00})
146 t
.Fatalf("compressed length %d is too large", len(enc
))
148 b
.WriteByte(byte(len(enc
)))
152 b
.WriteString(trailerStr
)
154 g
, err
:= DecodeAll(b
)
156 t
.Fatalf("DecodeAll: %v", err
)
158 c0
:= color
.RGBA
{paletteStr
[0], paletteStr
[1], paletteStr
[2], 0xff}
159 c1
:= color
.RGBA
{paletteStr
[3], paletteStr
[4], paletteStr
[5], 0xff}
161 wants
:= []color
.Palette
{
166 if len(g
.Image
) != len(wants
) {
167 t
.Fatalf("got %d images, want %d", len(g
.Image
), len(wants
))
169 for i
, want
:= range wants
{
170 got
:= g
.Image
[i
].Palette
171 if !reflect
.DeepEqual(got
, want
) {
172 t
.Errorf("palette #%d:\ngot %v\nwant %v", i
, got
, want
)
177 // testGIF is a simple GIF that we can modify to test different scenarios.
178 var testGIF
= []byte{
179 'G', 'I', 'F', '8', '9', 'a',
180 1, 0, 1, 0, // w=1, h=1 (6)
181 128, 0, 0, // headerFields, bg, aspect (10)
182 0, 0, 0, 1, 1, 1, // color table and graphics control (13)
183 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
184 // frame 1 (0,0 - 1,1)
186 0x00, 0x00, 0x00, 0x00,
187 0x01, 0x00, 0x01, 0x00, // (32)
189 0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels
194 func try(t
*testing
.T
, b
[]byte, want
string) {
195 _
, err
:= DecodeAll(bytes
.NewReader(b
))
201 t
.Fatalf("got %v, want %v", got
, want
)
205 func TestBounds(t
*testing
.T
) {
206 // Make a local copy of testGIF.
207 gif
:= make([]byte, len(testGIF
))
209 // Make the bounds too big, just by one.
211 want
:= "gif: frame bounds larger than image bounds"
214 // Make the bounds too small; does not trigger bounds
215 // check, but now there's too much data.
217 want
= "gif: too much image data"
221 // Make the bounds really big, expect an error.
222 want
= "gif: frame bounds larger than image bounds"
223 for i
:= 0; i
< 4; i
++ {
229 func TestNoPalette(t
*testing
.T
) {
232 // Manufacture a GIF with no palette, so any pixel at all
234 b
.WriteString(headerStr
[:len(headerStr
)-3])
235 b
.WriteString("\x00\x00\x00") // No global palette.
237 // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
238 b
.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
240 // Encode the pixels: neither is in range, because there is no palette.
241 enc
:= lzwEncode([]byte{0x00, 0x03})
242 b
.WriteByte(byte(len(enc
)))
244 b
.WriteByte(0x00) // An empty block signifies the end of the image data.
246 b
.WriteString(trailerStr
)
248 try(t
, b
.Bytes(), "gif: no color table")
251 func TestPixelOutsidePaletteRange(t
*testing
.T
) {
252 for _
, pval
:= range []byte{0, 1, 2, 3} {
255 // Manufacture a GIF with a 2 color palette.
256 b
.WriteString(headerStr
)
257 b
.WriteString(paletteStr
)
259 // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
260 b
.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
262 // Encode the pixels; some pvals trigger the expected error.
263 enc
:= lzwEncode([]byte{pval
, pval
})
264 b
.WriteByte(byte(len(enc
)))
266 b
.WriteByte(0x00) // An empty block signifies the end of the image data.
268 b
.WriteString(trailerStr
)
270 // No error expected, unless the pixels are beyond the 2 color palette.
273 want
= "gif: invalid pixel value"
275 try(t
, b
.Bytes(), want
)
279 func TestTransparentPixelOutsidePaletteRange(t
*testing
.T
) {
282 // Manufacture a GIF with a 2 color palette.
283 b
.WriteString(headerStr
)
284 b
.WriteString(paletteStr
)
286 // Graphic Control Extension: transparency, transparent color index = 3.
288 // This index, 3, is out of range of the global palette and there is no
289 // local palette in the subsequent image descriptor. This is an error
290 // according to the spec, but Firefox and Google Chrome seem OK with this.
292 // See golang.org/issue/15059.
293 b
.WriteString("\x21\xf9\x04\x01\x00\x00\x03\x00")
295 // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
296 b
.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
298 // Encode the pixels.
299 enc
:= lzwEncode([]byte{0x03, 0x03})
300 b
.WriteByte(byte(len(enc
)))
302 b
.WriteByte(0x00) // An empty block signifies the end of the image data.
304 b
.WriteString(trailerStr
)
306 try(t
, b
.Bytes(), "")
309 func TestLoopCount(t
*testing
.T
) {
310 data
:= []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
311 "\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")
312 img
, err
:= DecodeAll(bytes
.NewReader(data
))
314 t
.Fatal("DecodeAll:", err
)
316 w
:= new(bytes
.Buffer
)
317 err
= EncodeAll(w
, img
)
319 t
.Fatal("EncodeAll:", err
)
321 img1
, err
:= DecodeAll(w
)
323 t
.Fatal("DecodeAll:", err
)
325 if img
.LoopCount
!= img1
.LoopCount
{
326 t
.Errorf("loop count mismatch: %d vs %d", img
.LoopCount
, img1
.LoopCount
)
330 func TestUnexpectedEOF(t
*testing
.T
) {
331 for i
:= len(testGIF
) - 1; i
>= 0; i
-- {
332 _
, err
:= Decode(bytes
.NewReader(testGIF
[:i
]))
333 if err
== errNotEnough
{
340 if !strings
.HasPrefix(text
, "gif:") ||
!strings
.HasSuffix(text
, ": unexpected EOF") {
341 t
.Errorf("Decode(testGIF[:%d]) = %v, want gif: ...: unexpected EOF", i
, err
)