diff --git a/ChangeLog b/ChangeLog index c2261452..8536a03f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,7 @@ - added test_foreign.py, plus more test images - rewritten tiff writer is about 3 - 4x faster at making pyramids - jpg, magick, png, tiff readers now use only 1 fd per input image +- python: use [] to index and slice image bands 6/2/15 started 7.42.3 - bump version for back-compat ABI change diff --git a/TODO b/TODO index 7fdd515f..dbab1cf4 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,14 @@ python people are not going to want to use the glib arg parser, for example +- need to add [] overload to Ruby bindings + +- overload (x, y) to be getpoint()? + + + + + - support orientation tag in tiff images diff --git a/cplusplus/include/vips/VImage8.h b/cplusplus/include/vips/VImage8.h index 7489d232..323062cf 100644 --- a/cplusplus/include/vips/VImage8.h +++ b/cplusplus/include/vips/VImage8.h @@ -1263,6 +1263,12 @@ public: return( a * -1 ); } + friend VImage operator[]( VImage a, int index ) + throw( VError ) + { + return( a.extract_band( index ) ); + } + }; VIPS_NAMESPACE_END diff --git a/doc/using-python.xml b/doc/using-python.xml index 376a952d..620c1c70 100644 --- a/doc/using-python.xml +++ b/doc/using-python.xml @@ -347,6 +347,26 @@ help(image.add) result_image = ((image * [1, 2, 3]).abs() < 128) | 4 + + + The wrapper overloads [] to be band indexing. You can write: + + +result_image = image[2] + + + to extract the third band of the image. It implements the usual + slicing and negative indexes, so you can write: + + +result_image = image[1:] +result_image = image[:3] +result_image = image[-2:] +result_image = [x.avg() for x in image] + + + and so on. + diff --git a/python/Vips.py b/python/Vips.py index c6bf8fc5..5ee8dc90 100644 --- a/python/Vips.py +++ b/python/Vips.py @@ -757,6 +757,32 @@ class Image(Vips.Image): else: return self.relational_const(other, Vips.OperationRelational.NOTEQ) + def __getitem__(self, arg): + if isinstance(arg, slice): + i = 0 + if arg.start != None: + i = arg.start + + n = self.bands - i + if arg.stop != None: + if arg.stop < 0: + n = self.bands + arg.stop - i + else: + n = arg.stop - i + elif isinstance(arg, int): + i = arg + n = 1 + else: + raise TypeError + + if i < 0: + i = self.bands + i + + if i < 0 or i >= self.bands: + raise IndexError + + return self.extract_band(i, n = n) + # the cast operators int(), long() and float() must return numeric types, # so we can't define them for images @@ -813,7 +839,7 @@ class Image(Vips.Image): def bandsplit(self): """Split an n-band image into n separate images.""" - return [self.extract_band(i) for i in range(0, self.bands)] + return [x for x in self] def bandjoin(self, other): """Join a set of images bandwise.""" diff --git a/python/example/try17.py b/python/example/try17.py new file mode 100755 index 00000000..bc5eaf8f --- /dev/null +++ b/python/example/try17.py @@ -0,0 +1,18 @@ +#!/usr/bin/python3 + +import sys + +import logging +#logging.basicConfig(level = logging.DEBUG) + +from gi.repository import Vips + +#Vips.cache_set_trace(True) + +a = Vips.Image.new_from_file(sys.argv[1]) + +a = a[1:] + +a.write_to_file(sys.argv[2]) + + diff --git a/test/test_conversion.py b/test/test_conversion.py index 5518c4b7..df4e03ad 100755 --- a/test/test_conversion.py +++ b/test/test_conversion.py @@ -80,6 +80,8 @@ rot_angle_bonds = [Vips.Angle.D0, # the other def zip_expand(x, y): if isinstance(x, list) and isinstance(y, list): + if len(x) != len(y): + raise Vips.Error("zip_expand list args not equal length") return list(zip(x, y)) elif isinstance(x, list): return [[i, y] for i in x] @@ -138,7 +140,7 @@ class TestConversion(unittest.TestCase): def setUp(self): im = Vips.Image.mask_ideal(100, 100, 0.5, reject = True, optical = True) self.colour = im * [1, 2, 3] + [2, 3, 4] - self.mono = self.colour.extract_band(1) + self.mono = self.colour[1] self.all_images = [self.mono, self.colour] def test_band_and(self): @@ -295,6 +297,31 @@ class TestConversion(unittest.TestCase): pixel = sub.getpoint(30, 30) self.assertAlmostEqualObjects(pixel, [3, 4]) + def test_slice(self): + test = self.colour + bands = [x.avg() for x in test] + + x = test[0].avg() + self.assertEqual(x, bands[0]) + + x = test[-1].avg() + self.assertAlmostEqualObjects(x, bands[2]) + + x = [i.avg() for i in test[1:3]] + self.assertAlmostEqualObjects(x, bands[1:3]) + + x = [i.avg() for i in test[1:-1]] + self.assertAlmostEqualObjects(x, bands[1:-1]) + + x = [i.avg() for i in test[:2]] + self.assertAlmostEqualObjects(x, bands[:2]) + + x = [i.avg() for i in test[1:]] + self.assertAlmostEqualObjects(x, bands[1:]) + + x = [i.avg() for i in test[-1]] + self.assertAlmostEqualObjects(x, bands[-1]) + def test_crop(self): for fmt in all_formats: test = self.colour.cast(fmt)