1package imaging
2
3import (
4	"bytes"
5	"image"
6	"image/color"
7	"testing"
8)
9
10func TestNew(t *testing.T) {
11	testCases := []struct {
12		name      string
13		w, h      int
14		c         color.Color
15		dstBounds image.Rectangle
16		dstPix    []uint8
17	}{
18		{
19			"New 1x1 transparent",
20			1, 1,
21			color.Transparent,
22			image.Rect(0, 0, 1, 1),
23			[]uint8{0x00, 0x00, 0x00, 0x00},
24		},
25		{
26			"New 1x2 red",
27			1, 2,
28			color.RGBA{255, 0, 0, 255},
29			image.Rect(0, 0, 1, 2),
30			[]uint8{0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff},
31		},
32		{
33			"New 2x1 white",
34			2, 1,
35			color.White,
36			image.Rect(0, 0, 2, 1),
37			[]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
38		},
39		{
40			"New 3x3 with alpha",
41			3, 3,
42			color.NRGBA{0x01, 0x23, 0x45, 0x67},
43			image.Rect(0, 0, 3, 3),
44			[]uint8{
45				0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67,
46				0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67,
47				0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67, 0x01, 0x23, 0x45, 0x67,
48			},
49		},
50		{
51			"New 0x0 white",
52			0, 0,
53			color.White,
54			image.Rect(0, 0, 0, 0),
55			nil,
56		},
57		{
58			"New 800x600 custom",
59			800, 600,
60			color.NRGBA{1, 2, 3, 4},
61			image.Rect(0, 0, 800, 600),
62			bytes.Repeat([]byte{1, 2, 3, 4}, 800*600),
63		},
64	}
65
66	for _, tc := range testCases {
67		t.Run(tc.name, func(t *testing.T) {
68			got := New(tc.w, tc.h, tc.c)
69			want := image.NewNRGBA(tc.dstBounds)
70			want.Pix = tc.dstPix
71			if !compareNRGBA(got, want, 0) {
72				t.Fatalf("got result %#v want %#v", got, want)
73			}
74		})
75	}
76}
77
78func BenchmarkNew(b *testing.B) {
79	b.ReportAllocs()
80	for i := 0; i < b.N; i++ {
81		New(1024, 1024, color.White)
82	}
83}
84
85func TestClone(t *testing.T) {
86	testCases := []struct {
87		name string
88		src  image.Image
89		want *image.NRGBA
90	}{
91		{
92			"Clone NRGBA",
93			&image.NRGBA{
94				Rect:   image.Rect(-1, -1, 0, 1),
95				Stride: 1 * 4,
96				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
97			},
98			&image.NRGBA{
99				Rect:   image.Rect(0, 0, 1, 2),
100				Stride: 1 * 4,
101				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
102			},
103		},
104		{
105			"Clone NRGBA64",
106			&image.NRGBA64{
107				Rect:   image.Rect(-1, -1, 0, 1),
108				Stride: 1 * 8,
109				Pix: []uint8{
110					0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
111					0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
112				},
113			},
114			&image.NRGBA{
115				Rect:   image.Rect(0, 0, 1, 2),
116				Stride: 1 * 4,
117				Pix:    []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
118			},
119		},
120		{
121			"Clone RGBA",
122			&image.RGBA{
123				Rect:   image.Rect(-1, -1, 0, 2),
124				Stride: 1 * 4,
125				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
126			},
127			&image.NRGBA{
128				Rect:   image.Rect(0, 0, 1, 3),
129				Stride: 1 * 4,
130				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
131			},
132		},
133		{
134			"Clone RGBA64",
135			&image.RGBA64{
136				Rect:   image.Rect(-1, -1, 0, 2),
137				Stride: 1 * 8,
138				Pix: []uint8{
139					0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140					0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
141					0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
142				},
143			},
144			&image.NRGBA{
145				Rect:   image.Rect(0, 0, 1, 3),
146				Stride: 1 * 4,
147				Pix:    []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
148			},
149		},
150		{
151			"Clone Gray",
152			&image.Gray{
153				Rect:   image.Rect(-1, -1, 0, 1),
154				Stride: 1 * 1,
155				Pix:    []uint8{0x11, 0xee},
156			},
157			&image.NRGBA{
158				Rect:   image.Rect(0, 0, 1, 2),
159				Stride: 1 * 4,
160				Pix:    []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
161			},
162		},
163		{
164			"Clone Gray16",
165			&image.Gray16{
166				Rect:   image.Rect(-1, -1, 0, 1),
167				Stride: 1 * 2,
168				Pix:    []uint8{0x11, 0x11, 0xee, 0xee},
169			},
170			&image.NRGBA{
171				Rect:   image.Rect(0, 0, 1, 2),
172				Stride: 1 * 4,
173				Pix:    []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
174			},
175		},
176		{
177			"Clone Alpha",
178			&image.Alpha{
179				Rect:   image.Rect(-1, -1, 0, 1),
180				Stride: 1 * 1,
181				Pix:    []uint8{0x11, 0xee},
182			},
183			&image.NRGBA{
184				Rect:   image.Rect(0, 0, 1, 2),
185				Stride: 1 * 4,
186				Pix:    []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
187			},
188		},
189		{
190			"Clone YCbCr",
191			&image.YCbCr{
192				Rect:           image.Rect(-1, -1, 5, 0),
193				SubsampleRatio: image.YCbCrSubsampleRatio444,
194				YStride:        6,
195				CStride:        6,
196				Y:              []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
197				Cb:             []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
198				Cr:             []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
199			},
200			&image.NRGBA{
201				Rect:   image.Rect(0, 0, 6, 1),
202				Stride: 6 * 4,
203				Pix: []uint8{
204					0x00, 0x00, 0x00, 0xff,
205					0xff, 0xff, 0xff, 0xff,
206					0x7f, 0x7f, 0x7f, 0xff,
207					0x7f, 0x00, 0x00, 0xff,
208					0x00, 0x7f, 0x00, 0xff,
209					0x00, 0x00, 0x7f, 0xff,
210				},
211			},
212		},
213		{
214			"Clone YCbCr 444",
215			&image.YCbCr{
216				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
217				Cb:             []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
218				Cr:             []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
219				YStride:        4,
220				CStride:        4,
221				SubsampleRatio: image.YCbCrSubsampleRatio444,
222				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
223			},
224			&image.NRGBA{
225				Pix:    []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
226				Stride: 16,
227				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
228			},
229		},
230		{
231			"Clone YCbCr 440",
232			&image.YCbCr{
233				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
234				Cb:             []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
235				Cr:             []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
236				YStride:        4,
237				CStride:        4,
238				SubsampleRatio: image.YCbCrSubsampleRatio440,
239				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
240			},
241			&image.NRGBA{
242				Pix:    []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
243				Stride: 16,
244				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
245			},
246		},
247		{
248			"Clone YCbCr 422",
249			&image.YCbCr{
250				Y:              []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
251				Cb:             []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
252				Cr:             []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
253				YStride:        4,
254				CStride:        2,
255				SubsampleRatio: image.YCbCrSubsampleRatio422,
256				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
257			},
258			&image.NRGBA{
259				Pix:    []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
260				Stride: 16,
261				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
262			},
263		},
264		{
265			"Clone YCbCr 420",
266			&image.YCbCr{
267				Y:       []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
268				Cb:      []uint8{0x01, 0xaa, 0x80, 0x80},
269				Cr:      []uint8{0x95, 0xb5, 0x80, 0x80},
270				YStride: 4, CStride: 2,
271				SubsampleRatio: image.YCbCrSubsampleRatio420,
272				Rect:           image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
273			},
274			&image.NRGBA{
275				Pix:    []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
276				Stride: 16,
277				Rect:   image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
278			},
279		},
280		{
281			"Clone Paletted",
282			&image.Paletted{
283				Rect:   image.Rect(-1, -1, 5, 0),
284				Stride: 6 * 1,
285				Palette: color.Palette{
286					color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
287					color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
288					color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
289					color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
290					color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
291					color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
292				},
293				Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
294			},
295			&image.NRGBA{
296				Rect:   image.Rect(0, 0, 6, 1),
297				Stride: 6 * 4,
298				Pix: []uint8{
299					0x00, 0x00, 0x00, 0xff,
300					0xff, 0xff, 0xff, 0xff,
301					0x7f, 0x7f, 0x7f, 0xff,
302					0x7f, 0x00, 0x00, 0xff,
303					0x00, 0x7f, 0x00, 0xff,
304					0x00, 0x00, 0x7f, 0xff,
305				},
306			},
307		},
308	}
309
310	for _, tc := range testCases {
311		t.Run(tc.name, func(t *testing.T) {
312			got := Clone(tc.src)
313			delta := 0
314			if _, ok := tc.src.(*image.YCbCr); ok {
315				delta = 1
316			}
317			if !compareNRGBA(got, tc.want, delta) {
318				t.Fatalf("got result %#v want %#v", got, tc.want)
319			}
320		})
321	}
322}
323
324func TestCrop(t *testing.T) {
325	testCases := []struct {
326		name string
327		src  image.Image
328		r    image.Rectangle
329		want *image.NRGBA
330	}{
331		{
332			"Crop 2x3 2x1",
333			&image.NRGBA{
334				Rect:   image.Rect(-1, -1, 1, 2),
335				Stride: 2 * 4,
336				Pix: []uint8{
337					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
338					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
339					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
340				},
341			},
342			image.Rect(-1, 0, 1, 1),
343			&image.NRGBA{
344				Rect:   image.Rect(0, 0, 2, 1),
345				Stride: 2 * 4,
346				Pix: []uint8{
347					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
348				},
349			},
350		},
351	}
352	for _, tc := range testCases {
353		t.Run(tc.name, func(t *testing.T) {
354			got := Crop(tc.src, tc.r)
355			if !compareNRGBA(got, tc.want, 0) {
356				t.Fatalf("got result %#v want %#v", got, tc.want)
357			}
358		})
359	}
360}
361
362func BenchmarkCrop(b *testing.B) {
363	b.ReportAllocs()
364	for i := 0; i < b.N; i++ {
365		Crop(testdataBranchesJPG, image.Rect(100, 100, 300, 300))
366	}
367}
368
369func TestCropCenter(t *testing.T) {
370	testCases := []struct {
371		name string
372		src  image.Image
373		w, h int
374		want *image.NRGBA
375	}{
376		{
377			"CropCenter 2x3 2x1",
378			&image.NRGBA{
379				Rect:   image.Rect(-1, -1, 1, 2),
380				Stride: 2 * 4,
381				Pix: []uint8{
382					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
383					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
384					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
385				},
386			},
387			2, 1,
388			&image.NRGBA{
389				Rect:   image.Rect(0, 0, 2, 1),
390				Stride: 2 * 4,
391				Pix: []uint8{
392					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
393				},
394			},
395		},
396		{
397			"CropCenter 2x3 0x1",
398			&image.NRGBA{
399				Rect:   image.Rect(-1, -1, 1, 2),
400				Stride: 2 * 4,
401				Pix: []uint8{
402					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
403					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
404					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
405				},
406			},
407			0, 1,
408			&image.NRGBA{
409				Rect:   image.Rect(0, 0, 0, 0),
410				Stride: 0,
411				Pix:    []uint8{},
412			},
413		},
414		{
415			"CropCenter 2x3 5x5",
416			&image.NRGBA{
417				Rect:   image.Rect(-1, -1, 1, 2),
418				Stride: 2 * 4,
419				Pix: []uint8{
420					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
421					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
422					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
423				},
424			},
425			5, 5,
426			&image.NRGBA{
427				Rect:   image.Rect(0, 0, 2, 3),
428				Stride: 2 * 4,
429				Pix: []uint8{
430					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
431					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
432					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
433				},
434			},
435		},
436	}
437	for _, tc := range testCases {
438		t.Run(tc.name, func(t *testing.T) {
439			got := CropCenter(tc.src, tc.w, tc.h)
440			if !compareNRGBA(got, tc.want, 0) {
441				t.Fatalf("got result %#v want %#v", got, tc.want)
442			}
443		})
444	}
445}
446
447func TestCropAnchor(t *testing.T) {
448	testCases := []struct {
449		name   string
450		src    image.Image
451		w, h   int
452		anchor Anchor
453		want   *image.NRGBA
454	}{
455		{
456			"CropAnchor 4x4 2x2 TopLeft",
457			&image.NRGBA{
458				Rect:   image.Rect(-1, -1, 3, 3),
459				Stride: 4 * 4,
460				Pix: []uint8{
461					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
462					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
463					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
464					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
465				},
466			},
467			2, 2,
468			TopLeft,
469			&image.NRGBA{
470				Rect:   image.Rect(0, 0, 2, 2),
471				Stride: 2 * 4,
472				Pix: []uint8{
473					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
474					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
475				},
476			},
477		},
478		{
479			"CropAnchor 4x4 2x2 Top",
480			&image.NRGBA{
481				Rect:   image.Rect(-1, -1, 3, 3),
482				Stride: 4 * 4,
483				Pix: []uint8{
484					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
485					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
486					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
487					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
488				},
489			},
490			2, 2,
491			Top,
492			&image.NRGBA{
493				Rect:   image.Rect(0, 0, 2, 2),
494				Stride: 2 * 4,
495				Pix: []uint8{
496					0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
497					0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
498				},
499			},
500		},
501		{
502			"CropAnchor 4x4 2x2 TopRight",
503			&image.NRGBA{
504				Rect:   image.Rect(-1, -1, 3, 3),
505				Stride: 4 * 4,
506				Pix: []uint8{
507					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
508					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
509					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
510					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
511				},
512			},
513			2, 2,
514			TopRight,
515			&image.NRGBA{
516				Rect:   image.Rect(0, 0, 2, 2),
517				Stride: 2 * 4,
518				Pix: []uint8{
519					0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
520					0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
521				},
522			},
523		},
524		{
525			"CropAnchor 4x4 2x2 Left",
526			&image.NRGBA{
527				Rect:   image.Rect(-1, -1, 3, 3),
528				Stride: 4 * 4,
529				Pix: []uint8{
530					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
531					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
532					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
533					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
534				},
535			},
536			2, 2,
537			Left,
538			&image.NRGBA{
539				Rect:   image.Rect(0, 0, 2, 2),
540				Stride: 2 * 4,
541				Pix: []uint8{
542					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
543					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
544				},
545			},
546		},
547		{
548			"CropAnchor 4x4 2x2 Center",
549			&image.NRGBA{
550				Rect:   image.Rect(-1, -1, 3, 3),
551				Stride: 4 * 4,
552				Pix: []uint8{
553					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
554					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
555					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
556					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
557				},
558			},
559			2, 2,
560			Center,
561			&image.NRGBA{
562				Rect:   image.Rect(0, 0, 2, 2),
563				Stride: 2 * 4,
564				Pix: []uint8{
565					0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
566					0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
567				},
568			},
569		},
570		{
571			"CropAnchor 4x4 2x2 Right",
572			&image.NRGBA{
573				Rect:   image.Rect(-1, -1, 3, 3),
574				Stride: 4 * 4,
575				Pix: []uint8{
576					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
577					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
578					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
579					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
580				},
581			},
582			2, 2,
583			Right,
584			&image.NRGBA{
585				Rect:   image.Rect(0, 0, 2, 2),
586				Stride: 2 * 4,
587				Pix: []uint8{
588					0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
589					0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
590				},
591			},
592		},
593		{
594			"CropAnchor 4x4 2x2 BottomLeft",
595			&image.NRGBA{
596				Rect:   image.Rect(-1, -1, 3, 3),
597				Stride: 4 * 4,
598				Pix: []uint8{
599					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
600					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
601					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
602					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
603				},
604			},
605			2, 2,
606			BottomLeft,
607			&image.NRGBA{
608				Rect:   image.Rect(0, 0, 2, 2),
609				Stride: 2 * 4,
610				Pix: []uint8{
611					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
612					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
613				},
614			},
615		},
616		{
617			"CropAnchor 4x4 2x2 Bottom",
618			&image.NRGBA{
619				Rect:   image.Rect(-1, -1, 3, 3),
620				Stride: 4 * 4,
621				Pix: []uint8{
622					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
623					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
624					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
625					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
626				},
627			},
628			2, 2,
629			Bottom,
630			&image.NRGBA{
631				Rect:   image.Rect(0, 0, 2, 2),
632				Stride: 2 * 4,
633				Pix: []uint8{
634					0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
635					0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
636				},
637			},
638		},
639		{
640			"CropAnchor 4x4 2x2 BottomRight",
641			&image.NRGBA{
642				Rect:   image.Rect(-1, -1, 3, 3),
643				Stride: 4 * 4,
644				Pix: []uint8{
645					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
646					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
647					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
648					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
649				},
650			},
651			2, 2,
652			BottomRight,
653			&image.NRGBA{
654				Rect:   image.Rect(0, 0, 2, 2),
655				Stride: 2 * 4,
656				Pix: []uint8{
657					0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
658					0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
659				},
660			},
661		},
662		{
663			"CropAnchor 4x4 0x0 BottomRight",
664			&image.NRGBA{
665				Rect:   image.Rect(-1, -1, 3, 3),
666				Stride: 4 * 4,
667				Pix: []uint8{
668					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
669					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
670					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
671					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
672				},
673			},
674			0, 0,
675			BottomRight,
676			&image.NRGBA{
677				Rect:   image.Rect(0, 0, 0, 0),
678				Stride: 0,
679				Pix:    []uint8{},
680			},
681		},
682		{
683			"CropAnchor 4x4 100x100 BottomRight",
684			&image.NRGBA{
685				Rect:   image.Rect(-1, -1, 3, 3),
686				Stride: 4 * 4,
687				Pix: []uint8{
688					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
689					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
690					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
691					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
692				},
693			},
694			100, 100,
695			BottomRight,
696			&image.NRGBA{
697				Rect:   image.Rect(0, 0, 4, 4),
698				Stride: 4 * 4,
699				Pix: []uint8{
700					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
701					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
702					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
703					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
704				},
705			},
706		},
707		{
708			"CropAnchor 4x4 1x100 BottomRight",
709			&image.NRGBA{
710				Rect:   image.Rect(-1, -1, 3, 3),
711				Stride: 4 * 4,
712				Pix: []uint8{
713					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
714					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
715					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
716					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
717				},
718			},
719			1, 100,
720			BottomRight,
721			&image.NRGBA{
722				Rect:   image.Rect(0, 0, 1, 4),
723				Stride: 1 * 4,
724				Pix: []uint8{
725					0x0c, 0x0d, 0x0e, 0x0f,
726					0x1c, 0x1d, 0x1e, 0x1f,
727					0x2c, 0x2d, 0x2e, 0x2f,
728					0x3c, 0x3d, 0x3e, 0x3f,
729				},
730			},
731		},
732		{
733			"CropAnchor 4x4 0x100 BottomRight",
734			&image.NRGBA{
735				Rect:   image.Rect(-1, -1, 3, 3),
736				Stride: 4 * 4,
737				Pix: []uint8{
738					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
739					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
740					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
741					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
742				},
743			},
744			0, 100,
745			BottomRight,
746			&image.NRGBA{
747				Rect:   image.Rect(0, 0, 0, 0),
748				Stride: 0,
749				Pix:    []uint8{},
750			},
751		},
752	}
753	for _, tc := range testCases {
754		t.Run(tc.name, func(t *testing.T) {
755			got := CropAnchor(tc.src, tc.w, tc.h, tc.anchor)
756			if !compareNRGBA(got, tc.want, 0) {
757				t.Fatalf("got result %#v want %#v", got, tc.want)
758			}
759		})
760	}
761}
762
763func TestPaste(t *testing.T) {
764	testCases := []struct {
765		name string
766		src1 image.Image
767		src2 image.Image
768		p    image.Point
769		want *image.NRGBA
770	}{
771		{
772			"Paste 2x3 2x1",
773			&image.NRGBA{
774				Rect:   image.Rect(-1, -1, 1, 2),
775				Stride: 2 * 4,
776				Pix: []uint8{
777					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
778					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
779					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
780				},
781			},
782			&image.NRGBA{
783				Rect:   image.Rect(1, 1, 3, 2),
784				Stride: 2 * 4,
785				Pix: []uint8{
786					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
787				},
788			},
789			image.Pt(-1, 0),
790			&image.NRGBA{
791				Rect:   image.Rect(0, 0, 2, 3),
792				Stride: 2 * 4,
793				Pix: []uint8{
794					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
795					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
796					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
797				},
798			},
799		},
800		{
801			"Paste 3x4 4x3 bottom right intersection",
802			&image.NRGBA{
803				Rect:   image.Rect(-1, -1, 2, 3),
804				Stride: 3 * 4,
805				Pix: []uint8{
806					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
807					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
808					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
809					0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
810				},
811			},
812			&image.NRGBA{
813				Rect:   image.Rect(1, 1, 5, 4),
814				Stride: 4 * 4,
815				Pix: []uint8{
816					0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
817					0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
818					0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
819				},
820			},
821			image.Pt(0, 1),
822			&image.NRGBA{
823				Rect:   image.Rect(0, 0, 3, 4),
824				Stride: 3 * 4,
825				Pix: []uint8{
826					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
827					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
828					0x30, 0x31, 0x32, 0x33, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
829					0x40, 0x41, 0x42, 0x43, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
830				},
831			},
832		},
833		{
834			"Paste 3x4 4x3 top left intersection",
835			&image.NRGBA{
836				Rect:   image.Rect(-1, -1, 2, 3),
837				Stride: 3 * 4,
838				Pix: []uint8{
839					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
840					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
841					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
842					0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
843				},
844			},
845			&image.NRGBA{
846				Rect:   image.Rect(1, 1, 5, 4),
847				Stride: 4 * 4,
848				Pix: []uint8{
849					0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
850					0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
851					0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
852				},
853			},
854			image.Pt(-3, -2),
855			&image.NRGBA{
856				Rect:   image.Rect(0, 0, 3, 4),
857				Stride: 3 * 4,
858				Pix: []uint8{
859					0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0x18, 0x19, 0x1a, 0x1b,
860					0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x28, 0x29, 0x2a, 0x2b,
861					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
862					0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
863				},
864			},
865		},
866		{
867			"Paste 3x4 4x3 no intersection",
868			&image.NRGBA{
869				Rect:   image.Rect(-1, -1, 2, 3),
870				Stride: 3 * 4,
871				Pix: []uint8{
872					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
873					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
874					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
875					0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
876				},
877			},
878			&image.NRGBA{
879				Rect:   image.Rect(1, 1, 5, 4),
880				Stride: 4 * 4,
881				Pix: []uint8{
882					0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
883					0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
884					0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
885				},
886			},
887			image.Pt(-20, 20),
888			&image.NRGBA{
889				Rect:   image.Rect(0, 0, 3, 4),
890				Stride: 3 * 4,
891				Pix: []uint8{
892					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
893					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
894					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
895					0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
896				},
897			},
898		},
899	}
900	for _, tc := range testCases {
901		t.Run(tc.name, func(t *testing.T) {
902			got := Paste(tc.src1, tc.src2, tc.p)
903			if !compareNRGBA(got, tc.want, 0) {
904				t.Fatalf("got result %#v want %#v", got, tc.want)
905			}
906		})
907	}
908}
909
910func BenchmarkPaste(b *testing.B) {
911	b.ReportAllocs()
912	for i := 0; i < b.N; i++ {
913		Paste(testdataBranchesJPG, testdataFlowersSmallPNG, image.Pt(100, 100))
914	}
915}
916
917func TestPasteCenter(t *testing.T) {
918	testCases := []struct {
919		name string
920		src1 image.Image
921		src2 image.Image
922		want *image.NRGBA
923	}{
924		{
925			"PasteCenter 2x3 2x1",
926			&image.NRGBA{
927				Rect:   image.Rect(-1, -1, 1, 2),
928				Stride: 2 * 4,
929				Pix: []uint8{
930					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
931					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
932					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
933				},
934			},
935			&image.NRGBA{
936				Rect:   image.Rect(1, 1, 3, 2),
937				Stride: 2 * 4,
938				Pix: []uint8{
939					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
940				},
941			},
942			&image.NRGBA{
943				Rect:   image.Rect(0, 0, 2, 3),
944				Stride: 2 * 4,
945				Pix: []uint8{
946					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
947					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
948					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
949				},
950			},
951		},
952	}
953	for _, tc := range testCases {
954		t.Run(tc.name, func(t *testing.T) {
955			got := PasteCenter(tc.src1, tc.src2)
956			if !compareNRGBA(got, tc.want, 0) {
957				t.Fatalf("got result %#v want %#v", got, tc.want)
958			}
959		})
960	}
961}
962
963func TestOverlay(t *testing.T) {
964	testCases := []struct {
965		name string
966		src1 image.Image
967		src2 image.Image
968		p    image.Point
969		a    float64
970		want *image.NRGBA
971	}{
972		{
973			"Overlay 2x3 2x1 1.0",
974			&image.NRGBA{
975				Rect:   image.Rect(-1, -1, 1, 2),
976				Stride: 2 * 4,
977				Pix: []uint8{
978					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
979					0x60, 0x00, 0x90, 0xff, 0xff, 0x00, 0x99, 0x7f,
980					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
981				},
982			},
983			&image.NRGBA{
984				Rect:   image.Rect(1, 1, 3, 2),
985				Stride: 2 * 4,
986				Pix: []uint8{
987					0x20, 0x40, 0x80, 0x7f, 0xaa, 0xbb, 0xcc, 0xff,
988				},
989			},
990			image.Pt(-1, 0),
991			1.0,
992			&image.NRGBA{
993				Rect:   image.Rect(0, 0, 2, 3),
994				Stride: 2 * 4,
995				Pix: []uint8{
996					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
997					0x40, 0x1f, 0x88, 0xff, 0xaa, 0xbb, 0xcc, 0xff,
998					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
999				},
1000			},
1001		},
1002		{
1003			"Overlay 2x2 2x2 0.5",
1004			&image.NRGBA{
1005				Rect:   image.Rect(-1, -1, 1, 1),
1006				Stride: 2 * 4,
1007				Pix: []uint8{
1008					0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
1009					0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
1010				},
1011			},
1012			&image.NRGBA{
1013				Rect:   image.Rect(-1, -1, 1, 1),
1014				Stride: 2 * 4,
1015				Pix: []uint8{
1016					0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
1017					0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff,
1018				},
1019			},
1020			image.Pt(-1, -1),
1021			0.5,
1022			&image.NRGBA{
1023				Rect:   image.Rect(0, 0, 2, 2),
1024				Stride: 2 * 4,
1025				Pix: []uint8{
1026					0xff, 0x7f, 0x7f, 0xff, 0x00, 0xff, 0x00, 0xff,
1027					0x7f, 0x7f, 0x7f, 0xff, 0x20, 0x20, 0x20, 0x7f,
1028				},
1029			},
1030		},
1031		{
1032			"Overlay 2x2 2x2 0.5 no intersection",
1033			&image.NRGBA{
1034				Rect:   image.Rect(-1, -1, 1, 1),
1035				Stride: 2 * 4,
1036				Pix: []uint8{
1037					0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
1038					0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
1039				},
1040			},
1041			&image.NRGBA{
1042				Rect:   image.Rect(-1, -1, 1, 1),
1043				Stride: 2 * 4,
1044				Pix: []uint8{
1045					0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
1046					0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff,
1047				},
1048			},
1049			image.Pt(-10, 10),
1050			0.5,
1051			&image.NRGBA{
1052				Rect:   image.Rect(0, 0, 2, 2),
1053				Stride: 2 * 4,
1054				Pix: []uint8{
1055					0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
1056					0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
1057				},
1058			},
1059		},
1060	}
1061	for _, tc := range testCases {
1062		t.Run(tc.name, func(t *testing.T) {
1063			got := Overlay(tc.src1, tc.src2, tc.p, tc.a)
1064			if !compareNRGBA(got, tc.want, 0) {
1065				t.Fatalf("got result %#v want %#v", got, tc.want)
1066			}
1067		})
1068	}
1069}
1070
1071func BenchmarkOverlay(b *testing.B) {
1072	b.ReportAllocs()
1073	for i := 0; i < b.N; i++ {
1074		Overlay(testdataBranchesJPG, testdataFlowersSmallPNG, image.Pt(100, 100), 0.5)
1075	}
1076}
1077
1078func TestOverlayCenter(t *testing.T) {
1079	testCases := []struct {
1080		name string
1081		src1 image.Image
1082		src2 image.Image
1083		a    float64
1084		want *image.NRGBA
1085	}{
1086		{
1087			"OverlayCenter 2x3 2x1",
1088			&image.NRGBA{
1089				Rect:   image.Rect(-1, -1, 1, 2),
1090				Stride: 2 * 4,
1091				Pix: []uint8{
1092					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
1093					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
1094					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
1095				},
1096			},
1097			&image.NRGBA{
1098				Rect:   image.Rect(1, 1, 3, 2),
1099				Stride: 2 * 4,
1100				Pix: []uint8{
1101					0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
1102				},
1103			},
1104			0.5,
1105			&image.NRGBA{
1106				Rect:   image.Rect(0, 0, 2, 3),
1107				Stride: 2 * 4,
1108				Pix: []uint8{
1109					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
1110					0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff,
1111					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
1112				},
1113			},
1114		},
1115	}
1116	for _, tc := range testCases {
1117		t.Run(tc.name, func(t *testing.T) {
1118			got := OverlayCenter(tc.src1, tc.src2, 0.5)
1119			if !compareNRGBA(got, tc.want, 0) {
1120				t.Fatalf("got result %#v want %#v", got, tc.want)
1121			}
1122		})
1123	}
1124}
1125