github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/src/image/gif/writer_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  	"image"
    10  	"image/color"
    11  	_ "image/png"
    12  	"io/ioutil"
    13  	"math/rand"
    14  	"os"
    15  	"testing"
    16  )
    17  
    18  func readImg(filename string) (image.Image, error) {
    19  	f, err := os.Open(filename)
    20  	if err != nil {
    21  		return nil, err
    22  	}
    23  	defer f.Close()
    24  	m, _, err := image.Decode(f)
    25  	return m, err
    26  }
    27  
    28  func readGIF(filename string) (*GIF, error) {
    29  	f, err := os.Open(filename)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  	defer f.Close()
    34  	return DecodeAll(f)
    35  }
    36  
    37  func delta(u0, u1 uint32) int64 {
    38  	d := int64(u0) - int64(u1)
    39  	if d < 0 {
    40  		return -d
    41  	}
    42  	return d
    43  }
    44  
    45  // averageDelta returns the average delta in RGB space. The two images must
    46  // have the same bounds.
    47  func averageDelta(m0, m1 image.Image) int64 {
    48  	b := m0.Bounds()
    49  	var sum, n int64
    50  	for y := b.Min.Y; y < b.Max.Y; y++ {
    51  		for x := b.Min.X; x < b.Max.X; x++ {
    52  			c0 := m0.At(x, y)
    53  			c1 := m1.At(x, y)
    54  			r0, g0, b0, _ := c0.RGBA()
    55  			r1, g1, b1, _ := c1.RGBA()
    56  			sum += delta(r0, r1)
    57  			sum += delta(g0, g1)
    58  			sum += delta(b0, b1)
    59  			n += 3
    60  		}
    61  	}
    62  	return sum / n
    63  }
    64  
    65  var testCase = []struct {
    66  	filename  string
    67  	tolerance int64
    68  }{
    69  	{"../testdata/video-001.png", 1 << 12},
    70  	{"../testdata/video-001.gif", 0},
    71  	{"../testdata/video-001.interlaced.gif", 0},
    72  }
    73  
    74  func TestWriter(t *testing.T) {
    75  	for _, tc := range testCase {
    76  		m0, err := readImg(tc.filename)
    77  		if err != nil {
    78  			t.Error(tc.filename, err)
    79  			continue
    80  		}
    81  		var buf bytes.Buffer
    82  		err = Encode(&buf, m0, nil)
    83  		if err != nil {
    84  			t.Error(tc.filename, err)
    85  			continue
    86  		}
    87  		m1, err := Decode(&buf)
    88  		if err != nil {
    89  			t.Error(tc.filename, err)
    90  			continue
    91  		}
    92  		if m0.Bounds() != m1.Bounds() {
    93  			t.Errorf("%s, bounds differ: %v and %v", tc.filename, m0.Bounds(), m1.Bounds())
    94  			continue
    95  		}
    96  		// Compare the average delta to the tolerance level.
    97  		avgDelta := averageDelta(m0, m1)
    98  		if avgDelta > tc.tolerance {
    99  			t.Errorf("%s: average delta is too high. expected: %d, got %d", tc.filename, tc.tolerance, avgDelta)
   100  			continue
   101  		}
   102  	}
   103  }
   104  
   105  func TestSubImage(t *testing.T) {
   106  	m0, err := readImg("../testdata/video-001.gif")
   107  	if err != nil {
   108  		t.Fatalf("readImg: %v", err)
   109  	}
   110  	m0 = m0.(*image.Paletted).SubImage(image.Rect(0, 0, 50, 30))
   111  	var buf bytes.Buffer
   112  	err = Encode(&buf, m0, nil)
   113  	if err != nil {
   114  		t.Fatalf("Encode: %v", err)
   115  	}
   116  	m1, err := Decode(&buf)
   117  	if err != nil {
   118  		t.Fatalf("Decode: %v", err)
   119  	}
   120  	if m0.Bounds() != m1.Bounds() {
   121  		t.Fatalf("bounds differ: %v and %v", m0.Bounds(), m1.Bounds())
   122  	}
   123  	if averageDelta(m0, m1) != 0 {
   124  		t.Fatalf("images differ")
   125  	}
   126  }
   127  
   128  var frames = []string{
   129  	"../testdata/video-001.gif",
   130  	"../testdata/video-005.gray.gif",
   131  }
   132  
   133  func TestEncodeAll(t *testing.T) {
   134  	g0 := &GIF{
   135  		Image:     make([]*image.Paletted, len(frames)),
   136  		Delay:     make([]int, len(frames)),
   137  		LoopCount: 5,
   138  	}
   139  	for i, f := range frames {
   140  		m, err := readGIF(f)
   141  		if err != nil {
   142  			t.Fatal(f, err)
   143  		}
   144  		g0.Image[i] = m.Image[0]
   145  	}
   146  	var buf bytes.Buffer
   147  	if err := EncodeAll(&buf, g0); err != nil {
   148  		t.Fatal("EncodeAll:", err)
   149  	}
   150  	g1, err := DecodeAll(&buf)
   151  	if err != nil {
   152  		t.Fatal("DecodeAll:", err)
   153  	}
   154  	if g0.LoopCount != g1.LoopCount {
   155  		t.Errorf("loop counts differ: %d and %d", g0.LoopCount, g1.LoopCount)
   156  	}
   157  	for i := range g0.Image {
   158  		m0, m1 := g0.Image[i], g1.Image[i]
   159  		if m0.Bounds() != m1.Bounds() {
   160  			t.Errorf("%s, bounds differ: %v and %v", frames[i], m0.Bounds(), m1.Bounds())
   161  		}
   162  		d0, d1 := g0.Delay[i], g1.Delay[i]
   163  		if d0 != d1 {
   164  			t.Errorf("%s: delay values differ: %d and %d", frames[i], d0, d1)
   165  		}
   166  	}
   167  
   168  	g1.Delay = make([]int, 1)
   169  	if err := EncodeAll(ioutil.Discard, g1); err == nil {
   170  		t.Error("expected error from mismatched delay and image slice lengths")
   171  	}
   172  	if err := EncodeAll(ioutil.Discard, &GIF{}); err == nil {
   173  		t.Error("expected error from providing empty gif")
   174  	}
   175  }
   176  
   177  func BenchmarkEncode(b *testing.B) {
   178  	b.StopTimer()
   179  
   180  	bo := image.Rect(0, 0, 640, 480)
   181  	rnd := rand.New(rand.NewSource(123))
   182  
   183  	// Restrict to a 256-color paletted image to avoid quantization path.
   184  	palette := make(color.Palette, 256)
   185  	for i := range palette {
   186  		palette[i] = color.RGBA{
   187  			uint8(rnd.Intn(256)),
   188  			uint8(rnd.Intn(256)),
   189  			uint8(rnd.Intn(256)),
   190  			255,
   191  		}
   192  	}
   193  	img := image.NewPaletted(image.Rect(0, 0, 640, 480), palette)
   194  	for y := bo.Min.Y; y < bo.Max.Y; y++ {
   195  		for x := bo.Min.X; x < bo.Max.X; x++ {
   196  			img.Set(x, y, palette[rnd.Intn(256)])
   197  		}
   198  	}
   199  
   200  	b.SetBytes(640 * 480 * 4)
   201  	b.StartTimer()
   202  	for i := 0; i < b.N; i++ {
   203  		Encode(ioutil.Discard, img, nil)
   204  	}
   205  }
   206  
   207  func BenchmarkQuantizedEncode(b *testing.B) {
   208  	b.StopTimer()
   209  	img := image.NewRGBA(image.Rect(0, 0, 640, 480))
   210  	bo := img.Bounds()
   211  	rnd := rand.New(rand.NewSource(123))
   212  	for y := bo.Min.Y; y < bo.Max.Y; y++ {
   213  		for x := bo.Min.X; x < bo.Max.X; x++ {
   214  			img.SetRGBA(x, y, color.RGBA{
   215  				uint8(rnd.Intn(256)),
   216  				uint8(rnd.Intn(256)),
   217  				uint8(rnd.Intn(256)),
   218  				255,
   219  			})
   220  		}
   221  	}
   222  	b.SetBytes(640 * 480 * 4)
   223  	b.StartTimer()
   224  	for i := 0; i < b.N; i++ {
   225  		Encode(ioutil.Discard, img, nil)
   226  	}
   227  }