1// +build go1.5
2
3/*
4Copyright (c) 2014, Charlie Vieth <charlie.vieth@gmail.com>
5
6Permission to use, copy, modify, and/or distribute this software for any purpose
7with or without fee is hereby granted, provided that the above copyright notice
8and this permission notice appear in all copies.
9
10THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
11REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
12FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
13INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
16THIS SOFTWARE.
17*/
18
19package resize
20
21import (
22	"image"
23	"image/color"
24	"testing"
25)
26
27type Image interface {
28	image.Image
29	SubImage(image.Rectangle) image.Image
30}
31
32func TestImage(t *testing.T) {
33	testImage := []Image{
34		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio420),
35		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio422),
36		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio440),
37		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio444),
38		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio411),
39		newYCC(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio410),
40	}
41	for _, m := range testImage {
42		if !image.Rect(0, 0, 10, 10).Eq(m.Bounds()) {
43			t.Errorf("%T: want bounds %v, got %v",
44				m, image.Rect(0, 0, 10, 10), m.Bounds())
45			continue
46		}
47		m = m.SubImage(image.Rect(3, 2, 9, 8)).(Image)
48		if !image.Rect(3, 2, 9, 8).Eq(m.Bounds()) {
49			t.Errorf("%T: sub-image want bounds %v, got %v",
50				m, image.Rect(3, 2, 9, 8), m.Bounds())
51			continue
52		}
53		// Test that taking an empty sub-image starting at a corner does not panic.
54		m.SubImage(image.Rect(0, 0, 0, 0))
55		m.SubImage(image.Rect(10, 0, 10, 0))
56		m.SubImage(image.Rect(0, 10, 0, 10))
57		m.SubImage(image.Rect(10, 10, 10, 10))
58	}
59}
60
61func TestConvertYCbCr(t *testing.T) {
62	testImage := []Image{
63		image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio420),
64		image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio422),
65		image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio440),
66		image.NewYCbCr(image.Rect(0, 0, 50, 50), image.YCbCrSubsampleRatio444),
67		image.NewYCbCr(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio411),
68		image.NewYCbCr(image.Rect(0, 0, 10, 10), image.YCbCrSubsampleRatio410),
69	}
70	for _, img := range testImage {
71		m := img.(*image.YCbCr)
72		for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
73			for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
74				yi := m.YOffset(x, y)
75				ci := m.COffset(x, y)
76				m.Y[yi] = uint8(16*y + x)
77				m.Cb[ci] = uint8(y + 16*x)
78				m.Cr[ci] = uint8(y + 16*x)
79			}
80		}
81
82		// test conversion from YCbCr to ycc
83		yc := imageYCbCrToYCC(m)
84		for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
85			for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
86				ystride := 3 * (m.Rect.Max.X - m.Rect.Min.X)
87				xstride := 3
88				yi := m.YOffset(x, y)
89				ci := m.COffset(x, y)
90				si := (y * ystride) + (x * xstride)
91				if m.Y[yi] != yc.Pix[si] {
92					t.Errorf("Err Y - found: %d expected: %d x: %d y: %d yi: %d si: %d",
93						m.Y[yi], yc.Pix[si], x, y, yi, si)
94				}
95				if m.Cb[ci] != yc.Pix[si+1] {
96					t.Errorf("Err Cb - found: %d expected: %d x: %d y: %d ci: %d si: %d",
97						m.Cb[ci], yc.Pix[si+1], x, y, ci, si+1)
98				}
99				if m.Cr[ci] != yc.Pix[si+2] {
100					t.Errorf("Err Cr - found: %d expected: %d x: %d y: %d ci: %d si: %d",
101						m.Cr[ci], yc.Pix[si+2], x, y, ci, si+2)
102				}
103			}
104		}
105
106		// test conversion from ycc back to YCbCr
107		ym := yc.YCbCr()
108		for y := m.Rect.Min.Y; y < m.Rect.Max.Y; y++ {
109			for x := m.Rect.Min.X; x < m.Rect.Max.X; x++ {
110				yi := m.YOffset(x, y)
111				ci := m.COffset(x, y)
112				if m.Y[yi] != ym.Y[yi] {
113					t.Errorf("Err Y - found: %d expected: %d x: %d y: %d yi: %d",
114						m.Y[yi], ym.Y[yi], x, y, yi)
115				}
116				if m.Cb[ci] != ym.Cb[ci] {
117					t.Errorf("Err Cb - found: %d expected: %d x: %d y: %d ci: %d",
118						m.Cb[ci], ym.Cb[ci], x, y, ci)
119				}
120				if m.Cr[ci] != ym.Cr[ci] {
121					t.Errorf("Err Cr - found: %d expected: %d x: %d y: %d ci: %d",
122						m.Cr[ci], ym.Cr[ci], x, y, ci)
123				}
124			}
125		}
126	}
127}
128
129func TestYCbCr(t *testing.T) {
130	rects := []image.Rectangle{
131		image.Rect(0, 0, 16, 16),
132		image.Rect(1, 0, 16, 16),
133		image.Rect(0, 1, 16, 16),
134		image.Rect(1, 1, 16, 16),
135		image.Rect(1, 1, 15, 16),
136		image.Rect(1, 1, 16, 15),
137		image.Rect(1, 1, 15, 15),
138		image.Rect(2, 3, 14, 15),
139		image.Rect(7, 0, 7, 16),
140		image.Rect(0, 8, 16, 8),
141		image.Rect(0, 0, 10, 11),
142		image.Rect(5, 6, 16, 16),
143		image.Rect(7, 7, 8, 8),
144		image.Rect(7, 8, 8, 9),
145		image.Rect(8, 7, 9, 8),
146		image.Rect(8, 8, 9, 9),
147		image.Rect(7, 7, 17, 17),
148		image.Rect(8, 8, 17, 17),
149		image.Rect(9, 9, 17, 17),
150		image.Rect(10, 10, 17, 17),
151	}
152	subsampleRatios := []image.YCbCrSubsampleRatio{
153		image.YCbCrSubsampleRatio444,
154		image.YCbCrSubsampleRatio422,
155		image.YCbCrSubsampleRatio420,
156		image.YCbCrSubsampleRatio440,
157	}
158	deltas := []image.Point{
159		image.Pt(0, 0),
160		image.Pt(1000, 1001),
161		image.Pt(5001, -400),
162		image.Pt(-701, -801),
163	}
164	for _, r := range rects {
165		for _, subsampleRatio := range subsampleRatios {
166			for _, delta := range deltas {
167				testYCbCr(t, r, subsampleRatio, delta)
168			}
169		}
170		if testing.Short() {
171			break
172		}
173	}
174}
175
176func testYCbCr(t *testing.T, r image.Rectangle, subsampleRatio image.YCbCrSubsampleRatio, delta image.Point) {
177	// Create a YCbCr image m, whose bounds are r translated by (delta.X, delta.Y).
178	r1 := r.Add(delta)
179	img := image.NewYCbCr(r1, subsampleRatio)
180
181	// Initialize img's pixels. For 422 and 420 subsampling, some of the Cb and Cr elements
182	// will be set multiple times. That's OK. We just want to avoid a uniform image.
183	for y := r1.Min.Y; y < r1.Max.Y; y++ {
184		for x := r1.Min.X; x < r1.Max.X; x++ {
185			yi := img.YOffset(x, y)
186			ci := img.COffset(x, y)
187			img.Y[yi] = uint8(16*y + x)
188			img.Cb[ci] = uint8(y + 16*x)
189			img.Cr[ci] = uint8(y + 16*x)
190		}
191	}
192
193	m := imageYCbCrToYCC(img)
194
195	// Make various sub-images of m.
196	for y0 := delta.Y + 3; y0 < delta.Y+7; y0++ {
197		for y1 := delta.Y + 8; y1 < delta.Y+13; y1++ {
198			for x0 := delta.X + 3; x0 < delta.X+7; x0++ {
199				for x1 := delta.X + 8; x1 < delta.X+13; x1++ {
200					subRect := image.Rect(x0, y0, x1, y1)
201					sub := m.SubImage(subRect).(*ycc)
202
203					// For each point in the sub-image's bounds, check that m.At(x, y) equals sub.At(x, y).
204					for y := sub.Rect.Min.Y; y < sub.Rect.Max.Y; y++ {
205						for x := sub.Rect.Min.X; x < sub.Rect.Max.X; x++ {
206							color0 := m.At(x, y).(color.YCbCr)
207							color1 := sub.At(x, y).(color.YCbCr)
208							if color0 != color1 {
209								t.Errorf("r=%v, subsampleRatio=%v, delta=%v, x=%d, y=%d, color0=%v, color1=%v",
210									r, subsampleRatio, delta, x, y, color0, color1)
211								return
212							}
213						}
214					}
215				}
216			}
217		}
218	}
219}
220