Skip to content

Commit

Permalink
image/gif: don't let the per-frame transparent index modify the global
Browse files Browse the repository at this point in the history
palette.

Fixes golang#7993.

LGTM=r
R=r
CC=golang-codereviews, james.jdunne
https://golang.org/cl/138600043
  • Loading branch information
nigeltao committed Sep 22, 2014
1 parent 3b2577c commit 0be3176
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 10 deletions.
7 changes: 6 additions & 1 deletion src/image/gif/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down
64 changes: 55 additions & 9 deletions src/image/gif/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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',
Expand Down

0 comments on commit 0be3176

Please sign in to comment.