From: Nigel Tao Date: Mon, 22 Sep 2014 04:29:45 +0000 (+1000) Subject: image/gif: don't let the per-frame transparent index modify the global X-Git-Tag: go1.4beta1~331 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0be3176a8bc394f5234a2665843b5490e9095f46;p=gostls13.git image/gif: don't let the per-frame transparent index modify the global palette. Fixes #7993. LGTM=r R=r CC=golang-codereviews, james.jdunne https://golang.org/cl/138600043 --- diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go index 926710a456..5a863e204f 100644 --- a/src/image/gif/reader.go +++ b/src/image/gif/reader.go @@ -171,7 +171,8 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { if err != nil { return err } - if d.imageFields&fColorMapFollows != 0 { + useLocalColorMap := d.imageFields&fColorMapFollows != 0 + if useLocalColorMap { m.Palette, err = d.readColorMap() if err != nil { return err @@ -180,6 +181,10 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { m.Palette = d.globalColorMap } if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) { + if !useLocalColorMap { + // Clone the global color map. + m.Palette = append(color.Palette(nil), d.globalColorMap...) + } m.Palette[d.transparentIndex] = color.RGBA{} } litWidth, err := d.r.ReadByte() diff --git a/src/image/gif/reader_test.go b/src/image/gif/reader_test.go index fc2041e997..7b6f504367 100644 --- a/src/image/gif/reader_test.go +++ b/src/image/gif/reader_test.go @@ -22,16 +22,16 @@ const ( trailerStr = "\x3b" ) -func TestDecode(t *testing.T) { - // lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes. - lzwEncode := func(n int) []byte { - b := &bytes.Buffer{} - w := lzw.NewWriter(b, lzw.LSB, 2) - w.Write(make([]byte, n)) - w.Close() - return b.Bytes() - } +// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes. +func lzwEncode(n int) []byte { + b := &bytes.Buffer{} + w := lzw.NewWriter(b, lzw.LSB, 2) + w.Write(make([]byte, n)) + w.Close() + return b.Bytes() +} +func TestDecode(t *testing.T) { testCases := []struct { nPix int // The number of pixels in the image data. extra bool // Whether to write an extra block after the LZW-encoded data. @@ -90,6 +90,52 @@ func TestDecode(t *testing.T) { } } +func TestTransparentIndex(t *testing.T) { + b := &bytes.Buffer{} + b.WriteString(headerStr) + b.WriteString(paletteStr) + for transparentIndex := 0; transparentIndex < 3; transparentIndex++ { + if transparentIndex < 2 { + // Write the graphic control for the transparent index. + b.WriteString("\x21\xf9\x00\x01\x00\x00") + b.WriteByte(byte(transparentIndex)) + b.WriteByte(0) + } + // 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) + if len(enc) > 0xff { + t.Fatalf("compressed length %d is too large", len(enc)) + } + b.WriteByte(byte(len(enc))) + b.Write(enc) + b.WriteByte(0x00) + } + b.WriteString(trailerStr) + + g, err := DecodeAll(b) + if err != nil { + t.Fatalf("DecodeAll: %v", err) + } + c0 := color.RGBA{paletteStr[0], paletteStr[1], paletteStr[2], 0xff} + c1 := color.RGBA{paletteStr[3], paletteStr[4], paletteStr[5], 0xff} + cz := color.RGBA{} + wants := []color.Palette{ + {cz, c1}, + {c0, cz}, + {c0, c1}, + } + if len(g.Image) != len(wants) { + t.Fatalf("got %d images, want %d", len(g.Image), len(wants)) + } + for i, want := range wants { + got := g.Image[i].Palette + if !reflect.DeepEqual(got, want) { + t.Errorf("palette #%d:\ngot %v\nwant %v", i, got, want) + } + } +} + // testGIF is a simple GIF that we can modify to test different scenarios. var testGIF = []byte{ 'G', 'I', 'F', '8', '9', 'a',