github.com/shijuvar/go@v0.0.0-20141209052335-e8f13700b70c/src/image/gif/reader_test.go (about)

     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.
     4  
     5  package gif
     6  
     7  import (
     8  	"bytes"
     9  	"compress/lzw"
    10  	"image"
    11  	"image/color"
    12  	"reflect"
    13  	"testing"
    14  )
    15  
    16  // header, palette and trailer are parts of a valid 2x1 GIF image.
    17  const (
    18  	headerStr = "GIF89a" +
    19  		"\x02\x00\x01\x00" + // width=2, height=1
    20  		"\x80\x00\x00" // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
    21  	paletteStr = "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
    22  	trailerStr = "\x3b"
    23  )
    24  
    25  // lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
    26  func lzwEncode(n int) []byte {
    27  	b := &bytes.Buffer{}
    28  	w := lzw.NewWriter(b, lzw.LSB, 2)
    29  	w.Write(make([]byte, n))
    30  	w.Close()
    31  	return b.Bytes()
    32  }
    33  
    34  func TestDecode(t *testing.T) {
    35  	testCases := []struct {
    36  		nPix    int  // The number of pixels in the image data.
    37  		extra   bool // Whether to write an extra block after the LZW-encoded data.
    38  		wantErr error
    39  	}{
    40  		{0, false, errNotEnough},
    41  		{1, false, errNotEnough},
    42  		{2, false, nil},
    43  		{2, true, errTooMuch},
    44  		{3, false, errTooMuch},
    45  	}
    46  	for _, tc := range testCases {
    47  		b := &bytes.Buffer{}
    48  		b.WriteString(headerStr)
    49  		b.WriteString(paletteStr)
    50  		// Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2
    51  		// then this should result in an invalid GIF image. First, write a
    52  		// magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags
    53  		// byte, and 2-bit LZW literals.
    54  		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
    55  		if tc.nPix > 0 {
    56  			enc := lzwEncode(tc.nPix)
    57  			if len(enc) > 0xff {
    58  				t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
    59  				continue
    60  			}
    61  			b.WriteByte(byte(len(enc)))
    62  			b.Write(enc)
    63  		}
    64  		if tc.extra {
    65  			b.WriteString("\x01\x02") // A 1-byte payload with an 0x02 byte.
    66  		}
    67  		b.WriteByte(0x00) // An empty block signifies the end of the image data.
    68  		b.WriteString(trailerStr)
    69  
    70  		got, err := Decode(b)
    71  		if err != tc.wantErr {
    72  			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, err, tc.wantErr)
    73  		}
    74  
    75  		if tc.wantErr != nil {
    76  			continue
    77  		}
    78  		want := &image.Paletted{
    79  			Pix:    []uint8{0, 0},
    80  			Stride: 2,
    81  			Rect:   image.Rect(0, 0, 2, 1),
    82  			Palette: color.Palette{
    83  				color.RGBA{0x10, 0x20, 0x30, 0xff},
    84  				color.RGBA{0x40, 0x50, 0x60, 0xff},
    85  			},
    86  		}
    87  		if !reflect.DeepEqual(got, want) {
    88  			t.Errorf("nPix=%d, extra=%t\ngot  %v\nwant %v", tc.nPix, tc.extra, got, want)
    89  		}
    90  	}
    91  }
    92  
    93  func TestTransparentIndex(t *testing.T) {
    94  	b := &bytes.Buffer{}
    95  	b.WriteString(headerStr)
    96  	b.WriteString(paletteStr)
    97  	for transparentIndex := 0; transparentIndex < 3; transparentIndex++ {
    98  		if transparentIndex < 2 {
    99  			// Write the graphic control for the transparent index.
   100  			b.WriteString("\x21\xf9\x00\x01\x00\x00")
   101  			b.WriteByte(byte(transparentIndex))
   102  			b.WriteByte(0)
   103  		}
   104  		// Write an image with bounds 2x1, as per TestDecode.
   105  		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
   106  		enc := lzwEncode(2)
   107  		if len(enc) > 0xff {
   108  			t.Fatalf("compressed length %d is too large", len(enc))
   109  		}
   110  		b.WriteByte(byte(len(enc)))
   111  		b.Write(enc)
   112  		b.WriteByte(0x00)
   113  	}
   114  	b.WriteString(trailerStr)
   115  
   116  	g, err := DecodeAll(b)
   117  	if err != nil {
   118  		t.Fatalf("DecodeAll: %v", err)
   119  	}
   120  	c0 := color.RGBA{paletteStr[0], paletteStr[1], paletteStr[2], 0xff}
   121  	c1 := color.RGBA{paletteStr[3], paletteStr[4], paletteStr[5], 0xff}
   122  	cz := color.RGBA{}
   123  	wants := []color.Palette{
   124  		{cz, c1},
   125  		{c0, cz},
   126  		{c0, c1},
   127  	}
   128  	if len(g.Image) != len(wants) {
   129  		t.Fatalf("got %d images, want %d", len(g.Image), len(wants))
   130  	}
   131  	for i, want := range wants {
   132  		got := g.Image[i].Palette
   133  		if !reflect.DeepEqual(got, want) {
   134  			t.Errorf("palette #%d:\ngot  %v\nwant %v", i, got, want)
   135  		}
   136  	}
   137  }
   138  
   139  // testGIF is a simple GIF that we can modify to test different scenarios.
   140  var testGIF = []byte{
   141  	'G', 'I', 'F', '8', '9', 'a',
   142  	1, 0, 1, 0, // w=1, h=1 (6)
   143  	128, 0, 0, // headerFields, bg, aspect (10)
   144  	0, 0, 0, 1, 1, 1, // color map and graphics control (13)
   145  	0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
   146  	// frame 1 (0,0 - 1,1)
   147  	0x2c,
   148  	0x00, 0x00, 0x00, 0x00,
   149  	0x01, 0x00, 0x01, 0x00, // (32)
   150  	0x00,
   151  	0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels
   152  	// trailer
   153  	0x3b,
   154  }
   155  
   156  func try(t *testing.T, b []byte, want string) {
   157  	_, err := DecodeAll(bytes.NewReader(b))
   158  	var got string
   159  	if err != nil {
   160  		got = err.Error()
   161  	}
   162  	if got != want {
   163  		t.Fatalf("got %v, want %v", got, want)
   164  	}
   165  }
   166  
   167  func TestBounds(t *testing.T) {
   168  	// Make a local copy of testGIF.
   169  	gif := make([]byte, len(testGIF))
   170  	copy(gif, testGIF)
   171  	// Make the bounds too big, just by one.
   172  	gif[32] = 2
   173  	want := "gif: frame bounds larger than image bounds"
   174  	try(t, gif, want)
   175  
   176  	// Make the bounds too small; does not trigger bounds
   177  	// check, but now there's too much data.
   178  	gif[32] = 0
   179  	want = "gif: too much image data"
   180  	try(t, gif, want)
   181  	gif[32] = 1
   182  
   183  	// Make the bounds really big, expect an error.
   184  	want = "gif: frame bounds larger than image bounds"
   185  	for i := 0; i < 4; i++ {
   186  		gif[32+i] = 0xff
   187  	}
   188  	try(t, gif, want)
   189  }
   190  
   191  func TestNoPalette(t *testing.T) {
   192  	b := &bytes.Buffer{}
   193  
   194  	// Manufacture a GIF with no palette, so any pixel at all
   195  	// will be invalid.
   196  	b.WriteString(headerStr[:len(headerStr)-3])
   197  	b.WriteString("\x00\x00\x00") // No global palette.
   198  
   199  	// Image descriptor: 2x1, no local palette.
   200  	b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
   201  
   202  	// Encode the pixels: neither is in range, because there is no palette.
   203  	pix := []byte{0, 128}
   204  	enc := &bytes.Buffer{}
   205  	w := lzw.NewWriter(enc, lzw.LSB, 2)
   206  	w.Write(pix)
   207  	w.Close()
   208  	b.WriteByte(byte(len(enc.Bytes())))
   209  	b.Write(enc.Bytes())
   210  	b.WriteByte(0x00) // An empty block signifies the end of the image data.
   211  
   212  	b.WriteString(trailerStr)
   213  
   214  	try(t, b.Bytes(), "gif: invalid pixel value")
   215  }
   216  
   217  func TestPixelOutsidePaletteRange(t *testing.T) {
   218  	for _, pval := range []byte{0, 1, 2, 3, 255} {
   219  		b := &bytes.Buffer{}
   220  
   221  		// Manufacture a GIF with a 2 color palette.
   222  		b.WriteString(headerStr)
   223  		b.WriteString(paletteStr)
   224  
   225  		// Image descriptor: 2x1, no local palette.
   226  		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
   227  
   228  		// Encode the pixels; some pvals trigger the expected error.
   229  		pix := []byte{pval, pval}
   230  		enc := &bytes.Buffer{}
   231  		w := lzw.NewWriter(enc, lzw.LSB, 2)
   232  		w.Write(pix)
   233  		w.Close()
   234  		b.WriteByte(byte(len(enc.Bytes())))
   235  		b.Write(enc.Bytes())
   236  		b.WriteByte(0x00) // An empty block signifies the end of the image data.
   237  
   238  		b.WriteString(trailerStr)
   239  
   240  		// No error expected, unless the pixels are beyond the 2 color palette.
   241  		want := ""
   242  		if pval >= 2 {
   243  			want = "gif: invalid pixel value"
   244  		}
   245  		try(t, b.Bytes(), want)
   246  	}
   247  }