1# vim: set fileencoding=utf-8 : 2import filecmp 3from functools import reduce 4 5import os 6import pytest 7import tempfile 8import shutil 9 10import pyvips 11from helpers import IMAGES, JPEG_FILE, RGBA_FILE, unsigned_formats, \ 12 signed_formats, float_formats, int_formats, \ 13 noncomplex_formats, all_formats, max_value, \ 14 sizeof_format, rot45_angles, rot45_angle_bonds, \ 15 rot_angles, rot_angle_bonds, run_cmp, run_cmp2, \ 16 assert_almost_equal_objects, temp_filename 17 18 19class TestConversion: 20 tempdir = None 21 22 # run a function on an image, 23 # 50,50 and 10,10 should have different values on the test image 24 # don't loop over band elements 25 def run_image_pixels(self, message, im, fn): 26 run_cmp(message, im, 50, 50, fn) 27 run_cmp(message, im, 10, 10, fn) 28 29 # run a function on a pair of images 30 # 50,50 and 10,10 should have different values on the test image 31 # don't loop over band elements 32 def run_image_pixels2(self, message, left, right, fn): 33 run_cmp2(message, left, right, 50, 50, fn) 34 run_cmp2(message, left, right, 10, 10, fn) 35 36 def run_unary(self, images, fn, fmt=all_formats): 37 [self.run_image_pixels(fn.__name__ + (' %s' % y), x.cast(y), fn) 38 for x in images for y in fmt] 39 40 def run_binary(self, images, fn, fmt=all_formats): 41 [self.run_image_pixels2(fn.__name__ + (' %s %s' % (y, z)), 42 x.cast(y), x.cast(z), fn) 43 for x in images for y in fmt for z in fmt] 44 45 @classmethod 46 def setup_class(cls): 47 cls.tempdir = tempfile.mkdtemp() 48 im = pyvips.Image.mask_ideal(100, 100, 0.5, 49 reject=True, optical=True) 50 cls.colour = (im * [1, 2, 3] + [2, 3, 4]).copy(interpretation="srgb") 51 cls.mono = cls.colour[1].copy(interpretation="b-w") 52 cls.all_images = [cls.mono, cls.colour] 53 cls.image = pyvips.Image.jpegload(JPEG_FILE) 54 55 @classmethod 56 def teardown_class(cls): 57 shutil.rmtree(cls.tempdir, ignore_errors=True) 58 cls.colour = None 59 cls.mono = None 60 cls.image = None 61 cls.all_images = None 62 63 def test_cast(self): 64 # casting negative pixels to an unsigned format should clip to zero 65 for signed in signed_formats: 66 im = (pyvips.Image.black(1, 1) - 10).cast(signed) 67 for unsigned in unsigned_formats: 68 im2 = im.cast(unsigned) 69 assert im2.avg() == 0 70 71 # casting very positive pixels to a signed format should clip to max 72 im = (pyvips.Image.black(1, 1) + max_value["uint"]).cast("uint") 73 assert im.avg() == max_value["uint"] 74 im2 = im.cast("int") 75 assert im2.avg() == max_value["int"] 76 im = (pyvips.Image.black(1, 1) + max_value["ushort"]).cast("ushort") 77 im2 = im.cast("short") 78 assert im2.avg() == max_value["short"] 79 im = (pyvips.Image.black(1, 1) + max_value["uchar"]).cast("uchar") 80 im2 = im.cast("char") 81 assert im2.avg() == max_value["char"] 82 83 def test_band_and(self): 84 def band_and(x): 85 if isinstance(x, pyvips.Image): 86 return x.bandand() 87 else: 88 return [reduce(lambda a, b: int(a) & int(b), x)] 89 90 self.run_unary(self.all_images, band_and, fmt=int_formats) 91 92 def test_band_or(self): 93 def band_or(x): 94 if isinstance(x, pyvips.Image): 95 return x.bandor() 96 else: 97 return [reduce(lambda a, b: int(a) | int(b), x)] 98 99 self.run_unary(self.all_images, band_or, fmt=int_formats) 100 101 def test_band_eor(self): 102 def band_eor(x): 103 if isinstance(x, pyvips.Image): 104 return x.bandeor() 105 else: 106 return [reduce(lambda a, b: int(a) ^ int(b), x)] 107 108 self.run_unary(self.all_images, band_eor, fmt=int_formats) 109 110 def test_bandjoin(self): 111 def bandjoin(x, y): 112 if isinstance(x, pyvips.Image) and isinstance(y, pyvips.Image): 113 return x.bandjoin(y) 114 else: 115 return x + y 116 117 self.run_binary(self.all_images, bandjoin) 118 119 def test_bandjoin_const(self): 120 x = self.colour.bandjoin(1) 121 assert x.bands == 4 122 assert x[3].avg() == 1 123 124 x = self.colour.bandjoin([1, 2]) 125 assert x.bands == 5 126 assert x[3].avg() == 1 127 assert x[4].avg() == 2 128 129 def test_bandmean(self): 130 def bandmean(x): 131 if isinstance(x, pyvips.Image): 132 return x.bandmean() 133 else: 134 return [sum(x) // len(x)] 135 136 self.run_unary(self.all_images, bandmean, fmt=noncomplex_formats) 137 138 def test_bandrank(self): 139 def median(x, y): 140 joined = [[a, b] for a, b in zip(x, y)] 141 # .sort() isn't a function, so we have to run this as a separate 142 # pass 143 [z.sort() for z in joined] 144 return [z[len(z) // 2] for z in joined] 145 146 def bandrank(x, y): 147 if isinstance(x, pyvips.Image) and isinstance(y, pyvips.Image): 148 return x.bandrank([y]) 149 else: 150 return median(x, y) 151 152 self.run_binary(self.all_images, bandrank, fmt=noncomplex_formats) 153 154 # we can mix images and constants, and set the index arg 155 a = self.mono.bandrank([2], index=0) 156 b = (self.mono < 2).ifthenelse(self.mono, 2) 157 assert (a - b).abs().min() == 0 158 159 def test_cache(self): 160 def cache(x): 161 if isinstance(x, pyvips.Image): 162 return x.cache() 163 else: 164 return x 165 166 self.run_unary(self.all_images, cache) 167 168 def test_copy(self): 169 x = self.colour.copy(interpretation=pyvips.Interpretation.LAB) 170 assert x.interpretation == pyvips.Interpretation.LAB 171 x = self.colour.copy(xres=42) 172 assert x.xres == 42 173 x = self.colour.copy(yres=42) 174 assert x.yres == 42 175 x = self.colour.copy(xoffset=42) 176 assert x.xoffset == 42 177 x = self.colour.copy(yoffset=42) 178 assert x.yoffset == 42 179 x = self.colour.copy(coding=pyvips.Coding.NONE) 180 assert x.coding == pyvips.Coding.NONE 181 182 def test_bandfold(self): 183 x = self.mono.bandfold() 184 assert x.width == 1 185 assert x.bands == self.mono.width 186 187 y = x.bandunfold() 188 assert y.width == self.mono.width 189 assert y.bands == 1 190 assert x.avg() == y.avg() 191 192 x = self.mono.bandfold(factor=2) 193 assert x.width == self.mono.width / 2 194 assert x.bands == 2 195 196 y = x.bandunfold(factor=2) 197 assert y.width == self.mono.width 198 assert y.bands == 1 199 assert x.avg() == y.avg() 200 201 def test_byteswap(self): 202 x = self.mono.cast("ushort") 203 y = x.byteswap().byteswap() 204 assert x.width == y.width 205 assert x.height == y.height 206 assert x.bands == y.bands 207 assert x.avg() == y.avg() 208 209 def test_embed(self): 210 for fmt in all_formats: 211 test = self.colour.cast(fmt) 212 213 im = test.embed(20, 20, 214 self.colour.width + 40, 215 self.colour.height + 40) 216 pixel = im(10, 10) 217 assert_almost_equal_objects(pixel, [0, 0, 0]) 218 pixel = im(30, 30) 219 assert_almost_equal_objects(pixel, [2, 3, 4]) 220 pixel = im(im.width - 10, im.height - 10) 221 assert_almost_equal_objects(pixel, [0, 0, 0]) 222 223 im = test.embed(20, 20, 224 self.colour.width + 40, 225 self.colour.height + 40, 226 extend=pyvips.Extend.COPY) 227 pixel = im(10, 10) 228 assert_almost_equal_objects(pixel, [2, 3, 4]) 229 pixel = im(im.width - 10, im.height - 10) 230 assert_almost_equal_objects(pixel, [2, 3, 4]) 231 232 im = test.embed(20, 20, 233 self.colour.width + 40, 234 self.colour.height + 40, 235 extend=pyvips.Extend.BACKGROUND, 236 background=[7, 8, 9]) 237 pixel = im(10, 10) 238 assert_almost_equal_objects(pixel, [7, 8, 9]) 239 pixel = im(im.width - 10, im.height - 10) 240 assert_almost_equal_objects(pixel, [7, 8, 9]) 241 242 im = test.embed(20, 20, 243 self.colour.width + 40, 244 self.colour.height + 40, 245 extend=pyvips.Extend.WHITE) 246 pixel = im(10, 10) 247 # uses 255 in all bytes of ints, 255.0 for float 248 pixel = [int(x) & 0xff for x in pixel] 249 assert_almost_equal_objects(pixel, [255, 255, 255]) 250 pixel = im(im.width - 10, im.height - 10) 251 pixel = [int(x) & 0xff for x in pixel] 252 assert_almost_equal_objects(pixel, [255, 255, 255]) 253 254 @pytest.mark.skipif(pyvips.type_find("VipsOperation", "gravity") == 0, 255 reason="no gravity in this vips, skipping test") 256 def test_gravity(self): 257 im = pyvips.Image.black(1, 1) + 255 258 259 positions = [ 260 ['centre', 1, 1], 261 ['north', 1, 0], 262 ['south', 1, 2], 263 ['east', 2, 1], 264 ['west', 0, 1], 265 ['north-east', 2, 0], 266 ['south-east', 2, 2], 267 ['south-west', 0, 2], 268 ['north-west', 0, 0] 269 ] 270 271 for direction, x, y in positions: 272 im2 = im.gravity(direction, 3, 3) 273 assert_almost_equal_objects(im2(x, y), [255]) 274 assert_almost_equal_objects(im2.avg(), 255.0 / 9.0) 275 276 def test_extract(self): 277 for fmt in all_formats: 278 test = self.colour.cast(fmt) 279 280 pixel = test(30, 30) 281 assert_almost_equal_objects(pixel, [2, 3, 4]) 282 283 sub = test.extract_area(25, 25, 10, 10) 284 285 pixel = sub(5, 5) 286 assert_almost_equal_objects(pixel, [2, 3, 4]) 287 288 sub = test.extract_band(1, n=2) 289 290 pixel = sub(30, 30) 291 assert_almost_equal_objects(pixel, [3, 4]) 292 293 def test_slice(self): 294 test = self.colour 295 bands = [x.avg() for x in test] 296 297 x = test[0].avg() 298 assert x == bands[0] 299 300 x = test[-1].avg() 301 assert_almost_equal_objects(x, bands[2]) 302 303 x = [i.avg() for i in test[1:3]] 304 assert_almost_equal_objects(x, bands[1:3]) 305 306 x = [i.avg() for i in test[1:-1]] 307 assert_almost_equal_objects(x, bands[1:-1]) 308 309 x = [i.avg() for i in test[:2]] 310 assert_almost_equal_objects(x, bands[:2]) 311 312 x = [i.avg() for i in test[1:]] 313 assert_almost_equal_objects(x, bands[1:]) 314 315 x = [i.avg() for i in test[-1]] 316 assert_almost_equal_objects(x, bands[-1]) 317 318 def test_crop(self): 319 for fmt in all_formats: 320 test = self.colour.cast(fmt) 321 322 pixel = test(30, 30) 323 assert_almost_equal_objects(pixel, [2, 3, 4]) 324 325 sub = test.crop(25, 25, 10, 10) 326 327 pixel = sub(5, 5) 328 assert_almost_equal_objects(pixel, [2, 3, 4]) 329 330 @pytest.mark.skipif(pyvips.type_find("VipsOperation", "smartcrop") == 0, 331 reason="no smartcrop, skipping test") 332 def test_smartcrop(self): 333 test = self.image.smartcrop(100, 100) 334 assert test.width == 100 335 assert test.height == 100 336 337 def test_falsecolour(self): 338 for fmt in all_formats: 339 test = self.colour.cast(fmt) 340 341 im = test.falsecolour() 342 343 assert im.width == test.width 344 assert im.height == test.height 345 assert im.bands == 3 346 347 pixel = im(30, 30) 348 assert_almost_equal_objects(pixel, [20, 0, 41]) 349 350 def test_flatten(self): 351 for fmt in unsigned_formats + [pyvips.BandFormat.SHORT, 352 pyvips.BandFormat.INT] + float_formats: 353 mx = 255 354 alpha = mx / 2.0 355 nalpha = mx - alpha 356 test = self.colour.bandjoin(alpha).cast(fmt) 357 pixel = test(30, 30) 358 359 predict = [int(x) * alpha / mx for x in pixel[:-1]] 360 361 im = test.flatten() 362 363 assert im.bands == 3 364 pixel = im(30, 30) 365 for x, y in zip(pixel, predict): 366 # we use float arithetic for int and uint, so the rounding 367 # differs ... don't require huge accuracy 368 assert abs(x - y) < 2 369 370 im = test.flatten(background=[100, 100, 100]) 371 372 pixel = test(30, 30) 373 predict = [int(x) * alpha / mx + (100 * nalpha) / mx 374 for x in pixel[:-1]] 375 376 assert im.bands == 3 377 pixel = im(30, 30) 378 for x, y in zip(pixel, predict): 379 assert abs(x - y) < 2 380 381 # if the image has max_alpha less than the numeric range of the 382 # format, we can get out of range values ... check they are clipped 383 # correctly 384 rgba = pyvips.Image.new_from_file(RGBA_FILE) 385 386 im = rgba * 256 387 im = im.cast("ushort") 388 im = im.flatten() 389 390 im2 = rgba * 256 391 im2 = im2.flatten() 392 im2 = im2.cast("ushort") 393 394 assert(abs(im - im2).max() == 0) 395 396 def test_premultiply(self): 397 for fmt in unsigned_formats + [pyvips.BandFormat.SHORT, 398 pyvips.BandFormat.INT] + float_formats: 399 mx = 255 400 alpha = mx / 2.0 401 test = self.colour.bandjoin(alpha).cast(fmt) 402 pixel = test(30, 30) 403 404 predict = [int(x) * alpha / mx for x in pixel[:-1]] + [alpha] 405 406 im = test.premultiply() 407 408 assert im.bands == test.bands 409 pixel = im(30, 30) 410 for x, y in zip(pixel, predict): 411 # we use float arithetic for int and uint, so the rounding 412 # differs ... don't require huge accuracy 413 assert abs(x - y) < 2 414 415 @pytest.mark.skipif(pyvips.type_find("VipsConversion", "composite") == 0, 416 reason="no composite support, skipping test") 417 def test_composite(self): 418 # 50% transparent image 419 overlay = self.colour.bandjoin(128) 420 base = self.colour + 100 421 comp = base.composite(overlay, "over") 422 423 assert_almost_equal_objects(comp(0, 0), [51.8, 52.8, 53.8, 255], 424 threshold=0.1) 425 426 def test_unpremultiply(self): 427 for fmt in unsigned_formats + [pyvips.BandFormat.SHORT, 428 pyvips.BandFormat.INT] + float_formats: 429 mx = 255 430 alpha = mx / 2.0 431 test = self.colour.bandjoin(alpha).cast(fmt) 432 pixel = test(30, 30) 433 434 predict = [int(x) / (alpha / mx) for x in pixel[:-1]] + [alpha] 435 436 im = test.unpremultiply() 437 438 assert im.bands == test.bands 439 pixel = im(30, 30) 440 for x, y in zip(pixel, predict): 441 # we use float arithetic for int and uint, so the rounding 442 # differs ... don't require huge accuracy 443 assert abs(x - y) < 2 444 445 def test_flip(self): 446 for fmt in all_formats: 447 test = self.colour.cast(fmt) 448 449 result = test.fliphor() 450 result = result.flipver() 451 result = result.fliphor() 452 result = result.flipver() 453 454 diff = (test - result).abs().max() 455 456 assert diff == 0 457 458 def test_gamma(self): 459 exponent = 2.4 460 for fmt in noncomplex_formats: 461 mx = max_value[fmt] 462 test = (self.colour + mx / 2.0).cast(fmt) 463 464 norm = mx ** exponent / mx 465 result = test.gamma() 466 before = test(30, 30) 467 after = result(30, 30) 468 predict = [x ** exponent / norm for x in before] 469 for a, b in zip(after, predict): 470 # ie. less than 1% error, rounding on 7-bit images 471 # means this is all we can expect 472 assert abs(a - b) < mx / 100.0 473 474 exponent = 1.2 475 for fmt in noncomplex_formats: 476 mx = max_value[fmt] 477 test = (self.colour + mx / 2.0).cast(fmt) 478 479 norm = mx ** exponent / mx 480 result = test.gamma(exponent=1.0 / 1.2) 481 before = test(30, 30) 482 after = result(30, 30) 483 predict = [x ** exponent / norm for x in before] 484 for a, b in zip(after, predict): 485 # ie. less than 1% error, rounding on 7-bit images 486 # means this is all we can expect 487 assert abs(a - b) < mx / 100.0 488 489 def test_grid(self): 490 test = self.colour.replicate(1, 12) 491 assert test.width == self.colour.width 492 assert test.height == self.colour.height * 12 493 494 for fmt in all_formats: 495 im = test.cast(fmt) 496 result = im.grid(test.width, 3, 4) 497 assert result.width == self.colour.width * 3 498 assert result.height == self.colour.height * 4 499 500 before = im(10, 10) 501 after = result(10 + test.width * 2, 10 + test.width * 2) 502 assert_almost_equal_objects(before, after) 503 504 before = im(50, 50) 505 after = result(50 + test.width * 2, 50 + test.width * 2) 506 assert_almost_equal_objects(before, after) 507 508 def test_ifthenelse(self): 509 test = self.mono > 3 510 for x in all_formats: 511 for y in all_formats: 512 t = (self.colour + 10).cast(x) 513 e = self.colour.cast(y) 514 r = test.ifthenelse(t, e) 515 516 assert r.width == self.colour.width 517 assert r.height == self.colour.height 518 assert r.bands == self.colour.bands 519 520 predict = e(10, 10) 521 result = r(10, 10) 522 assert_almost_equal_objects(result, predict) 523 524 predict = t(50, 50) 525 result = r(50, 50) 526 assert_almost_equal_objects(result, predict) 527 528 test = self.colour > 3 529 for x in all_formats: 530 for y in all_formats: 531 t = (self.mono + 10).cast(x) 532 e = self.mono.cast(y) 533 r = test.ifthenelse(t, e) 534 535 assert r.width == self.colour.width 536 assert r.height == self.colour.height 537 assert r.bands == self.colour.bands 538 539 cp = test(10, 10) 540 tp = t(10, 10) * 3 541 ep = e(10, 10) * 3 542 predict = [te if ce != 0 else ee 543 for ce, te, ee in zip(cp, tp, ep)] 544 result = r(10, 10) 545 assert_almost_equal_objects(result, predict) 546 547 cp = test(50, 50) 548 tp = t(50, 50) * 3 549 ep = e(50, 50) * 3 550 predict = [te if ce != 0 else ee 551 for ce, te, ee in zip(cp, tp, ep)] 552 result = r(50, 50) 553 assert_almost_equal_objects(result, predict) 554 555 test = self.colour > 3 556 for x in all_formats: 557 for y in all_formats: 558 t = (self.mono + 10).cast(x) 559 e = self.mono.cast(y) 560 r = test.ifthenelse(t, e, blend=True) 561 562 assert r.width == self.colour.width 563 assert r.height == self.colour.height 564 assert r.bands == self.colour.bands 565 566 result = r(10, 10) 567 assert_almost_equal_objects(result, [3, 3, 13]) 568 569 test = self.mono > 3 570 r = test.ifthenelse([1, 2, 3], self.colour) 571 assert r.width == self.colour.width 572 assert r.height == self.colour.height 573 assert r.bands == self.colour.bands 574 assert r.format == self.colour.format 575 assert r.interpretation == self.colour.interpretation 576 result = r(10, 10) 577 assert_almost_equal_objects(result, [2, 3, 4]) 578 result = r(50, 50) 579 assert_almost_equal_objects(result, [1, 2, 3]) 580 581 test = self.mono 582 r = test.ifthenelse([1, 2, 3], self.colour, blend=True) 583 assert r.width == self.colour.width 584 assert r.height == self.colour.height 585 assert r.bands == self.colour.bands 586 assert r.format == self.colour.format 587 assert r.interpretation == self.colour.interpretation 588 result = r(10, 10) 589 assert_almost_equal_objects(result, [2, 3, 4], threshold=0.1) 590 result = r(50, 50) 591 assert_almost_equal_objects(result, [3.0, 4.9, 6.9], threshold=0.1) 592 593 def test_switch(self): 594 x = pyvips.Image.grey(256, 256, uchar=True) 595 596 # slice into two at 128, we should get 50% of pixels in each half 597 index = pyvips.Image.switch([x < 128, x >= 128]) 598 assert index.avg() == 0.5 599 600 # slice into four 601 index = pyvips.Image.switch([ 602 x < 64, 603 x >= 64 and x < 128, 604 x >= 128 and x < 192, 605 x >= 192 606 ]) 607 assert index.avg() == 1.5 608 609 # no match should return n + 1 610 index = pyvips.Image.switch([x == 1000, x == 2000]) 611 assert index.avg() == 2 612 613 def test_insert(self): 614 for x in all_formats: 615 for y in all_formats: 616 main = self.mono.cast(x) 617 sub = self.colour.cast(y) 618 r = main.insert(sub, 10, 10) 619 620 assert r.width == main.width 621 assert r.height == main.height 622 assert r.bands == sub.bands 623 624 a = r(10, 10) 625 b = sub(0, 0) 626 assert_almost_equal_objects(a, b) 627 628 a = r(0, 0) 629 b = main(0, 0) * 3 630 assert_almost_equal_objects(a, b) 631 632 for x in all_formats: 633 for y in all_formats: 634 main = self.mono.cast(x) 635 sub = self.colour.cast(y) 636 r = main.insert(sub, 10, 10, expand=True, background=100) 637 638 assert r.width == main.width + 10 639 assert r.height == main.height + 10 640 assert r.bands == sub.bands 641 642 a = r(r.width - 5, 5) 643 assert_almost_equal_objects(a, [100, 100, 100]) 644 645 def test_arrayjoin(self): 646 max_width = 0 647 max_height = 0 648 max_bands = 0 649 for image in self.all_images: 650 if image.width > max_width: 651 max_width = image.width 652 if image.height > max_height: 653 max_height = image.height 654 if image.bands > max_bands: 655 max_bands = image.bands 656 657 im = pyvips.Image.arrayjoin(self.all_images) 658 assert im.width == max_width * len(self.all_images) 659 assert im.height == max_height 660 assert im.bands == max_bands 661 662 im = pyvips.Image.arrayjoin(self.all_images, across=1) 663 assert im.width == max_width 664 assert im.height == max_height * len(self.all_images) 665 assert im.bands == max_bands 666 667 im = pyvips.Image.arrayjoin(self.all_images, shim=10) 668 assert im.width == max_width * len(self.all_images) + 10 * (len(self.all_images) - 1) # noqa: E501 669 assert im.height == max_height 670 assert im.bands == max_bands 671 672 def test_msb(self): 673 for fmt in unsigned_formats: 674 mx = max_value[fmt] 675 size = sizeof_format[fmt] 676 test = (self.colour + mx / 8.0).cast(fmt) 677 im = test.msb() 678 679 before = test(10, 10) 680 predict = [int(x) >> ((size - 1) * 8) for x in before] 681 result = im(10, 10) 682 assert_almost_equal_objects(result, predict) 683 684 before = test(50, 50) 685 predict = [int(x) >> ((size - 1) * 8) for x in before] 686 result = im(50, 50) 687 assert_almost_equal_objects(result, predict) 688 689 for fmt in signed_formats: 690 mx = max_value[fmt] 691 size = sizeof_format[fmt] 692 test = (self.colour + mx / 8.0).cast(fmt) 693 im = test.msb() 694 695 before = test(10, 10) 696 predict = [128 + (int(x) >> ((size - 1) * 8)) for x in before] 697 result = im(10, 10) 698 assert_almost_equal_objects(result, predict) 699 700 before = test(50, 50) 701 predict = [128 + (int(x) >> ((size - 1) * 8)) for x in before] 702 result = im(50, 50) 703 assert_almost_equal_objects(result, predict) 704 705 for fmt in unsigned_formats: 706 mx = max_value[fmt] 707 size = sizeof_format[fmt] 708 test = (self.colour + mx / 8.0).cast(fmt) 709 im = test.msb(band=1) 710 711 before = [test(10, 10)[1]] 712 predict = [int(x) >> ((size - 1) * 8) for x in before] 713 result = im(10, 10) 714 assert_almost_equal_objects(result, predict) 715 716 before = [test(50, 50)[1]] 717 predict = [int(x) >> ((size - 1) * 8) for x in before] 718 result = im(50, 50) 719 assert_almost_equal_objects(result, predict) 720 721 def test_recomb(self): 722 array = [[0.2, 0.5, 0.3]] 723 724 def recomb(x): 725 if isinstance(x, pyvips.Image): 726 return x.recomb(array) 727 else: 728 sum = 0 729 for i, c in zip(array[0], x): 730 sum += i * c 731 return [sum] 732 733 self.run_unary([self.colour], recomb, fmt=noncomplex_formats) 734 735 def test_replicate(self): 736 for fmt in all_formats: 737 im = self.colour.cast(fmt) 738 739 test = im.replicate(10, 10) 740 assert test.width == self.colour.width * 10 741 assert test.height == self.colour.height * 10 742 743 before = im(10, 10) 744 after = test(10 + im.width * 2, 10 + im.width * 2) 745 assert_almost_equal_objects(before, after) 746 747 before = im(50, 50) 748 after = test(50 + im.width * 2, 50 + im.width * 2) 749 assert_almost_equal_objects(before, after) 750 751 def test_rot45(self): 752 # test has a quarter-circle in the bottom right 753 test = self.colour.crop(0, 0, 51, 51) 754 for fmt in all_formats: 755 im = test.cast(fmt) 756 757 im2 = im.rot45() 758 before = im(50, 50) 759 after = im2(25, 50) 760 assert_almost_equal_objects(before, after) 761 762 for a, b in zip(rot45_angles, rot45_angle_bonds): 763 im2 = im.rot45(angle=a) 764 after = im2.rot45(angle=b) 765 diff = (after - im).abs().max() 766 assert diff == 0 767 768 def test_rot(self): 769 # test has a quarter-circle in the bottom right 770 test = self.colour.crop(0, 0, 51, 51) 771 for fmt in all_formats: 772 im = test.cast(fmt) 773 774 im2 = im.rot(pyvips.Angle.D90) 775 before = im(50, 50) 776 after = im2(0, 50) 777 assert_almost_equal_objects(before, after) 778 779 for a, b in zip(rot_angles, rot_angle_bonds): 780 im2 = im.rot(a) 781 after = im2.rot(b) 782 diff = (after - im).abs().max() 783 assert diff == 0 784 785 def test_autorot(self): 786 rotation_images = os.path.join(IMAGES, 'rotation') 787 files = os.listdir(rotation_images) 788 files.sort() 789 790 meta = { 791 0: {'w': 290, 'h': 442}, 792 1: {'w': 308, 'h': 410}, 793 2: {'w': 308, 'h': 410}, 794 3: {'w': 308, 'h': 410}, 795 4: {'w': 308, 'h': 410}, 796 5: {'w': 231, 'h': 308}, 797 6: {'w': 231, 'h': 308}, 798 7: {'w': 231, 'h': 308}, 799 8: {'w': 231, 'h': 308}, 800 } 801 802 i = 0 803 for f in files: 804 if '.autorot.' not in f and not f.startswith('.'): 805 source_filename = os.path.join(rotation_images, f) 806 807 actual_filename = temp_filename(self.tempdir, '.jpg') 808 809 pyvips.Image.new_from_file(source_filename).autorot().write_to_file(actual_filename) 810 811 actual = pyvips.Image.new_from_file(actual_filename) 812 813 assert actual.width == meta[i]['w'] 814 assert actual.height == meta[i]['h'] 815 assert actual.get('orientation') if actual.get_typeof('orientation') else None is None 816 i = i + 1 817 818 def test_scaleimage(self): 819 for fmt in noncomplex_formats: 820 test = self.colour.cast(fmt) 821 822 im = test.scaleimage() 823 assert im.max() == 255 824 assert im.min() == 0 825 826 im = test.scaleimage(log=True) 827 assert im.max() == 255 828 829 def test_subsample(self): 830 for fmt in all_formats: 831 test = self.colour.cast(fmt) 832 833 im = test.subsample(3, 3) 834 assert im.width == test.width // 3 835 assert im.height == test.height // 3 836 837 before = test(60, 60) 838 after = im(20, 20) 839 assert_almost_equal_objects(before, after) 840 841 def test_zoom(self): 842 for fmt in all_formats: 843 test = self.colour.cast(fmt) 844 845 im = test.zoom(3, 3) 846 assert im.width == test.width * 3 847 assert im.height == test.height * 3 848 849 before = test(50, 50) 850 after = im(150, 150) 851 assert_almost_equal_objects(before, after) 852 853 def test_wrap(self): 854 for fmt in all_formats: 855 test = self.colour.cast(fmt) 856 857 im = test.wrap() 858 assert im.width == test.width 859 assert im.height == test.height 860 861 before = test(0, 0) 862 after = im(50, 50) 863 assert_almost_equal_objects(before, after) 864 865 before = test(50, 50) 866 after = im(0, 0) 867 assert_almost_equal_objects(before, after) 868 869 870if __name__ == '__main__': 871 pytest.main() 872