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
5package bmp
6
7import (
8	"bytes"
9	"fmt"
10	"image"
11	"image/draw"
12	"io/ioutil"
13	"os"
14	"testing"
15	"time"
16)
17
18func openImage(filename string) (image.Image, error) {
19	f, err := os.Open(testdataDir + filename)
20	if err != nil {
21		return nil, err
22	}
23	defer f.Close()
24	return Decode(f)
25}
26
27func convertToRGBA(in image.Image) image.Image {
28	b := in.Bounds()
29	out := image.NewRGBA(b)
30	draw.Draw(out, b, in, b.Min, draw.Src)
31	return out
32}
33
34func convertToNRGBA(in image.Image) image.Image {
35	b := in.Bounds()
36	out := image.NewNRGBA(b)
37	draw.Draw(out, b, in, b.Min, draw.Src)
38	return out
39}
40
41func TestEncode(t *testing.T) {
42	testCases := []string{
43		"video-001.bmp",
44		"yellow_rose-small.bmp",
45	}
46
47	for _, tc := range testCases {
48		img0, err := openImage(tc)
49		if err != nil {
50			t.Errorf("%s: Open BMP: %v", tc, err)
51			continue
52		}
53
54		buf := new(bytes.Buffer)
55		err = Encode(buf, img0)
56		if err != nil {
57			t.Errorf("%s: Encode BMP: %v", tc, err)
58			continue
59		}
60
61		img1, err := Decode(buf)
62		if err != nil {
63			t.Errorf("%s: Decode BMP: %v", tc, err)
64			continue
65		}
66
67		err = compare(img0, img1)
68		if err != nil {
69			t.Errorf("%s: Compare BMP: %v", tc, err)
70			continue
71		}
72
73		buf2 := new(bytes.Buffer)
74		rgba := convertToRGBA(img0)
75		err = Encode(buf2, rgba)
76		if err != nil {
77			t.Errorf("%s: Encode pre-multiplied BMP: %v", tc, err)
78			continue
79		}
80
81		img2, err := Decode(buf2)
82		if err != nil {
83			t.Errorf("%s: Decode pre-multiplied BMP: %v", tc, err)
84			continue
85		}
86
87		// We need to do another round trip to NRGBA to compare to, since
88		// the conversion process is lossy.
89		img3 := convertToNRGBA(rgba)
90
91		err = compare(img3, img2)
92		if err != nil {
93			t.Errorf("%s: Compare pre-multiplied BMP: %v", tc, err)
94		}
95	}
96}
97
98// TestZeroWidthVeryLargeHeight tests that encoding and decoding a degenerate
99// image with zero width but over one billion pixels in height is faster than
100// naively calling an io.Reader or io.Writer method once per row.
101func TestZeroWidthVeryLargeHeight(t *testing.T) {
102	c := make(chan error, 1)
103	go func() {
104		b := image.Rect(0, 0, 0, 0x3fffffff)
105		var buf bytes.Buffer
106		if err := Encode(&buf, image.NewRGBA(b)); err != nil {
107			c <- err
108			return
109		}
110		m, err := Decode(&buf)
111		if err != nil {
112			c <- err
113			return
114		}
115		if got := m.Bounds(); got != b {
116			c <- fmt.Errorf("bounds: got %v, want %v", got, b)
117			return
118		}
119		c <- nil
120	}()
121	select {
122	case err := <-c:
123		if err != nil {
124			t.Fatal(err)
125		}
126	case <-time.After(3 * time.Second):
127		t.Fatalf("timed out")
128	}
129}
130
131// BenchmarkEncode benchmarks the encoding of an image.
132func BenchmarkEncode(b *testing.B) {
133	img, err := openImage("video-001.bmp")
134	if err != nil {
135		b.Fatal(err)
136	}
137	s := img.Bounds().Size()
138	b.SetBytes(int64(s.X * s.Y * 4))
139	b.ResetTimer()
140	for i := 0; i < b.N; i++ {
141		Encode(ioutil.Discard, img)
142	}
143}
144