1/*
2Copyright 2014 The Perkeep Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8     http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package images
18
19import (
20	"bytes"
21	"image"
22	"image/jpeg"
23	"io"
24	"io/ioutil"
25	"testing"
26
27	"perkeep.org/internal/images/fastjpeg"
28	"perkeep.org/internal/images/resize"
29)
30
31// The decode routines being benchmarked in this file will use these bytes for
32// their in-memory io.Readers.
33var jpegBytes []byte
34
35func init() {
36	// Create image with non-uniform color to make decoding more realistic.
37	// Solid color jpeg images decode faster than non-uniform images.
38	b := new(bytes.Buffer)
39	w, h := 4000, 4000
40	im := image.NewNRGBA(image.Rect(0, 0, w, h))
41	for i := range im.Pix {
42		switch {
43		case i%4 == 3:
44			im.Pix[i] = 255
45		default:
46			im.Pix[i] = uint8(i)
47		}
48	}
49	if err := jpeg.Encode(b, im, nil); err != nil {
50		panic(err)
51	}
52	jpegBytes = b.Bytes()
53}
54
55type decodeFunc func(r io.Reader) (image.Image, string, error)
56
57func BenchmarkStdlib(b *testing.B) {
58	common(b, image.Decode)
59}
60
61func decodeDownsample(factor int) decodeFunc {
62	return func(r io.Reader) (image.Image, string, error) {
63		im, err := fastjpeg.DecodeDownsample(r, factor)
64		return im, "jpeg", err
65	}
66}
67
68func BenchmarkDjpeg1(b *testing.B) {
69	if !fastjpeg.Available() {
70		b.Skip("Skipping benchmark, djpeg unavailable.")
71	}
72	common(b, decodeDownsample(1))
73}
74
75func BenchmarkDjpeg2(b *testing.B) {
76	if !fastjpeg.Available() {
77		b.Skip("Skipping benchmark, djpeg unavailable.")
78	}
79	common(b, decodeDownsample(2))
80}
81
82func BenchmarkDjpeg4(b *testing.B) {
83	if !fastjpeg.Available() {
84		b.Skip("Skipping benchmark, djpeg unavailable.")
85	}
86	common(b, decodeDownsample(4))
87}
88
89func BenchmarkDjpeg8(b *testing.B) {
90	if !fastjpeg.Available() {
91		b.Skip("Skipping benchmark, djpeg unavailable.")
92	}
93	common(b, decodeDownsample(8))
94}
95
96func testRun(b testing.TB, decode decodeFunc) {
97	if !fastjpeg.Available() {
98		b.Skip("Skipping benchmark, djpeg unavailable.")
99	}
100	im, _, err := decode(bytes.NewReader(jpegBytes))
101	if err != nil {
102		b.Fatal(err)
103	}
104	rect := im.Bounds()
105	w, h := 128, 128
106	im = resize.Resize(im, rect, w, h)
107	err = jpeg.Encode(ioutil.Discard, im, nil)
108	if err != nil {
109		b.Fatal(err)
110	}
111}
112
113func common(b *testing.B, decode decodeFunc) {
114	for i := 0; i < b.N; i++ {
115		testRun(b, decode)
116	}
117}
118
119func TestStdlib(t *testing.T) {
120	testRun(t, decodeDownsample(1))
121}
122
123func TestDjpeg1(t *testing.T) {
124	testRun(t, decodeDownsample(1))
125}
126
127func TestDjpeg2(t *testing.T) {
128	testRun(t, decodeDownsample(2))
129}
130
131func TestDjpeg4(t *testing.T) {
132	testRun(t, decodeDownsample(4))
133}
134
135func TestDjpeg8(t *testing.T) {
136	testRun(t, decodeDownsample(8))
137}
138