git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/imaging/tools_test.go (about)

     1  package imaging
     2  
     3  import (
     4  	"bytes"
     5  	"image"
     6  	"image/color"
     7  	"testing"
     8  )
     9  
    10  func 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  
    78  func BenchmarkNew(b *testing.B) {
    79  	b.ReportAllocs()
    80  	for i := 0; i < b.N; i++ {
    81  		New(1024, 1024, color.White)
    82  	}
    83  }
    84  
    85  func 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  
   324  func 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 2x3",
   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, -1, 1, 2),
   343  			&image.NRGBA{
   344  				Rect:   image.Rect(0, 0, 2, 3),
   345  				Stride: 2 * 4,
   346  				Pix: []uint8{
   347  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   348  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   349  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   350  				},
   351  			},
   352  		},
   353  		{
   354  			"Crop 2x3 2x1",
   355  			&image.NRGBA{
   356  				Rect:   image.Rect(-1, -1, 1, 2),
   357  				Stride: 2 * 4,
   358  				Pix: []uint8{
   359  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   360  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   361  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   362  				},
   363  			},
   364  			image.Rect(-1, 0, 1, 1),
   365  			&image.NRGBA{
   366  				Rect:   image.Rect(0, 0, 2, 1),
   367  				Stride: 2 * 4,
   368  				Pix: []uint8{
   369  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   370  				},
   371  			},
   372  		},
   373  	}
   374  	for _, tc := range testCases {
   375  		t.Run(tc.name, func(t *testing.T) {
   376  			got := Crop(tc.src, tc.r)
   377  			if !compareNRGBA(got, tc.want, 0) {
   378  				t.Fatalf("got result %#v want %#v", got, tc.want)
   379  			}
   380  		})
   381  	}
   382  }
   383  
   384  func BenchmarkCrop(b *testing.B) {
   385  	b.ReportAllocs()
   386  	for i := 0; i < b.N; i++ {
   387  		Crop(testdataBranchesJPG, image.Rect(100, 100, 300, 300))
   388  	}
   389  }
   390  
   391  func TestCropCenter(t *testing.T) {
   392  	testCases := []struct {
   393  		name string
   394  		src  image.Image
   395  		w, h int
   396  		want *image.NRGBA
   397  	}{
   398  		{
   399  			"CropCenter 2x3 2x1",
   400  			&image.NRGBA{
   401  				Rect:   image.Rect(-1, -1, 1, 2),
   402  				Stride: 2 * 4,
   403  				Pix: []uint8{
   404  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   405  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   406  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   407  				},
   408  			},
   409  			2, 1,
   410  			&image.NRGBA{
   411  				Rect:   image.Rect(0, 0, 2, 1),
   412  				Stride: 2 * 4,
   413  				Pix: []uint8{
   414  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   415  				},
   416  			},
   417  		},
   418  		{
   419  			"CropCenter 2x3 0x1",
   420  			&image.NRGBA{
   421  				Rect:   image.Rect(-1, -1, 1, 2),
   422  				Stride: 2 * 4,
   423  				Pix: []uint8{
   424  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   425  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   426  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   427  				},
   428  			},
   429  			0, 1,
   430  			&image.NRGBA{
   431  				Rect:   image.Rect(0, 0, 0, 0),
   432  				Stride: 0,
   433  				Pix:    []uint8{},
   434  			},
   435  		},
   436  		{
   437  			"CropCenter 2x3 5x5",
   438  			&image.NRGBA{
   439  				Rect:   image.Rect(-1, -1, 1, 2),
   440  				Stride: 2 * 4,
   441  				Pix: []uint8{
   442  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   443  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   444  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   445  				},
   446  			},
   447  			5, 5,
   448  			&image.NRGBA{
   449  				Rect:   image.Rect(0, 0, 2, 3),
   450  				Stride: 2 * 4,
   451  				Pix: []uint8{
   452  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   453  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   454  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   455  				},
   456  			},
   457  		},
   458  	}
   459  	for _, tc := range testCases {
   460  		t.Run(tc.name, func(t *testing.T) {
   461  			got := CropCenter(tc.src, tc.w, tc.h)
   462  			if !compareNRGBA(got, tc.want, 0) {
   463  				t.Fatalf("got result %#v want %#v", got, tc.want)
   464  			}
   465  		})
   466  	}
   467  }
   468  
   469  func TestCropAnchor(t *testing.T) {
   470  	testCases := []struct {
   471  		name   string
   472  		src    image.Image
   473  		w, h   int
   474  		anchor Anchor
   475  		want   *image.NRGBA
   476  	}{
   477  		{
   478  			"CropAnchor 4x4 2x2 TopLeft",
   479  			&image.NRGBA{
   480  				Rect:   image.Rect(-1, -1, 3, 3),
   481  				Stride: 4 * 4,
   482  				Pix: []uint8{
   483  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   484  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   485  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   486  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   487  				},
   488  			},
   489  			2, 2,
   490  			TopLeft,
   491  			&image.NRGBA{
   492  				Rect:   image.Rect(0, 0, 2, 2),
   493  				Stride: 2 * 4,
   494  				Pix: []uint8{
   495  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   496  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   497  				},
   498  			},
   499  		},
   500  		{
   501  			"CropAnchor 4x4 2x2 Top",
   502  			&image.NRGBA{
   503  				Rect:   image.Rect(-1, -1, 3, 3),
   504  				Stride: 4 * 4,
   505  				Pix: []uint8{
   506  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   507  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   508  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   509  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   510  				},
   511  			},
   512  			2, 2,
   513  			Top,
   514  			&image.NRGBA{
   515  				Rect:   image.Rect(0, 0, 2, 2),
   516  				Stride: 2 * 4,
   517  				Pix: []uint8{
   518  					0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
   519  					0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
   520  				},
   521  			},
   522  		},
   523  		{
   524  			"CropAnchor 4x4 2x2 TopRight",
   525  			&image.NRGBA{
   526  				Rect:   image.Rect(-1, -1, 3, 3),
   527  				Stride: 4 * 4,
   528  				Pix: []uint8{
   529  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   530  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   531  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   532  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   533  				},
   534  			},
   535  			2, 2,
   536  			TopRight,
   537  			&image.NRGBA{
   538  				Rect:   image.Rect(0, 0, 2, 2),
   539  				Stride: 2 * 4,
   540  				Pix: []uint8{
   541  					0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   542  					0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   543  				},
   544  			},
   545  		},
   546  		{
   547  			"CropAnchor 4x4 2x2 Left",
   548  			&image.NRGBA{
   549  				Rect:   image.Rect(-1, -1, 3, 3),
   550  				Stride: 4 * 4,
   551  				Pix: []uint8{
   552  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   553  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   554  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   555  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   556  				},
   557  			},
   558  			2, 2,
   559  			Left,
   560  			&image.NRGBA{
   561  				Rect:   image.Rect(0, 0, 2, 2),
   562  				Stride: 2 * 4,
   563  				Pix: []uint8{
   564  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   565  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
   566  				},
   567  			},
   568  		},
   569  		{
   570  			"CropAnchor 4x4 2x2 Center",
   571  			&image.NRGBA{
   572  				Rect:   image.Rect(-1, -1, 3, 3),
   573  				Stride: 4 * 4,
   574  				Pix: []uint8{
   575  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   576  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   577  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   578  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   579  				},
   580  			},
   581  			2, 2,
   582  			Center,
   583  			&image.NRGBA{
   584  				Rect:   image.Rect(0, 0, 2, 2),
   585  				Stride: 2 * 4,
   586  				Pix: []uint8{
   587  					0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
   588  					0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
   589  				},
   590  			},
   591  		},
   592  		{
   593  			"CropAnchor 4x4 2x2 Right",
   594  			&image.NRGBA{
   595  				Rect:   image.Rect(-1, -1, 3, 3),
   596  				Stride: 4 * 4,
   597  				Pix: []uint8{
   598  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   599  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   600  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   601  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   602  				},
   603  			},
   604  			2, 2,
   605  			Right,
   606  			&image.NRGBA{
   607  				Rect:   image.Rect(0, 0, 2, 2),
   608  				Stride: 2 * 4,
   609  				Pix: []uint8{
   610  					0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   611  					0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   612  				},
   613  			},
   614  		},
   615  		{
   616  			"CropAnchor 4x4 2x2 BottomLeft",
   617  			&image.NRGBA{
   618  				Rect:   image.Rect(-1, -1, 3, 3),
   619  				Stride: 4 * 4,
   620  				Pix: []uint8{
   621  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   622  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   623  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   624  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   625  				},
   626  			},
   627  			2, 2,
   628  			BottomLeft,
   629  			&image.NRGBA{
   630  				Rect:   image.Rect(0, 0, 2, 2),
   631  				Stride: 2 * 4,
   632  				Pix: []uint8{
   633  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
   634  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   635  				},
   636  			},
   637  		},
   638  		{
   639  			"CropAnchor 4x4 2x2 Bottom",
   640  			&image.NRGBA{
   641  				Rect:   image.Rect(-1, -1, 3, 3),
   642  				Stride: 4 * 4,
   643  				Pix: []uint8{
   644  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   645  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   646  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   647  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   648  				},
   649  			},
   650  			2, 2,
   651  			Bottom,
   652  			&image.NRGBA{
   653  				Rect:   image.Rect(0, 0, 2, 2),
   654  				Stride: 2 * 4,
   655  				Pix: []uint8{
   656  					0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
   657  					0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
   658  				},
   659  			},
   660  		},
   661  		{
   662  			"CropAnchor 4x4 2x2 BottomRight",
   663  			&image.NRGBA{
   664  				Rect:   image.Rect(-1, -1, 3, 3),
   665  				Stride: 4 * 4,
   666  				Pix: []uint8{
   667  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   668  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   669  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   670  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   671  				},
   672  			},
   673  			2, 2,
   674  			BottomRight,
   675  			&image.NRGBA{
   676  				Rect:   image.Rect(0, 0, 2, 2),
   677  				Stride: 2 * 4,
   678  				Pix: []uint8{
   679  					0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   680  					0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   681  				},
   682  			},
   683  		},
   684  		{
   685  			"CropAnchor 4x4 0x0 BottomRight",
   686  			&image.NRGBA{
   687  				Rect:   image.Rect(-1, -1, 3, 3),
   688  				Stride: 4 * 4,
   689  				Pix: []uint8{
   690  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   691  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   692  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   693  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   694  				},
   695  			},
   696  			0, 0,
   697  			BottomRight,
   698  			&image.NRGBA{
   699  				Rect:   image.Rect(0, 0, 0, 0),
   700  				Stride: 0,
   701  				Pix:    []uint8{},
   702  			},
   703  		},
   704  		{
   705  			"CropAnchor 4x4 100x100 BottomRight",
   706  			&image.NRGBA{
   707  				Rect:   image.Rect(-1, -1, 3, 3),
   708  				Stride: 4 * 4,
   709  				Pix: []uint8{
   710  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   711  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   712  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   713  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   714  				},
   715  			},
   716  			100, 100,
   717  			BottomRight,
   718  			&image.NRGBA{
   719  				Rect:   image.Rect(0, 0, 4, 4),
   720  				Stride: 4 * 4,
   721  				Pix: []uint8{
   722  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   723  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   724  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   725  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   726  				},
   727  			},
   728  		},
   729  		{
   730  			"CropAnchor 4x4 1x100 BottomRight",
   731  			&image.NRGBA{
   732  				Rect:   image.Rect(-1, -1, 3, 3),
   733  				Stride: 4 * 4,
   734  				Pix: []uint8{
   735  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   736  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   737  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   738  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   739  				},
   740  			},
   741  			1, 100,
   742  			BottomRight,
   743  			&image.NRGBA{
   744  				Rect:   image.Rect(0, 0, 1, 4),
   745  				Stride: 1 * 4,
   746  				Pix: []uint8{
   747  					0x0c, 0x0d, 0x0e, 0x0f,
   748  					0x1c, 0x1d, 0x1e, 0x1f,
   749  					0x2c, 0x2d, 0x2e, 0x2f,
   750  					0x3c, 0x3d, 0x3e, 0x3f,
   751  				},
   752  			},
   753  		},
   754  		{
   755  			"CropAnchor 4x4 0x100 BottomRight",
   756  			&image.NRGBA{
   757  				Rect:   image.Rect(-1, -1, 3, 3),
   758  				Stride: 4 * 4,
   759  				Pix: []uint8{
   760  					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   761  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   762  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   763  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   764  				},
   765  			},
   766  			0, 100,
   767  			BottomRight,
   768  			&image.NRGBA{
   769  				Rect:   image.Rect(0, 0, 0, 0),
   770  				Stride: 0,
   771  				Pix:    []uint8{},
   772  			},
   773  		},
   774  	}
   775  	for _, tc := range testCases {
   776  		t.Run(tc.name, func(t *testing.T) {
   777  			got := CropAnchor(tc.src, tc.w, tc.h, tc.anchor)
   778  			if !compareNRGBA(got, tc.want, 0) {
   779  				t.Fatalf("got result %#v want %#v", got, tc.want)
   780  			}
   781  		})
   782  	}
   783  }
   784  
   785  func TestPaste(t *testing.T) {
   786  	testCases := []struct {
   787  		name string
   788  		src1 image.Image
   789  		src2 image.Image
   790  		p    image.Point
   791  		want *image.NRGBA
   792  	}{
   793  		{
   794  			"Paste 2x3 2x3",
   795  			&image.NRGBA{
   796  				Rect:   image.Rect(0, 0, 2, 3),
   797  				Stride: 2 * 4,
   798  				Pix: []uint8{
   799  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   800  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   801  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   802  				},
   803  			},
   804  			&image.NRGBA{
   805  				Rect:   image.Rect(-1, -1, 1, 2),
   806  				Stride: 2 * 4,
   807  				Pix: []uint8{
   808  					0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
   809  					0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
   810  					0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
   811  				},
   812  			},
   813  			image.Pt(0, 0),
   814  			&image.NRGBA{
   815  				Rect:   image.Rect(0, 0, 2, 3),
   816  				Stride: 2 * 4,
   817  				Pix: []uint8{
   818  					0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
   819  					0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
   820  					0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
   821  				},
   822  			},
   823  		},
   824  		{
   825  			"Paste 2x3 2x1",
   826  			&image.NRGBA{
   827  				Rect:   image.Rect(-1, -1, 1, 2),
   828  				Stride: 2 * 4,
   829  				Pix: []uint8{
   830  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   831  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   832  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   833  				},
   834  			},
   835  			&image.NRGBA{
   836  				Rect:   image.Rect(1, 1, 3, 2),
   837  				Stride: 2 * 4,
   838  				Pix: []uint8{
   839  					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
   840  				},
   841  			},
   842  			image.Pt(-1, 0),
   843  			&image.NRGBA{
   844  				Rect:   image.Rect(0, 0, 2, 3),
   845  				Stride: 2 * 4,
   846  				Pix: []uint8{
   847  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   848  					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
   849  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   850  				},
   851  			},
   852  		},
   853  		{
   854  			"Paste 3x4 4x3 bottom right intersection",
   855  			&image.NRGBA{
   856  				Rect:   image.Rect(-1, -1, 2, 3),
   857  				Stride: 3 * 4,
   858  				Pix: []uint8{
   859  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
   860  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 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  			&image.NRGBA{
   866  				Rect:   image.Rect(1, 1, 5, 4),
   867  				Stride: 4 * 4,
   868  				Pix: []uint8{
   869  					0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
   870  					0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
   871  					0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
   872  				},
   873  			},
   874  			image.Pt(0, 1),
   875  			&image.NRGBA{
   876  				Rect:   image.Rect(0, 0, 3, 4),
   877  				Stride: 3 * 4,
   878  				Pix: []uint8{
   879  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
   880  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
   881  					0x30, 0x31, 0x32, 0x33, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
   882  					0x40, 0x41, 0x42, 0x43, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
   883  				},
   884  			},
   885  		},
   886  		{
   887  			"Paste 3x4 4x3 top left intersection",
   888  			&image.NRGBA{
   889  				Rect:   image.Rect(-1, -1, 2, 3),
   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  			&image.NRGBA{
   899  				Rect:   image.Rect(1, 1, 5, 4),
   900  				Stride: 4 * 4,
   901  				Pix: []uint8{
   902  					0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
   903  					0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
   904  					0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
   905  				},
   906  			},
   907  			image.Pt(-3, -2),
   908  			&image.NRGBA{
   909  				Rect:   image.Rect(0, 0, 3, 4),
   910  				Stride: 3 * 4,
   911  				Pix: []uint8{
   912  					0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0x18, 0x19, 0x1a, 0x1b,
   913  					0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x28, 0x29, 0x2a, 0x2b,
   914  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
   915  					0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
   916  				},
   917  			},
   918  		},
   919  		{
   920  			"Paste 3x4 4x3 no intersection",
   921  			&image.NRGBA{
   922  				Rect:   image.Rect(-1, -1, 2, 3),
   923  				Stride: 3 * 4,
   924  				Pix: []uint8{
   925  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
   926  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
   927  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
   928  					0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
   929  				},
   930  			},
   931  			&image.NRGBA{
   932  				Rect:   image.Rect(1, 1, 5, 4),
   933  				Stride: 4 * 4,
   934  				Pix: []uint8{
   935  					0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
   936  					0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
   937  					0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
   938  				},
   939  			},
   940  			image.Pt(-20, 20),
   941  			&image.NRGBA{
   942  				Rect:   image.Rect(0, 0, 3, 4),
   943  				Stride: 3 * 4,
   944  				Pix: []uint8{
   945  					0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
   946  					0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
   947  					0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
   948  					0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
   949  				},
   950  			},
   951  		},
   952  	}
   953  	for _, tc := range testCases {
   954  		t.Run(tc.name, func(t *testing.T) {
   955  			got := Paste(tc.src1, tc.src2, tc.p)
   956  			if !compareNRGBA(got, tc.want, 0) {
   957  				t.Fatalf("got result %#v want %#v", got, tc.want)
   958  			}
   959  		})
   960  	}
   961  }
   962  
   963  func BenchmarkPaste(b *testing.B) {
   964  	b.ReportAllocs()
   965  	for i := 0; i < b.N; i++ {
   966  		Paste(testdataBranchesJPG, testdataFlowersSmallPNG, image.Pt(100, 100))
   967  	}
   968  }
   969  
   970  func TestPasteCenter(t *testing.T) {
   971  	testCases := []struct {
   972  		name string
   973  		src1 image.Image
   974  		src2 image.Image
   975  		want *image.NRGBA
   976  	}{
   977  		{
   978  			"PasteCenter 2x3 2x1",
   979  			&image.NRGBA{
   980  				Rect:   image.Rect(-1, -1, 1, 2),
   981  				Stride: 2 * 4,
   982  				Pix: []uint8{
   983  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
   984  					0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
   985  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
   986  				},
   987  			},
   988  			&image.NRGBA{
   989  				Rect:   image.Rect(1, 1, 3, 2),
   990  				Stride: 2 * 4,
   991  				Pix: []uint8{
   992  					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
   993  				},
   994  			},
   995  			&image.NRGBA{
   996  				Rect:   image.Rect(0, 0, 2, 3),
   997  				Stride: 2 * 4,
   998  				Pix: []uint8{
   999  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
  1000  					0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
  1001  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  1002  				},
  1003  			},
  1004  		},
  1005  	}
  1006  	for _, tc := range testCases {
  1007  		t.Run(tc.name, func(t *testing.T) {
  1008  			got := PasteCenter(tc.src1, tc.src2)
  1009  			if !compareNRGBA(got, tc.want, 0) {
  1010  				t.Fatalf("got result %#v want %#v", got, tc.want)
  1011  			}
  1012  		})
  1013  	}
  1014  }
  1015  
  1016  func TestOverlay(t *testing.T) {
  1017  	testCases := []struct {
  1018  		name string
  1019  		src1 image.Image
  1020  		src2 image.Image
  1021  		p    image.Point
  1022  		a    float64
  1023  		want *image.NRGBA
  1024  	}{
  1025  		{
  1026  			"Overlay 2x3 2x1 1.0",
  1027  			&image.NRGBA{
  1028  				Rect:   image.Rect(-1, -1, 1, 2),
  1029  				Stride: 2 * 4,
  1030  				Pix: []uint8{
  1031  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
  1032  					0x60, 0x00, 0x90, 0xff, 0xff, 0x00, 0x99, 0x7f,
  1033  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  1034  				},
  1035  			},
  1036  			&image.NRGBA{
  1037  				Rect:   image.Rect(1, 1, 3, 2),
  1038  				Stride: 2 * 4,
  1039  				Pix: []uint8{
  1040  					0x20, 0x40, 0x80, 0x7f, 0xaa, 0xbb, 0xcc, 0xff,
  1041  				},
  1042  			},
  1043  			image.Pt(-1, 0),
  1044  			1.0,
  1045  			&image.NRGBA{
  1046  				Rect:   image.Rect(0, 0, 2, 3),
  1047  				Stride: 2 * 4,
  1048  				Pix: []uint8{
  1049  					0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
  1050  					0x40, 0x1f, 0x88, 0xff, 0xaa, 0xbb, 0xcc, 0xff,
  1051  					0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
  1052  				},
  1053  			},
  1054  		},
  1055  		{
  1056  			"Overlay 2x2 2x2 0.5",
  1057  			&image.NRGBA{
  1058  				Rect:   image.Rect(-1, -1, 1, 1),
  1059  				Stride: 2 * 4,
  1060  				Pix: []uint8{
  1061  					0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
  1062  					0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
  1063  				},
  1064  			},
  1065  			&image.NRGBA{
  1066  				Rect:   image.Rect(-1, -1, 1, 1),
  1067  				Stride: 2 * 4,
  1068  				Pix: []uint8{
  1069  					0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  1070  					0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff,
  1071  				},
  1072  			},
  1073  			image.Pt(-1, -1),
  1074  			0.5,
  1075  			&image.NRGBA{
  1076  				Rect:   image.Rect(0, 0, 2, 2),
  1077  				Stride: 2 * 4,
  1078  				Pix: []uint8{
  1079  					0xff, 0x7f, 0x7f, 0xff, 0x00, 0xff, 0x00, 0xff,
  1080  					0x7f, 0x7f, 0x7f, 0xff, 0x20, 0x20, 0x20, 0x7f,
  1081  				},
  1082  			},
  1083  		},
  1084  		{
  1085  			"Overlay 2x2 2x2 0.5 no intersection",
  1086  			&image.NRGBA{
  1087  				Rect:   image.Rect(-1, -1, 1, 1),
  1088  				Stride: 2 * 4,
  1089  				Pix: []uint8{
  1090  					0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
  1091  					0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
  1092  				},
  1093  			},
  1094  			&image.NRGBA{
  1095  				Rect:   image.Rect(-1, -1, 1, 1),
  1096  				Stride: 2 * 4,
  1097  				Pix: []uint8{
  1098  					0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
  1099  					0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff,
  1100  				},
  1101  			},
  1102  			image.Pt(-10, 10),
  1103  			0.5,
  1104  			&image.NRGBA{
  1105  				Rect:   image.Rect(0, 0, 2, 2),
  1106  				Stride: 2 * 4,
  1107  				Pix: []uint8{
  1108  					0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
  1109  					0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
  1110  				},
  1111  			},
  1112  		},
  1113  	}
  1114  	for _, tc := range testCases {
  1115  		t.Run(tc.name, func(t *testing.T) {
  1116  			got := Overlay(tc.src1, tc.src2, tc.p, tc.a)
  1117  			if !compareNRGBA(got, tc.want, 0) {
  1118  				t.Fatalf("got result %#v want %#v", got, tc.want)
  1119  			}
  1120  		})
  1121  	}
  1122  }
  1123  
  1124  func BenchmarkOverlay(b *testing.B) {
  1125  	b.ReportAllocs()
  1126  	for i := 0; i < b.N; i++ {
  1127  		Overlay(testdataBranchesJPG, testdataFlowersSmallPNG, image.Pt(100, 100), 0.5)
  1128  	}
  1129  }
  1130  
  1131  func TestOverlayCenter(t *testing.T) {
  1132  	testCases := []struct {
  1133  		name string
  1134  		src1 image.Image
  1135  		src2 image.Image
  1136  		a    float64
  1137  		want *image.NRGBA
  1138  	}{
  1139  		{
  1140  			"OverlayCenter 2x3 2x1",
  1141  			&image.NRGBA{
  1142  				Rect:   image.Rect(-1, -1, 1, 2),
  1143  				Stride: 2 * 4,
  1144  				Pix: []uint8{
  1145  					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
  1146  					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
  1147  					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
  1148  				},
  1149  			},
  1150  			&image.NRGBA{
  1151  				Rect:   image.Rect(1, 1, 3, 2),
  1152  				Stride: 2 * 4,
  1153  				Pix: []uint8{
  1154  					0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
  1155  				},
  1156  			},
  1157  			0.5,
  1158  			&image.NRGBA{
  1159  				Rect:   image.Rect(0, 0, 2, 3),
  1160  				Stride: 2 * 4,
  1161  				Pix: []uint8{
  1162  					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
  1163  					0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff,
  1164  					0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
  1165  				},
  1166  			},
  1167  		},
  1168  	}
  1169  	for _, tc := range testCases {
  1170  		t.Run(tc.name, func(t *testing.T) {
  1171  			got := OverlayCenter(tc.src1, tc.src2, 0.5)
  1172  			if !compareNRGBA(got, tc.want, 0) {
  1173  				t.Fatalf("got result %#v want %#v", got, tc.want)
  1174  			}
  1175  		})
  1176  	}
  1177  }