1package transform 2 3import ( 4 "image" 5 "testing" 6 7 "github.com/anthonynsimon/bild/util" 8) 9 10func TestResize(t *testing.T) { 11 cases := []struct { 12 name string 13 width int 14 height int 15 img *image.RGBA 16 expected *image.RGBA 17 }{ 18 { 19 name: "empty", 20 width: 2, 21 height: 2, 22 img: &image.RGBA{ 23 Stride: 0, 24 Rect: image.Rect(0, 0, 0, 0), 25 Pix: []uint8{}, 26 }, 27 expected: &image.RGBA{ 28 Stride: 0, 29 Rect: image.Rect(0, 0, 0, 0), 30 Pix: []uint8{}, 31 }, 32 }, 33 { 34 name: "x1", 35 width: 1, 36 height: 1, 37 img: &image.RGBA{ 38 Stride: 1 * 4, 39 Rect: image.Rect(0, 0, 1, 1), 40 Pix: []uint8{0xFF, 0xFF, 0xFF, 0xFF}, 41 }, 42 expected: &image.RGBA{ 43 Stride: 1 * 4, 44 Rect: image.Rect(0, 0, 1, 1), 45 Pix: []uint8{0xFF, 0xFF, 0xFF, 0xFF}, 46 }, 47 }, 48 { 49 name: "x2", 50 width: 2, 51 height: 2, 52 img: &image.RGBA{ 53 Stride: 1 * 4, 54 Rect: image.Rect(0, 0, 1, 1), 55 Pix: []uint8{0xFF, 0xFF, 0xFF, 0xFF}, 56 }, 57 expected: &image.RGBA{ 58 Stride: 2 * 4, 59 Rect: image.Rect(0, 0, 2, 2), 60 Pix: []uint8{ 61 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 62 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 63 }, 64 }, 65 }, 66 { 67 name: "only horizontal x2", 68 width: 2, 69 height: 1, 70 img: &image.RGBA{ 71 Stride: 1 * 4, 72 Rect: image.Rect(0, 0, 1, 1), 73 Pix: []uint8{0xFF, 0xFF, 0xFF, 0xFF}, 74 }, 75 expected: &image.RGBA{ 76 Stride: 2 * 4, 77 Rect: image.Rect(0, 0, 2, 1), 78 Pix: []uint8{ 79 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 80 }, 81 }, 82 }, 83 { 84 name: "only vertical x2", 85 width: 1, 86 height: 2, 87 img: &image.RGBA{ 88 Stride: 1 * 4, 89 Rect: image.Rect(0, 0, 1, 1), 90 Pix: []uint8{0xFF, 0xFF, 0xFF, 0xFF}, 91 }, 92 expected: &image.RGBA{ 93 Stride: 1 * 4, 94 Rect: image.Rect(0, 0, 1, 2), 95 Pix: []uint8{ 96 0xFF, 0xFF, 0xFF, 0xFF, 97 0xFF, 0xFF, 0xFF, 0xFF, 98 }, 99 }, 100 }, 101 { 102 name: "x0.5", 103 width: 1, 104 height: 1, 105 img: &image.RGBA{ 106 Stride: 1 * 4, 107 Rect: image.Rect(0, 0, 1, 2), 108 Pix: []uint8{ 109 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 110 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 111 }, 112 }, 113 expected: &image.RGBA{ 114 Stride: 1 * 4, 115 Rect: image.Rect(0, 0, 1, 1), 116 Pix: []uint8{0xFF, 0xFF, 0xFF, 0xFF}, 117 }, 118 }, 119 { 120 name: "only horizontal x0.5", 121 width: 1, 122 height: 2, 123 img: &image.RGBA{ 124 Stride: 2 * 4, 125 Rect: image.Rect(0, 0, 2, 2), 126 Pix: []uint8{ 127 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 128 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 129 }, 130 }, 131 expected: &image.RGBA{ 132 Stride: 1 * 4, 133 Rect: image.Rect(0, 0, 1, 2), 134 Pix: []uint8{ 135 0xFF, 0xFF, 0xFF, 0xFF, 136 0xFF, 0xFF, 0xFF, 0xFF, 137 }, 138 }, 139 }, 140 { 141 name: "only vertical x0.5", 142 width: 2, 143 height: 1, 144 img: &image.RGBA{ 145 Stride: 2 * 4, 146 Rect: image.Rect(0, 0, 2, 2), 147 Pix: []uint8{ 148 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 149 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 150 }, 151 }, 152 expected: &image.RGBA{ 153 Stride: 2 * 4, 154 Rect: image.Rect(0, 0, 2, 1), 155 Pix: []uint8{ 156 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 157 }, 158 }, 159 }, 160 { 161 name: "x0", 162 width: 0, 163 height: 0, 164 img: &image.RGBA{ 165 Stride: 1 * 4, 166 Rect: image.Rect(0, 0, 1, 2), 167 Pix: []uint8{ 168 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 169 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 170 }, 171 }, 172 expected: &image.RGBA{ 173 Stride: 0, 174 Rect: image.Rect(0, 0, 0, 0), 175 Pix: []uint8{}, 176 }, 177 }, 178 } 179 180 for _, c := range cases { 181 result := Resize(c.img, c.width, c.height, NearestNeighbor) 182 if !util.RGBAImageEqual(result, c.expected) { 183 t.Errorf("%s: expected: %#v, actual: %#v", "Resize no filter "+c.name, c.expected, result) 184 } 185 186 result = Resize(c.img, c.width, c.height, Linear) 187 if !util.RGBAImageEqual(result, c.expected) { 188 t.Errorf("%s: expected: %#v, actual: %#v", "Resize with filter "+c.name, c.expected, result) 189 } 190 } 191} 192 193func TestResizeNearestNeighbor(t *testing.T) { 194 cases := []struct { 195 name string 196 width int 197 height int 198 img *image.RGBA 199 expected *image.RGBA 200 }{ 201 { 202 name: "x2", 203 width: 4, 204 height: 4, 205 img: &image.RGBA{ 206 Stride: 2 * 4, 207 Rect: image.Rect(0, 0, 2, 2), 208 Pix: []uint8{ 209 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 210 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 211 }, 212 }, 213 expected: &image.RGBA{ 214 Stride: 4 * 4, 215 Rect: image.Rect(0, 0, 4, 4), 216 Pix: []uint8{ 217 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 218 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 219 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 220 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 221 }, 222 }, 223 }, 224 { 225 name: "x0.5", 226 width: 2, 227 height: 2, 228 img: &image.RGBA{ 229 Stride: 4 * 4, 230 Rect: image.Rect(0, 0, 4, 4), 231 Pix: []uint8{ 232 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 233 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 234 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 235 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 236 }, 237 }, 238 expected: &image.RGBA{ 239 Stride: 2 * 4, 240 Rect: image.Rect(0, 0, 2, 2), 241 Pix: []uint8{ 242 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 243 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 244 }, 245 }, 246 }, 247 } 248 249 for _, c := range cases { 250 actual := Resize(c.img, c.width, c.height, NearestNeighbor) 251 if !util.RGBAImageEqual(actual, c.expected) { 252 t.Errorf("%s: expected: %#v, actual: %#v", "ResizeNearestNeighbor "+c.name, util.RGBAToString(c.expected), util.RGBAToString(actual)) 253 } 254 } 255} 256 257func TestResizeBox(t *testing.T) { 258 cases := []struct { 259 name string 260 width int 261 height int 262 img *image.RGBA 263 expected *image.RGBA 264 }{ 265 { 266 name: "x2", 267 width: 4, 268 height: 4, 269 img: &image.RGBA{ 270 Stride: 2 * 4, 271 Rect: image.Rect(0, 0, 2, 2), 272 Pix: []uint8{ 273 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 274 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 275 }, 276 }, 277 expected: &image.RGBA{ 278 Stride: 4 * 4, 279 Rect: image.Rect(0, 0, 4, 4), 280 Pix: []uint8{ 281 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 282 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 283 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 284 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 285 }, 286 }, 287 }, 288 { 289 name: "x0.5", 290 width: 2, 291 height: 2, 292 img: &image.RGBA{ 293 Stride: 4 * 4, 294 Rect: image.Rect(0, 0, 4, 4), 295 Pix: []uint8{ 296 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 297 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 298 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 299 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 300 }, 301 }, 302 expected: &image.RGBA{ 303 Stride: 2 * 4, 304 Rect: image.Rect(0, 0, 2, 2), 305 Pix: []uint8{ 306 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 307 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 308 }, 309 }, 310 }, 311 } 312 313 for _, c := range cases { 314 actual := Resize(c.img, c.width, c.height, Box) 315 if !util.RGBAImageEqual(actual, c.expected) { 316 t.Errorf("%s: expected: %#v, actual: %#v", "ResizeNearestNeighbor "+c.name, util.RGBAToString(c.expected), util.RGBAToString(actual)) 317 } 318 } 319} 320 321func TestResizeLinear(t *testing.T) { 322 cases := []struct { 323 name string 324 width int 325 height int 326 img *image.RGBA 327 expected *image.RGBA 328 }{ 329 { 330 name: "x2", 331 width: 4, 332 height: 4, 333 img: &image.RGBA{ 334 Stride: 2 * 4, 335 Rect: image.Rect(0, 0, 2, 2), 336 Pix: []uint8{ 337 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 338 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 339 }, 340 }, 341 expected: &image.RGBA{ 342 Stride: 4 * 4, 343 Rect: image.Rect(0, 0, 4, 4), 344 Pix: []uint8{ 345 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 346 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 347 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 348 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 349 }, 350 }, 351 }, 352 { 353 name: "x0.5", 354 width: 2, 355 height: 2, 356 img: &image.RGBA{ 357 Stride: 4 * 4, 358 Rect: image.Rect(0, 0, 4, 4), 359 Pix: []uint8{ 360 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 361 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 362 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 363 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 364 }, 365 }, 366 expected: &image.RGBA{ 367 Stride: 2 * 4, 368 Rect: image.Rect(0, 0, 2, 2), 369 Pix: []uint8{ 370 0xA3, 0x31, 0x31, 0xF9, 0x41, 0xB3, 0x21, 0xEA, 371 0x40, 0x21, 0xB3, 0xEA, 0x5B, 0x7A, 0x7A, 0xB0, 372 }, 373 }, 374 }, 375 } 376 377 for _, c := range cases { 378 actual := Resize(c.img, c.width, c.height, Linear) 379 if !util.RGBAImageEqual(actual, c.expected) { 380 t.Errorf("%s: expected: %#v, actual: %#v", "ResizeLinear "+c.name, util.RGBAToString(c.expected), util.RGBAToString(actual)) 381 } 382 } 383} 384 385func TestResizeGaussian(t *testing.T) { 386 cases := []struct { 387 name string 388 width int 389 height int 390 img *image.RGBA 391 expected *image.RGBA 392 }{ 393 { 394 name: "x2", 395 width: 4, 396 height: 4, 397 img: &image.RGBA{ 398 Stride: 2 * 4, 399 Rect: image.Rect(0, 0, 2, 2), 400 Pix: []uint8{ 401 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 402 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 403 }, 404 }, 405 expected: &image.RGBA{ 406 Stride: 4 * 4, 407 Rect: image.Rect(0, 0, 4, 4), 408 Pix: []uint8{ 409 0xFF, 0x0, 0x0, 0xFF, 0xD6, 0x29, 0x0, 0xFF, 0x29, 0xD6, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 410 0xD6, 0x0, 0x29, 0xFF, 0xB7, 0x26, 0x25, 0xFC, 0x34, 0xC5, 0x18, 0xEE, 0x14, 0xEB, 0x14, 0xEB, 411 0x29, 0x0, 0xD6, 0xFF, 0x33, 0x17, 0xC6, 0xEE, 0x61, 0x7D, 0x7C, 0xA5, 0x6C, 0x94, 0x6C, 0x94, 412 0x0, 0x0, 0xFF, 0xFF, 0x14, 0x14, 0xEB, 0xEB, 0x6C, 0x6C, 0x94, 0x94, 0x80, 0x80, 0x80, 0x80, 413 }, 414 }, 415 }, 416 { 417 name: "x0.5", 418 width: 2, 419 height: 2, 420 img: &image.RGBA{ 421 Stride: 4 * 4, 422 Rect: image.Rect(0, 0, 4, 4), 423 Pix: []uint8{ 424 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 425 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 426 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 427 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 428 }, 429 }, 430 expected: &image.RGBA{ 431 Stride: 2 * 4, 432 Rect: image.Rect(0, 0, 2, 2), 433 Pix: []uint8{ 434 0xAF, 0x2A, 0x2A, 0xFB, 0x39, 0xBE, 0x1B, 0xEC, 435 0x39, 0x1B, 0xBE, 0xEC, 0x5E, 0x7C, 0x7C, 0xAA, 436 }, 437 }, 438 }, 439 } 440 441 for _, c := range cases { 442 actual := Resize(c.img, c.width, c.height, Gaussian) 443 if !util.RGBAImageEqual(actual, c.expected) { 444 t.Errorf("%s: expected: %#v, actual: %#v", "ResizeGaussian "+c.name, util.RGBAToString(c.expected), util.RGBAToString(actual)) 445 } 446 } 447} 448 449func TestResizeCatmullRom(t *testing.T) { 450 cases := []struct { 451 name string 452 width int 453 height int 454 img *image.RGBA 455 expected *image.RGBA 456 }{ 457 { 458 name: "x2", 459 width: 4, 460 height: 4, 461 img: &image.RGBA{ 462 Stride: 2 * 4, 463 Rect: image.Rect(0, 0, 2, 2), 464 Pix: []uint8{ 465 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 466 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 467 }, 468 }, 469 expected: &image.RGBA{ 470 Stride: 4 * 4, 471 Rect: image.Rect(0, 0, 4, 4), 472 Pix: []uint8{ 473 0xFF, 0x0, 0x0, 0xFF, 0xD9, 0x37, 0x0, 0xFF, 0x31, 0xD3, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 474 0xCA, 0x0, 0x35, 0xFF, 0xA6, 0x30, 0x2F, 0xFA, 0x3F, 0xB5, 0x20, 0xEA, 0x1D, 0xE7, 0x18, 0xE2, 475 0x35, 0x0, 0xCA, 0xFF, 0x3F, 0x20, 0xB6, 0xEA, 0x5B, 0x7A, 0x7A, 0xAF, 0x6E, 0xA3, 0x5D, 0x92, 476 0x0, 0x0, 0xFF, 0xFF, 0xC, 0x19, 0xF9, 0xE3, 0x69, 0x5C, 0xA8, 0x91, 0x97, 0x81, 0x7F, 0x69, 477 }, 478 }, 479 }, 480 { 481 name: "x0.5", 482 width: 2, 483 height: 2, 484 img: &image.RGBA{ 485 Stride: 4 * 4, 486 Rect: image.Rect(0, 0, 4, 4), 487 Pix: []uint8{ 488 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 489 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 490 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 491 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 492 }, 493 }, 494 expected: &image.RGBA{ 495 Stride: 2 * 4, 496 Rect: image.Rect(0, 0, 2, 2), 497 Pix: []uint8{ 498 0xB4, 0x27, 0x27, 0xFC, 0x36, 0xC3, 0x19, 0xED, 499 0x35, 0x19, 0xC3, 0xED, 0x60, 0x7C, 0x7C, 0xA7, 500 }, 501 }, 502 }, 503 } 504 505 for _, c := range cases { 506 actual := Resize(c.img, c.width, c.height, CatmullRom) 507 if !util.RGBAImageEqual(actual, c.expected) { 508 t.Errorf("%s: expected: %#v, actual: %#v", "ResizeCatmullRom "+c.name, util.RGBAToString(c.expected), util.RGBAToString(actual)) 509 } 510 } 511} 512 513func TestResizeMitchell(t *testing.T) { 514 cases := []struct { 515 name string 516 width int 517 height int 518 img *image.RGBA 519 expected *image.RGBA 520 }{ 521 { 522 name: "x2", 523 width: 4, 524 height: 4, 525 img: &image.RGBA{ 526 Stride: 2 * 4, 527 Rect: image.Rect(0, 0, 2, 2), 528 Pix: []uint8{ 529 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 530 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 531 }, 532 }, 533 expected: &image.RGBA{ 534 Stride: 4 * 4, 535 Rect: image.Rect(0, 0, 4, 4), 536 Pix: []uint8{ 537 0xFF, 0x0, 0x0, 0xFF, 0xC5, 0x40, 0x0, 0xFF, 0x3E, 0xC3, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 538 0xC0, 0x0, 0x3F, 0xFF, 0x99, 0x37, 0x37, 0xF7, 0x47, 0xA8, 0x27, 0xE7, 0x21, 0xE1, 0x1F, 0xDF, 539 0x3F, 0x0, 0xC0, 0xFF, 0x47, 0x28, 0xA9, 0xE8, 0x58, 0x78, 0x78, 0xB7, 0x63, 0xA2, 0x5D, 0x9C, 540 0x0, 0x0, 0xFF, 0xFF, 0x1B, 0x1F, 0xE7, 0xDF, 0x61, 0x5D, 0xA4, 0x9C, 0x88, 0x80, 0x80, 0x78, 541 }, 542 }, 543 }, 544 { 545 name: "x0.5", 546 width: 2, 547 height: 2, 548 img: &image.RGBA{ 549 Stride: 4 * 4, 550 Rect: image.Rect(0, 0, 4, 4), 551 Pix: []uint8{ 552 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 553 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 554 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 555 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 556 }, 557 }, 558 expected: &image.RGBA{ 559 Stride: 2 * 4, 560 Rect: image.Rect(0, 0, 2, 2), 561 Pix: []uint8{ 562 0xA7, 0x2E, 0x2F, 0xFA, 0x3E, 0xB7, 0x1F, 0xEA, 563 0x3E, 0x1F, 0xB7, 0xEB, 0x5C, 0x7B, 0x7B, 0xAE, 564 }, 565 }, 566 }, 567 } 568 569 for _, c := range cases { 570 actual := Resize(c.img, c.width, c.height, MitchellNetravali) 571 if !util.RGBAImageEqual(actual, c.expected) { 572 t.Errorf("%s: expected: %#v, actual: %#v", "ResizeMitchell "+c.name, util.RGBAToString(c.expected), util.RGBAToString(actual)) 573 } 574 } 575} 576 577func TestResizeLanczos(t *testing.T) { 578 cases := []struct { 579 name string 580 width int 581 height int 582 img *image.RGBA 583 expected *image.RGBA 584 }{ 585 { 586 name: "x2", 587 width: 4, 588 height: 4, 589 img: &image.RGBA{ 590 Stride: 2 * 4, 591 Rect: image.Rect(0, 0, 2, 2), 592 Pix: []uint8{ 593 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 594 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80, 595 }, 596 }, 597 expected: &image.RGBA{ 598 Stride: 4 * 4, 599 Rect: image.Rect(0, 0, 4, 4), 600 Pix: []uint8{ 601 0xFF, 0x0, 0x0, 0xFF, 0xE1, 0x40, 0x0, 0xFF, 0x34, 0xD5, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 602 0xC4, 0x0, 0x3B, 0xFF, 0x9D, 0x34, 0x34, 0xF8, 0x44, 0xAD, 0x25, 0xE8, 0x23, 0xE7, 0x19, 0xDC, 603 0x3B, 0x0, 0xC4, 0xFF, 0x45, 0x25, 0xAD, 0xE8, 0x59, 0x79, 0x79, 0xB5, 0x73, 0xAE, 0x51, 0x8D, 604 0x0, 0x0, 0xFF, 0xFF, 0x1, 0x19, 0xFF, 0xDC, 0x69, 0x51, 0xBA, 0x8D, 0xB0, 0x84, 0x7D, 0x50, 605 }, 606 }, 607 }, 608 { 609 name: "x0.5", 610 width: 2, 611 height: 2, 612 img: &image.RGBA{ 613 Stride: 4 * 4, 614 Rect: image.Rect(0, 0, 4, 4), 615 Pix: []uint8{ 616 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 617 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 618 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 619 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 620 }, 621 }, 622 expected: &image.RGBA{ 623 Stride: 2 * 4, 624 Rect: image.Rect(0, 0, 2, 2), 625 Pix: []uint8{ 626 0xBA, 0x24, 0x24, 0xFC, 0x31, 0xC8, 0x17, 0xEF, 627 0x32, 0x17, 0xC8, 0xEF, 0x62, 0x7D, 0x7D, 0xA4, 628 }, 629 }, 630 }, 631 } 632 633 for _, c := range cases { 634 actual := Resize(c.img, c.width, c.height, Lanczos) 635 if !util.RGBAImageEqual(actual, c.expected) { 636 t.Errorf("%s: expected: %#v, actual: %#v", "ResizeLanczos "+c.name, util.RGBAToString(c.expected), util.RGBAToString(actual)) 637 } 638 } 639} 640 641func TestCrop(t *testing.T) { 642 cases := []struct { 643 name string 644 rect image.Rectangle 645 img *image.RGBA 646 expected *image.RGBA 647 }{ 648 { 649 name: "center", 650 rect: image.Rect(1, 1, 3, 3), 651 img: &image.RGBA{ 652 Stride: 4 * 4, 653 Rect: image.Rect(0, 0, 4, 4), 654 Pix: []uint8{ 655 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 656 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 657 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 658 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 659 }, 660 }, 661 expected: &image.RGBA{ 662 Stride: 2 * 4, 663 Rect: image.Rect(1, 1, 3, 3), 664 Pix: []uint8{ 665 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 666 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 667 }, 668 }, 669 }, 670 { 671 name: "top left", 672 rect: image.Rect(0, 0, 1, 1), 673 img: &image.RGBA{ 674 Stride: 4 * 4, 675 Rect: image.Rect(0, 0, 4, 4), 676 Pix: []uint8{ 677 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 678 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 679 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 680 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 681 }, 682 }, 683 expected: &image.RGBA{ 684 Stride: 1 * 4, 685 Rect: image.Rect(0, 0, 1, 1), 686 Pix: []uint8{ 687 0xFF, 0x0, 0x0, 0xFF, 688 }, 689 }, 690 }, 691 { 692 name: "no change", 693 rect: image.Rect(0, 0, 4, 4), 694 img: &image.RGBA{ 695 Stride: 4 * 4, 696 Rect: image.Rect(0, 0, 4, 4), 697 Pix: []uint8{ 698 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 699 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 700 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 701 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 702 }, 703 }, 704 expected: &image.RGBA{ 705 Stride: 4 * 4, 706 Rect: image.Rect(0, 0, 4, 4), 707 Pix: []uint8{ 708 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 709 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 710 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 711 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 712 }, 713 }, 714 }, 715 { 716 name: "larger intersect", 717 rect: image.Rect(-50, -50, 50, 50), 718 img: &image.RGBA{ 719 Stride: 4 * 4, 720 Rect: image.Rect(0, 0, 4, 4), 721 Pix: []uint8{ 722 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 723 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 724 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 725 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 726 }, 727 }, 728 expected: &image.RGBA{ 729 Stride: 4 * 4, 730 Rect: image.Rect(0, 0, 4, 4), 731 Pix: []uint8{ 732 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 733 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 734 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 735 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 736 }, 737 }, 738 }, 739 { 740 name: "horizontal only", 741 rect: image.Rect(2, 0, 4, 4), 742 img: &image.RGBA{ 743 Stride: 4 * 4, 744 Rect: image.Rect(0, 0, 4, 4), 745 Pix: []uint8{ 746 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 747 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 748 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 749 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 750 }, 751 }, 752 expected: &image.RGBA{ 753 Stride: 2 * 4, 754 Rect: image.Rect(2, 0, 4, 4), 755 Pix: []uint8{ 756 0x40, 0xBF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 757 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 758 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 759 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 760 }, 761 }, 762 }, 763 { 764 name: "vertical only", 765 rect: image.Rect(0, 2, 4, 4), 766 img: &image.RGBA{ 767 Stride: 4 * 4, 768 Rect: image.Rect(0, 0, 4, 4), 769 Pix: []uint8{ 770 0xFF, 0x0, 0x0, 0xFF, 0xBF, 0x40, 0x0, 0xFF, 0x40, 0xBF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 771 0xBF, 0x0, 0x40, 0xFF, 0x97, 0x38, 0x38, 0xF7, 0x48, 0xA7, 0x28, 0xE7, 0x20, 0xDF, 0x20, 0xDF, 772 0x40, 0x0, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 773 0x0, 0x0, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 774 }, 775 }, 776 expected: &image.RGBA{ 777 Stride: 4 * 4, 778 Rect: image.Rect(0, 2, 4, 4), 779 Pix: []uint8{ 780 0x40, 0x00, 0xBF, 0xFF, 0x48, 0x28, 0xA7, 0xE7, 0x58, 0x78, 0x78, 0xB8, 0x60, 0xA0, 0x60, 0xA0, 781 0x00, 0x00, 0xFF, 0xFF, 0x20, 0x20, 0xDF, 0xDF, 0x60, 0x60, 0xA0, 0xA0, 0x80, 0x80, 0x80, 0x80, 782 }, 783 }, 784 }, 785 } 786 787 for _, c := range cases { 788 actual := Crop(c.img, c.rect) 789 if !util.RGBAImageEqual(actual, c.expected) { 790 t.Errorf("%s: expected: %#v, actual: %#v", "Crop "+c.name, util.RGBAToString(c.expected), util.RGBAToString(actual)) 791 } 792 } 793} 794 795func BenchmarkResizeTenth(b *testing.B) { 796 benchResize(b, 4096, 4096, 0.1, Linear) 797} 798 799func BenchmarkResizeQuarter(b *testing.B) { 800 benchResize(b, 4096, 4096, 0.25, Linear) 801} 802 803func BenchmarkResizeHalf(b *testing.B) { 804 benchResize(b, 4096, 4096, 0.5, Linear) 805} 806 807func BenchmarkResize1x(b *testing.B) { 808 benchResize(b, 1024, 1024, 1.0, Linear) 809} 810 811func BenchmarkResize2x(b *testing.B) { 812 benchResize(b, 1024, 1024, 2.0, Linear) 813} 814 815func BenchmarkResize4x(b *testing.B) { 816 benchResize(b, 1024, 1024, 4.0, Linear) 817} 818 819func BenchmarkResize8x(b *testing.B) { 820 benchResize(b, 1024, 1024, 8.0, Linear) 821} 822 823func BenchmarkResize16x(b *testing.B) { 824 benchResize(b, 1024, 1024, 16.0, Linear) 825} 826 827func benchResize(b *testing.B, w, h int, scale float64, f ResampleFilter) { 828 newW := int(float64(w) * scale) 829 newH := int(float64(h) * scale) 830 img := image.NewRGBA(image.Rect(0, 0, w, h)) 831 b.ResetTimer() 832 for n := 0; n < b.N; n++ { 833 benchResult = Resize(img, newW, newH, f) 834 } 835} 836