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

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