Skip to content

Commit

Permalink
Finished Image.image_add/get/remove/set/swap methods
Browse files Browse the repository at this point in the history
  • Loading branch information
emcconville committed Jul 31, 2021
1 parent d3980a0 commit c6c676a
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 45 deletions.
8 changes: 6 additions & 2 deletions docs/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ Version 0.6.7

Unreleased.

- Added :meth:`Image.add_image() <wand.image.Image.add_image>` method.
- Added :meth:`Image.remove_image() <wand.image.Image.remove_image>` method.
- Added :meth:`Image.image_add() <wand.image.Image.image_add>` method.
- Added :meth:`Image.image_get() <wand.image.Image.image_get>` method.
- Added :meth:`Image.image_remove() <wand.image.Image.image_remove>` method.
- Added :meth:`Image.image_set() <wand.image.Image.image_set>` method.
- Added :meth:`Image.image_swap() <wand.image.Image.image_swap>` method.
- Fixed sub-image extraction on read. [:issue:`532`]
- [DOC] Completed :doc:`Distortion <./guide/distortion>` guide. [:issue:`534`]
- [DOC] Added :doc:`Morphology <./guide/morphology>` guide.


.. _changelog-0.6.6:
Expand Down
55 changes: 39 additions & 16 deletions tests/image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,16 +206,6 @@ def test_new_from_pseudo(fx_asset):
assert img.size == (10, 10)


def test_add_image():
with Image(filename='rose:') as a:
with Image(filename='rose:') as b:
a.add_image(b)
assert a.iterator_length() == 2
with raises(TypeError):
with Image(filename='rose:') as img:
img.add_image(0xdeadbeef)


def test_clone(fx_asset):
"""Clones the existing image."""
funcs = (lambda img: Image(image=img),
Expand All @@ -231,6 +221,45 @@ def test_clone(fx_asset):
img.wand


def test_image_add():
with Image(filename='rose:') as a:
with Image(filename='rose:') as b:
a.image_add(b)
assert a.iterator_length() == 2
with raises(TypeError):
with Image(filename='rose:') as img:
img.image_add(0xdeadbeef)


def test_image_get():
with Image(filename='rose:') as img:
with img.image_get() as i:
assert isinstance(i, Image)


def test_image_remove():
with Image(filename='null:') as empty:
empty.image_remove()
assert empty.iterator_length() == 0


def test_image_set():
with Image(filename='null:') as a:
with Image(filename='rose:') as b:
a.image_set(b)
assert a.iterator_length() == 1


def test_image_swap():
with Image(width=1, height=1, background='red') as a:
a.read(filename='xc:green')
a.read(filename='xc:blue')
was = a.iterator_get()
a.image_swap(0, 2)
assert a.iterator_get() == was
with raises(TypeError):
a.image_swap('a', 'b')

def test_ping_from_filename(fx_asset):
file_path = str(fx_asset.join('mona-lisa.jpg'))
with Image.ping(filename=file_path) as img:
Expand All @@ -249,12 +278,6 @@ def test_ping_from_file(fx_asset):
assert img.size == (402, 599)


def test_remove_image():
with Image(filename='null:') as empty:
empty.remove_image()
assert empty.iterator_length() == 0


def test_save_to_filename(fx_asset):
"""Saves an image to the filename."""
savefile = os.path.join(tempfile.mkdtemp(), 'savetest.jpg')
Expand Down
102 changes: 75 additions & 27 deletions wand/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2500,7 +2500,6 @@ def stroke_color(self):
return Color(stroke) if stroke else None

@stroke_color.setter
@manipulative
def stroke_color(self, color):
if isinstance(color, string_type):
color = Color(color)
Expand All @@ -2518,7 +2517,6 @@ def stroke_width(self):
return float(strokewidth) if strokewidth else None

@stroke_width.setter
@manipulative
def stroke_width(self, width):
assertions.assert_real(stroke_width=width)
self.options['strokewidth'] = str(width)
Expand Down Expand Up @@ -9457,23 +9455,6 @@ def mimetype(self):
rp = libmagick.DestroyString(rp)
return mtype

@trap_exception
def add_image(self, image):
"""Copies a given image on to the image stack. By default, the added
image will be append at the end of the stack, or immediately after
the current image iterator defined by :meth:`~BaseImage.iterator_set`.
Use :meth:`~BaseImage.iterator_reset` before calling this method to
insert the new image before existing images on the stack.
:param image: raster to add.
:type image: :class:`Image`
.. versionadded:: 0.6.7
"""
if not isinstance(image, Image):
raise TypeError('image must be instance of wand.image.Image')
return library.MagickAddImage(self.wand, image.wand)

def blank(self, width, height, background=None):
"""Creates blank image.
Expand Down Expand Up @@ -9603,6 +9584,81 @@ def data_url(self):
base_bytes = b64encode(self.make_blob())
return "data:{0};base64,{1}".format(mime_type, text(base_bytes))

@trap_exception
def image_add(self, image):
"""Copies a given image on to the image stack. By default, the added
image will be append at the end of the stack, or immediately after
the current image iterator defined by :meth:`~BaseImage.iterator_set`.
Use :meth:`~BaseImage.iterator_reset` before calling this method to
insert the new image before existing images on the stack.
:param image: raster to add.
:type image: :class:`Image`
.. versionadded:: 0.6.7
"""
if not isinstance(image, Image):
raise TypeError('image must be instance of wand.image.Image')
return library.MagickAddImage(self.wand, image.wand)

def image_get(self):
"""Generate & return a clone of a single image at the current
image-stack index.
.. versionadded:: 0.6.7
"""
r = library.MagickGetImage(self.wand)
if not r:
self.raise_exception()
return None # noqa - Safety if exception isn't thrown.
return Image(BaseImage(r))

@trap_exception
def image_remove(self):
"""Remove an image from the image-stack at the current index.
.. versionadded:: 0.6.7
"""
return library.MagickRemoveImage(self.wand)

@trap_exception
def image_set(self, image):
"""Overwrite current image on the image-stack with given image.
:param image: Wand instance of images to write to stack.
:type image: :class:`wand.image.Image`
.. versionadded:: 0.6.7
"""
if not isinstance(image, Image):
raise TypeError('image must be an instance of wand.image.Image,',
' not ' + repr(image))
return library.MagickSetImage(self.wand, image.wand)

@trap_exception
def image_swap(self, i, j):
"""Swap two images on the image-stack.
:param i: image index to replace with ``j``
:type i: :class:`numbers.Integral`
:param j: image index to replace with ``i``
:type j: :class:`numbers.Integral`
.. versionadded:: 0.6.7
"""
assertions.assert_integer(i=i)
assertions.assert_integer(j=j)
op = self.iterator_get()
self.iterator_set(i)
with self.image_get() as a:
self.iterator_set(j)
with self.image_get() as b:
self.image_set(a)
self.iterator_set(i)
self.image_set(b)
self.iterator_set(op)


def make_blob(self, format=None):
"""Makes the binary string of the image.
Expand Down Expand Up @@ -9758,14 +9814,6 @@ def read(self, file=None, filename=None, blob=None, background=None,
if units is not None:
self.units = units

@trap_exception
def remove_image(self):
"""Remove an image from the image-stack at the current index.
.. versionadded:: 0.6.7
"""
return library.MagickRemoveImage(self.wand)

def reset_sequence(self):
"""Remove any previously allocated :class:`~wand.sequence.SingleImage`
instances in :attr:`sequence` attribute.
Expand Down

0 comments on commit c6c676a

Please sign in to comment.