}
m.Palette = d.globalColorTable
}
- if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
+ if d.hasTransparentIndex {
if !useLocalColorTable {
// Clone the global color table.
m.Palette = append(color.Palette(nil), d.globalColorTable...)
}
- m.Palette[d.transparentIndex] = color.RGBA{}
+ if ti := int(d.transparentIndex); ti < len(m.Palette) {
+ m.Palette[ti] = color.RGBA{}
+ } else {
+ // The transparentIndex is out of range, which is an error
+ // according to the spec, but Firefox and Google Chrome
+ // seem OK with this, so we enlarge the palette with
+ // transparent colors. See golang.org/issue/15059.
+ p := make(color.Palette, ti+1)
+ copy(p, m.Palette)
+ for i := len(m.Palette); i < len(p); i++ {
+ p[i] = color.RGBA{}
+ }
+ m.Palette = p
+ }
}
litWidth, err := d.r.ReadByte()
if err != nil {
trailerStr = "\x3b"
)
-// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
-func lzwEncode(n int) []byte {
+// lzwEncode returns an LZW encoding (with 2-bit literals) of in.
+func lzwEncode(in []byte) []byte {
b := &bytes.Buffer{}
w := lzw.NewWriter(b, lzw.LSB, 2)
- w.Write(make([]byte, n))
- w.Close()
+ if _, err := w.Write(in); err != nil {
+ panic(err)
+ }
+ if err := w.Close(); err != nil {
+ panic(err)
+ }
return b.Bytes()
}
// byte, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
if tc.nPix > 0 {
- enc := lzwEncode(tc.nPix)
+ enc := lzwEncode(make([]byte, tc.nPix))
if len(enc) > 0xff {
t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
continue
}
// Write an image with bounds 2x1, as per TestDecode.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
- enc := lzwEncode(2)
+ enc := lzwEncode([]byte{0x00, 0x00})
if len(enc) > 0xff {
t.Fatalf("compressed length %d is too large", len(enc))
}
b.WriteString(headerStr[:len(headerStr)-3])
b.WriteString("\x00\x00\x00") // No global palette.
- // Image descriptor: 2x1, no local palette.
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels: neither is in range, because there is no palette.
- pix := []byte{0, 3}
- enc := &bytes.Buffer{}
- w := lzw.NewWriter(enc, lzw.LSB, 2)
- if _, err := w.Write(pix); err != nil {
- t.Fatalf("Write: %v", err)
- }
- if err := w.Close(); err != nil {
- t.Fatalf("Close: %v", err)
- }
- b.WriteByte(byte(len(enc.Bytes())))
- b.Write(enc.Bytes())
+ enc := lzwEncode([]byte{0x00, 0x03})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
b.WriteString(headerStr)
b.WriteString(paletteStr)
- // Image descriptor: 2x1, no local palette.
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
// Encode the pixels; some pvals trigger the expected error.
- pix := []byte{pval, pval}
- enc := &bytes.Buffer{}
- w := lzw.NewWriter(enc, lzw.LSB, 2)
- if _, err := w.Write(pix); err != nil {
- t.Fatalf("Write: %v", err)
- }
- if err := w.Close(); err != nil {
- t.Fatalf("Close: %v", err)
- }
- b.WriteByte(byte(len(enc.Bytes())))
- b.Write(enc.Bytes())
+ enc := lzwEncode([]byte{pval, pval})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
b.WriteByte(0x00) // An empty block signifies the end of the image data.
b.WriteString(trailerStr)
}
}
+func TestTransparentPixelOutsidePaletteRange(t *testing.T) {
+ b := &bytes.Buffer{}
+
+ // Manufacture a GIF with a 2 color palette.
+ b.WriteString(headerStr)
+ b.WriteString(paletteStr)
+
+ // Graphic Control Extension: transparency, transparent color index = 3.
+ //
+ // This index, 3, is out of range of the global palette and there is no
+ // local palette in the subsequent image descriptor. This is an error
+ // according to the spec, but Firefox and Google Chrome seem OK with this.
+ //
+ // See golang.org/issue/15059.
+ b.WriteString("\x21\xf9\x04\x01\x00\x00\x03\x00")
+
+ // Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
+ b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
+
+ // Encode the pixels.
+ enc := lzwEncode([]byte{0x03, 0x03})
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
+ b.WriteByte(0x00) // An empty block signifies the end of the image data.
+
+ b.WriteString(trailerStr)
+
+ try(t, b.Bytes(), "")
+}
+
func TestLoopCount(t *testing.T) {
data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
"\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")