git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/imaging/resize_test.go (about) 1 package imaging 2 3 import ( 4 "fmt" 5 "image" 6 "path/filepath" 7 "testing" 8 ) 9 10 func TestResize(t *testing.T) { 11 testCases := []struct { 12 name string 13 src image.Image 14 w, h int 15 f ResampleFilter 16 want *image.NRGBA 17 }{ 18 { 19 "Resize 2x2 1x1 box", 20 &image.NRGBA{ 21 Rect: image.Rect(-1, -1, 1, 1), 22 Stride: 2 * 4, 23 Pix: []uint8{ 24 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 25 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 26 }, 27 }, 28 1, 1, 29 Box, 30 &image.NRGBA{ 31 Rect: image.Rect(0, 0, 1, 1), 32 Stride: 1 * 4, 33 Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, 34 }, 35 }, 36 { 37 "Resize 2x2 1x2 box", 38 &image.NRGBA{ 39 Rect: image.Rect(-1, -1, 1, 1), 40 Stride: 2 * 4, 41 Pix: []uint8{ 42 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 43 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 44 }, 45 }, 46 1, 2, 47 Box, 48 &image.NRGBA{ 49 Rect: image.Rect(0, 0, 1, 2), 50 Stride: 1 * 4, 51 Pix: []uint8{ 52 0xff, 0x00, 0x00, 0x80, 53 0x00, 0x80, 0x80, 0xff, 54 }, 55 }, 56 }, 57 { 58 "Resize 2x2 2x1 box", 59 &image.NRGBA{ 60 Rect: image.Rect(-1, -1, 1, 1), 61 Stride: 2 * 4, 62 Pix: []uint8{ 63 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 64 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 65 }, 66 }, 67 2, 1, 68 Box, 69 &image.NRGBA{ 70 Rect: image.Rect(0, 0, 2, 1), 71 Stride: 2 * 4, 72 Pix: []uint8{ 73 0x00, 0xff, 0x00, 0x80, 0x80, 0x00, 0x80, 0xff, 74 }, 75 }, 76 }, 77 { 78 "Resize 2x2 2x2 box", 79 &image.NRGBA{ 80 Rect: image.Rect(-1, -1, 1, 1), 81 Stride: 2 * 4, 82 Pix: []uint8{ 83 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 84 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 85 }, 86 }, 87 2, 2, 88 Box, 89 &image.NRGBA{ 90 Rect: image.Rect(0, 0, 2, 2), 91 Stride: 2 * 4, 92 Pix: []uint8{ 93 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 94 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 95 }, 96 }, 97 }, 98 { 99 "Resize 3x1 1x1 nearest", 100 &image.NRGBA{ 101 Rect: image.Rect(-1, -1, 2, 0), 102 Stride: 3 * 4, 103 Pix: []uint8{ 104 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 105 }, 106 }, 107 1, 1, 108 NearestNeighbor, 109 &image.NRGBA{ 110 Rect: image.Rect(0, 0, 1, 1), 111 Stride: 1 * 4, 112 Pix: []uint8{0x00, 0xff, 0x00, 0xff}, 113 }, 114 }, 115 { 116 "Resize 2x2 0x4 box", 117 &image.NRGBA{ 118 Rect: image.Rect(-1, -1, 1, 1), 119 Stride: 2 * 4, 120 Pix: []uint8{ 121 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 122 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 123 }, 124 }, 125 0, 4, 126 Box, 127 &image.NRGBA{ 128 Rect: image.Rect(0, 0, 4, 4), 129 Stride: 4 * 4, 130 Pix: []uint8{ 131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 133 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 134 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 135 }, 136 }, 137 }, 138 { 139 "Resize 2x2 4x0 linear", 140 &image.NRGBA{ 141 Rect: image.Rect(-1, -1, 1, 1), 142 Stride: 2 * 4, 143 Pix: []uint8{ 144 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 145 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 146 }, 147 }, 148 4, 0, 149 Linear, 150 &image.NRGBA{ 151 Rect: image.Rect(0, 0, 4, 4), 152 Stride: 4 * 4, 153 Pix: []uint8{ 154 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x40, 0xff, 0x00, 0x00, 0xbf, 0xff, 0x00, 0x00, 0xff, 155 0x00, 0xff, 0x00, 0x40, 0x6e, 0x6d, 0x25, 0x70, 0xb0, 0x14, 0x3b, 0xcf, 0xbf, 0x00, 0x40, 0xff, 156 0x00, 0xff, 0x00, 0xbf, 0x14, 0xb0, 0x3b, 0xcf, 0x33, 0x33, 0x99, 0xef, 0x40, 0x00, 0xbf, 0xff, 157 0x00, 0xff, 0x00, 0xff, 0x00, 0xbf, 0x40, 0xff, 0x00, 0x40, 0xbf, 0xff, 0x00, 0x00, 0xff, 0xff, 158 }, 159 }, 160 }, 161 { 162 "Resize 0x0 1x1 box", 163 &image.NRGBA{ 164 Rect: image.Rect(-1, -1, -1, -1), 165 Stride: 0, 166 Pix: []uint8{}, 167 }, 168 1, 1, 169 Box, 170 &image.NRGBA{}, 171 }, 172 { 173 "Resize 2x2 0x0 box", 174 &image.NRGBA{ 175 Rect: image.Rect(-1, -1, 1, 1), 176 Stride: 2 * 4, 177 Pix: []uint8{ 178 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 179 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 180 }, 181 }, 182 0, 0, 183 Box, 184 &image.NRGBA{}, 185 }, 186 { 187 "Resize 2x2 -1x0 box", 188 &image.NRGBA{ 189 Rect: image.Rect(-1, -1, 1, 1), 190 Stride: 2 * 4, 191 Pix: []uint8{ 192 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 193 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 194 }, 195 }, 196 -1, 0, 197 Box, 198 &image.NRGBA{}, 199 }, 200 } 201 for _, tc := range testCases { 202 t.Run(tc.name, func(t *testing.T) { 203 got := Resize(tc.src, tc.w, tc.h, tc.f) 204 if !compareNRGBA(got, tc.want, 0) { 205 t.Fatalf("got result %#v want %#v", got, tc.want) 206 } 207 }) 208 } 209 } 210 211 func TestResampleFilters(t *testing.T) { 212 for _, filter := range []ResampleFilter{ 213 NearestNeighbor, 214 Box, 215 Linear, 216 Hermite, 217 MitchellNetravali, 218 CatmullRom, 219 BSpline, 220 Gaussian, 221 Lanczos, 222 Hann, 223 Hamming, 224 Blackman, 225 Bartlett, 226 Welch, 227 Cosine, 228 } { 229 t.Run("", func(t *testing.T) { 230 src := image.NewNRGBA(image.Rect(-1, -1, 2, 3)) 231 got := Resize(src, 5, 6, filter) 232 want := image.NewNRGBA(image.Rect(0, 0, 5, 6)) 233 if !compareNRGBA(got, want, 0) { 234 t.Fatalf("got result %#v want %#v", got, want) 235 } 236 if filter.Kernel != nil { 237 if x := filter.Kernel(filter.Support + 0.0001); x != 0 { 238 t.Fatalf("got kernel value %f want 0", x) 239 } 240 } 241 }) 242 } 243 } 244 245 func TestResizeGolden(t *testing.T) { 246 for name, filter := range map[string]ResampleFilter{ 247 "out_resize_nearest.png": NearestNeighbor, 248 "out_resize_linear.png": Linear, 249 "out_resize_catrom.png": CatmullRom, 250 "out_resize_lanczos.png": Lanczos, 251 } { 252 got := Resize(testdataBranchesPNG, 150, 0, filter) 253 want, err := Open("testdata/" + name) 254 if err != nil { 255 t.Fatalf("failed to open image: %v", err) 256 } 257 if !compareNRGBAGolden(got, toNRGBA(want)) { 258 t.Fatalf("resulting image differs from golden: %s", name) 259 } 260 } 261 } 262 263 func TestFit(t *testing.T) { 264 testCases := []struct { 265 name string 266 src image.Image 267 w, h int 268 f ResampleFilter 269 want *image.NRGBA 270 }{ 271 { 272 "Fit 2x2 1x10 box", 273 &image.NRGBA{ 274 Rect: image.Rect(-1, -1, 1, 1), 275 Stride: 2 * 4, 276 Pix: []uint8{ 277 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 278 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 279 }, 280 }, 281 1, 10, 282 Box, 283 &image.NRGBA{ 284 Rect: image.Rect(0, 0, 1, 1), 285 Stride: 1 * 4, 286 Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, 287 }, 288 }, 289 { 290 "Fit 2x2 10x1 box", 291 &image.NRGBA{ 292 Rect: image.Rect(-1, -1, 1, 1), 293 Stride: 2 * 4, 294 Pix: []uint8{ 295 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 296 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 297 }, 298 }, 299 10, 1, 300 Box, 301 &image.NRGBA{ 302 Rect: image.Rect(0, 0, 1, 1), 303 Stride: 1 * 4, 304 Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, 305 }, 306 }, 307 { 308 "Fit 2x2 10x10 box", 309 &image.NRGBA{ 310 Rect: image.Rect(-1, -1, 1, 1), 311 Stride: 2 * 4, 312 Pix: []uint8{ 313 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 314 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 315 }, 316 }, 317 10, 10, 318 Box, 319 &image.NRGBA{ 320 Rect: image.Rect(0, 0, 2, 2), 321 Stride: 2 * 4, 322 Pix: []uint8{ 323 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 324 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 325 }, 326 }, 327 }, 328 { 329 "Fit 0x0 1x1 box", 330 &image.NRGBA{ 331 Rect: image.Rect(-1, -1, -1, -1), 332 Stride: 0, 333 Pix: []uint8{}, 334 }, 335 1, 1, 336 Box, 337 &image.NRGBA{}, 338 }, 339 { 340 "Fit 2x2 0x0 box", 341 &image.NRGBA{ 342 Rect: image.Rect(-1, -1, 1, 1), 343 Stride: 2 * 4, 344 Pix: []uint8{ 345 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 346 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 347 }, 348 }, 349 0, 0, 350 Box, 351 &image.NRGBA{}, 352 }, 353 { 354 "Fit 2x2 -1x0 box", 355 &image.NRGBA{ 356 Rect: image.Rect(-1, -1, 1, 1), 357 Stride: 2 * 4, 358 Pix: []uint8{ 359 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 360 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 361 }, 362 }, 363 -1, 0, 364 Box, 365 &image.NRGBA{}, 366 }, 367 } 368 for _, tc := range testCases { 369 t.Run(tc.name, func(t *testing.T) { 370 got := Fit(tc.src, tc.w, tc.h, tc.f) 371 if !compareNRGBA(got, tc.want, 0) { 372 t.Fatalf("got result %#v want %#v", got, tc.want) 373 } 374 }) 375 } 376 } 377 378 func TestFitGolden(t *testing.T) { 379 got := Fit(testdataBranchesPNG, 150, 150, Box) 380 name := filepath.Join("testdata", "out_fit.png") 381 want, err := Open(name) 382 if err != nil { 383 t.Fatalf("failed to open image: %v", err) 384 } 385 if !compareNRGBAGolden(got, toNRGBA(want)) { 386 t.Fatalf("resulting image differs from golden: %s", name) 387 } 388 } 389 390 func TestFill(t *testing.T) { 391 testCases := []struct { 392 name string 393 src image.Image 394 w, h int 395 a Anchor 396 f ResampleFilter 397 want *image.NRGBA 398 }{ 399 { 400 "Fill 4x4 4x4 TopRight Box", 401 &image.NRGBA{ 402 Rect: image.Rect(-1, -1, 3, 3), 403 Stride: 4 * 4, 404 Pix: []uint8{ 405 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 406 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 407 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 408 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 409 }, 410 }, 411 4, 4, 412 TopRight, 413 Box, 414 &image.NRGBA{ 415 Rect: image.Rect(0, 0, 4, 4), 416 Stride: 4 * 4, 417 Pix: []uint8{ 418 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 419 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 420 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 421 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 422 }, 423 }, 424 }, 425 { 426 "Fill 4x4 0x4 Left Box", 427 &image.NRGBA{ 428 Rect: image.Rect(-1, -1, 3, 3), 429 Stride: 4 * 4, 430 Pix: []uint8{ 431 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 432 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 433 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 434 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 435 }, 436 }, 437 0, 4, 438 Left, 439 Box, 440 &image.NRGBA{}, 441 }, 442 { 443 "Fill 0x0 4x4 Right Box", 444 &image.NRGBA{}, 445 4, 4, 446 Right, 447 Box, 448 &image.NRGBA{}, 449 }, 450 { 451 "Fill 100x200 20x10 Center Linear", 452 image.NewRGBA(image.Rect(0, 0, 100, 200)), 453 20, 10, 454 Center, 455 Linear, 456 image.NewNRGBA(image.Rect(0, 0, 20, 10)), 457 }, 458 { 459 "Fill 10x20 20x10 Center Linear", 460 image.NewRGBA(image.Rect(0, 0, 10, 20)), 461 20, 10, 462 Center, 463 Linear, 464 image.NewNRGBA(image.Rect(0, 0, 20, 10)), 465 }, 466 } 467 for _, tc := range testCases { 468 t.Run(tc.name, func(t *testing.T) { 469 got := Fill(tc.src, tc.w, tc.h, tc.a, tc.f) 470 if !compareNRGBA(got, tc.want, 0) { 471 t.Fatalf("got result %#v want %#v", got, tc.want) 472 } 473 }) 474 } 475 } 476 477 func TestFillGolden(t *testing.T) { 478 anchorPoints := map[string]Anchor{ 479 "left": Left, 480 "center": Center, 481 "right": Right, 482 } 483 for apName, ap := range anchorPoints { 484 got := Fill(testdataBranchesPNG, 150, 150, ap, Box) 485 name := filepath.Join("testdata", "out_fill_"+apName+".png") 486 want, err := Open(name) 487 if err != nil { 488 t.Fatalf("failed to open image: %v", err) 489 } 490 if !compareNRGBAGolden(got, toNRGBA(want)) { 491 t.Fatalf("resulting image differs from golden: %s", name) 492 } 493 } 494 } 495 496 func TestResizeAndCrop(t *testing.T) { 497 testCases := []struct { 498 name string 499 src image.Image 500 w, h int 501 a Anchor 502 f ResampleFilter 503 want *image.NRGBA 504 }{ 505 { 506 "resizeAndCrop 4x4 2x2 Center Nearest", 507 &image.NRGBA{ 508 Rect: image.Rect(-1, -1, 3, 3), 509 Stride: 4 * 4, 510 Pix: []uint8{ 511 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 512 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 513 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 514 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 515 }, 516 }, 517 2, 2, 518 Center, 519 NearestNeighbor, 520 &image.NRGBA{ 521 Rect: image.Rect(0, 0, 2, 2), 522 Stride: 2 * 4, 523 Pix: []uint8{ 524 0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f, 525 0x34, 0x35, 0x36, 0x37, 0x3c, 0x3d, 0x3e, 0x3f, 526 }, 527 }, 528 }, 529 { 530 "resizeAndCrop 4x4 1x4 TopLeft Nearest", 531 &image.NRGBA{ 532 Rect: image.Rect(-1, -1, 3, 3), 533 Stride: 4 * 4, 534 Pix: []uint8{ 535 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 536 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 537 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 538 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 539 }, 540 }, 541 1, 4, 542 TopLeft, 543 NearestNeighbor, 544 &image.NRGBA{ 545 Rect: image.Rect(0, 0, 1, 4), 546 Stride: 1 * 4, 547 Pix: []uint8{ 548 0x00, 0x01, 0x02, 0x03, 549 0x10, 0x11, 0x12, 0x13, 550 0x20, 0x21, 0x22, 0x23, 551 0x30, 0x31, 0x32, 0x33, 552 }, 553 }, 554 }, 555 { 556 "resizeAndCrop 4x4 8x2 Bottom Nearest", 557 &image.NRGBA{ 558 Rect: image.Rect(-1, -1, 3, 3), 559 Stride: 4 * 4, 560 Pix: []uint8{ 561 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 562 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 563 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 564 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 565 }, 566 }, 567 8, 2, 568 Bottom, 569 NearestNeighbor, 570 &image.NRGBA{ 571 Rect: image.Rect(0, 0, 8, 2), 572 Stride: 8 * 4, 573 Pix: []uint8{ 574 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f, 575 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f, 576 }, 577 }, 578 }, 579 { 580 "resizeAndCrop 4x4 2x8 Top Nearest", 581 &image.NRGBA{ 582 Rect: image.Rect(-1, -1, 3, 3), 583 Stride: 4 * 4, 584 Pix: []uint8{ 585 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 586 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 587 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 588 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 589 }, 590 }, 591 2, 8, 592 Top, 593 NearestNeighbor, 594 &image.NRGBA{ 595 Rect: image.Rect(0, 0, 2, 8), 596 Stride: 2 * 4, 597 Pix: []uint8{ 598 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 599 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 600 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 601 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 602 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 603 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 604 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 605 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 606 }, 607 }, 608 }, 609 { 610 "resizeAndCrop 4x4 4x4 TopRight Box", 611 &image.NRGBA{ 612 Rect: image.Rect(-1, -1, 3, 3), 613 Stride: 4 * 4, 614 Pix: []uint8{ 615 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 616 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 617 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 618 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 619 }, 620 }, 621 4, 4, 622 TopRight, 623 Box, 624 &image.NRGBA{ 625 Rect: image.Rect(0, 0, 4, 4), 626 Stride: 4 * 4, 627 Pix: []uint8{ 628 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 629 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 630 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 631 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 632 }, 633 }, 634 }, 635 } 636 for _, tc := range testCases { 637 t.Run(tc.name, func(t *testing.T) { 638 got := resizeAndCrop(tc.src, tc.w, tc.h, tc.a, tc.f) 639 if !compareNRGBA(got, tc.want, 0) { 640 t.Fatalf("got result %#v want %#v", got, tc.want) 641 } 642 }) 643 } 644 } 645 646 func TestCropAndResize(t *testing.T) { 647 testCases := []struct { 648 name string 649 src image.Image 650 w, h int 651 a Anchor 652 f ResampleFilter 653 want *image.NRGBA 654 }{ 655 { 656 "cropAndResize 4x4 2x2 Center Nearest", 657 &image.NRGBA{ 658 Rect: image.Rect(-1, -1, 3, 3), 659 Stride: 4 * 4, 660 Pix: []uint8{ 661 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 662 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 663 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 664 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 665 }, 666 }, 667 2, 2, 668 Center, 669 NearestNeighbor, 670 &image.NRGBA{ 671 Rect: image.Rect(0, 0, 2, 2), 672 Stride: 2 * 4, 673 Pix: []uint8{ 674 0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f, 675 0x34, 0x35, 0x36, 0x37, 0x3c, 0x3d, 0x3e, 0x3f, 676 }, 677 }, 678 }, 679 { 680 "cropAndResize 4x4 1x4 TopLeft Nearest", 681 &image.NRGBA{ 682 Rect: image.Rect(-1, -1, 3, 3), 683 Stride: 4 * 4, 684 Pix: []uint8{ 685 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 686 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 687 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 688 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 689 }, 690 }, 691 1, 4, 692 TopLeft, 693 NearestNeighbor, 694 &image.NRGBA{ 695 Rect: image.Rect(0, 0, 1, 4), 696 Stride: 1 * 4, 697 Pix: []uint8{ 698 0x00, 0x01, 0x02, 0x03, 699 0x10, 0x11, 0x12, 0x13, 700 0x20, 0x21, 0x22, 0x23, 701 0x30, 0x31, 0x32, 0x33, 702 }, 703 }, 704 }, 705 { 706 "cropAndResize 4x4 8x2 Bottom Nearest", 707 &image.NRGBA{ 708 Rect: image.Rect(-1, -1, 3, 3), 709 Stride: 4 * 4, 710 Pix: []uint8{ 711 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 712 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 713 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 714 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 715 }, 716 }, 717 8, 2, 718 Bottom, 719 NearestNeighbor, 720 &image.NRGBA{ 721 Rect: image.Rect(0, 0, 8, 2), 722 Stride: 8 * 4, 723 Pix: []uint8{ 724 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f, 725 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f, 726 }, 727 }, 728 }, 729 { 730 "cropAndResize 4x4 2x8 Top Nearest", 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 2, 8, 742 Top, 743 NearestNeighbor, 744 &image.NRGBA{ 745 Rect: image.Rect(0, 0, 2, 8), 746 Stride: 2 * 4, 747 Pix: []uint8{ 748 0x04, 0x05, 0x06, 0x07, 0x04, 0x05, 0x06, 0x07, 749 0x04, 0x05, 0x06, 0x07, 0x04, 0x05, 0x06, 0x07, 750 0x14, 0x15, 0x16, 0x17, 0x14, 0x15, 0x16, 0x17, 751 0x14, 0x15, 0x16, 0x17, 0x14, 0x15, 0x16, 0x17, 752 0x24, 0x25, 0x26, 0x27, 0x24, 0x25, 0x26, 0x27, 753 0x24, 0x25, 0x26, 0x27, 0x24, 0x25, 0x26, 0x27, 754 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 755 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 756 }, 757 }, 758 }, 759 { 760 "cropAndResize 4x4 4x4 TopRight Box", 761 &image.NRGBA{ 762 Rect: image.Rect(-1, -1, 3, 3), 763 Stride: 4 * 4, 764 Pix: []uint8{ 765 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 766 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 767 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 768 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 769 }, 770 }, 771 4, 4, 772 TopRight, 773 Box, 774 &image.NRGBA{ 775 Rect: image.Rect(0, 0, 4, 4), 776 Stride: 4 * 4, 777 Pix: []uint8{ 778 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 779 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 780 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 781 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 782 }, 783 }, 784 }, 785 } 786 for _, tc := range testCases { 787 t.Run(tc.name, func(t *testing.T) { 788 got := cropAndResize(tc.src, tc.w, tc.h, tc.a, tc.f) 789 if !compareNRGBA(got, tc.want, 0) { 790 t.Fatalf("got result %#v want %#v", got, tc.want) 791 } 792 }) 793 } 794 } 795 796 func TestThumbnail(t *testing.T) { 797 testCases := []struct { 798 name string 799 src image.Image 800 w, h int 801 f ResampleFilter 802 want *image.NRGBA 803 }{ 804 { 805 "Thumbnail 6x2 1x1 box", 806 &image.NRGBA{ 807 Rect: image.Rect(-1, -1, 5, 1), 808 Stride: 6 * 4, 809 Pix: []uint8{ 810 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 811 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 812 }, 813 }, 814 1, 1, 815 Box, 816 &image.NRGBA{ 817 Rect: image.Rect(0, 0, 1, 1), 818 Stride: 1 * 4, 819 Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, 820 }, 821 }, 822 { 823 "Thumbnail 2x6 1x1 box", 824 &image.NRGBA{ 825 Rect: image.Rect(-1, -1, 1, 5), 826 Stride: 2 * 4, 827 Pix: []uint8{ 828 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 829 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 830 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 831 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 832 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 833 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 834 }, 835 }, 836 1, 1, 837 Box, 838 &image.NRGBA{ 839 Rect: image.Rect(0, 0, 1, 1), 840 Stride: 1 * 4, 841 Pix: []uint8{0x55, 0x55, 0x55, 0xc0}, 842 }, 843 }, 844 { 845 "Thumbnail 1x3 2x2 box", 846 &image.NRGBA{ 847 Rect: image.Rect(-1, -1, 0, 2), 848 Stride: 1 * 4, 849 Pix: []uint8{ 850 0x00, 0x00, 0x00, 0x00, 851 0xff, 0x00, 0x00, 0xff, 852 0xff, 0xff, 0xff, 0xff, 853 }, 854 }, 855 2, 2, 856 Box, 857 &image.NRGBA{ 858 Rect: image.Rect(0, 0, 2, 2), 859 Stride: 2 * 4, 860 Pix: []uint8{ 861 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 862 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 863 }, 864 }, 865 }, 866 } 867 for _, tc := range testCases { 868 t.Run(tc.name, func(t *testing.T) { 869 got := Thumbnail(tc.src, tc.w, tc.h, tc.f) 870 if !compareNRGBA(got, tc.want, 0) { 871 t.Fatalf("got result %#v want %#v", got, tc.want) 872 } 873 }) 874 } 875 } 876 877 func BenchmarkResize(b *testing.B) { 878 for _, dir := range []string{"Down", "Up"} { 879 for _, filter := range []string{"NearestNeighbor", "Linear", "CatmullRom", "Lanczos"} { 880 for _, format := range []string{"JPEG", "PNG"} { 881 var size int 882 switch dir { 883 case "Down": 884 size = 100 885 case "Up": 886 size = 1000 887 } 888 889 var f ResampleFilter 890 switch filter { 891 case "NearestNeighbor": 892 f = NearestNeighbor 893 case "Linear": 894 f = Linear 895 case "CatmullRom": 896 f = CatmullRom 897 case "Lanczos": 898 f = Lanczos 899 } 900 901 var img image.Image 902 switch format { 903 case "JPEG": 904 img = testdataBranchesJPG 905 case "PNG": 906 img = testdataBranchesPNG 907 } 908 909 b.Run(fmt.Sprintf("%s %s %s", dir, filter, format), func(b *testing.B) { 910 b.ReportAllocs() 911 for i := 0; i < b.N; i++ { 912 Resize(img, size, size, f) 913 } 914 }) 915 } 916 } 917 } 918 } 919 920 func BenchmarkFill(b *testing.B) { 921 for _, dir := range []string{"Vertical", "Horizontal"} { 922 for _, filter := range []string{"NearestNeighbor", "Linear", "CatmullRom", "Lanczos"} { 923 for _, format := range []string{"JPEG", "PNG"} { 924 var width, height int 925 switch dir { 926 case "Vertical": 927 width = 100 928 height = 1000 929 case "Horizontal": 930 width = 1000 931 height = 100 932 } 933 934 var f ResampleFilter 935 switch filter { 936 case "NearestNeighbor": 937 f = NearestNeighbor 938 case "Linear": 939 f = Linear 940 case "CatmullRom": 941 f = CatmullRom 942 case "Lanczos": 943 f = Lanczos 944 } 945 946 var img image.Image 947 switch format { 948 case "JPEG": 949 img = testdataBranchesJPG 950 case "PNG": 951 img = testdataBranchesPNG 952 } 953 954 b.Run(fmt.Sprintf("%s %s %s", dir, filter, format), func(b *testing.B) { 955 b.ReportAllocs() 956 for i := 0; i < b.N; i++ { 957 Fill(img, width, height, Center, f) 958 } 959 }) 960 } 961 } 962 } 963 }