:orphan:

What's new in Wand 0.5?
=======================

This guide doesn't cover all changes in 0.5.  See also the full list of
changes in :ref:`changelog-0.5`.


Numpy I/O
---------

.. versionadded:: 0.5.3

Instances of Wand's :class:`~wand.image.Image` can be created directly from
a :class:`numpy.array` object, or other objects that implements
`array interface`__ protocol.

__ https://docs.scipy.org/doc/numpy/reference/arrays.interface.html

.. code-block:: python

    import numpy as np
    from wand.image import Image

    array = np.zeros([100, 100, 3], dtype=np.uint8)
    array[:, :] = [0xff, 0x00, 0x00]

    with Image.from_array(array) as img:
        print(img[0, 0])  #=> srgb(255, 0, 0)

You can also convert an instance of :class:`~wand.image.Image` into an array.

.. code-block:: python

    import numpy as np
    from wand.image import Image

    with Image(filename='rose:') as img:
        array = np.array(img)
        print(array.shape)  #=> (70, 46, 3)


Resource Limits
---------------

.. versionadded:: 0.5.1

The :attr:`~wand.resource.limits` dictionary helper allows you to define run-time
policies. Doing this allows your application to process images without consuming
too much system resources.

.. code-block:: python

    from wand.image import Image
    from wand.resource import limits

    limits['thread'] = 1  # Only allow one CPU thread for raster.
    with Image(filename='input.tif') as img:
        pass

See :class:`~wand.resource.ResourceLimits` for more details.


Import & Extract Profiles
-------------------------

.. versionadded:: 0.5.1

Embedded profiles, like ICC_, can be accessed via
:attr:`Image.profiles <wand.image.Image.profiles>` dictionary.

.. code-block:: python

    with Image(filename='photo.jpg') as photo:
        with open('color_profile.icc', 'rb') as profile:
            photo.profiles['icc'] = profile.read()

.. hint::

    Each profile payload will be a raw binary blob. ImageMagick & Wand will not
    edit payloads, but only get, set, and delete them from an image.

See :class:`~wand.image.ProfileDict` for more details.

.. _ICC: https://en.wikipedia.org/wiki/ICC_profile


Pseudo Images
-------------

.. versionadded:: 0.5.0

The :class:`~wand.image.Image` constructor now accepts the ``pseudo`` parameter.
This allows you to quickly read `Pseudo-image Formats`_, and `Built-in Patterns`_

.. _Pseudo-image Formats: https://imagemagick.org/script/formats.php#pseudo
.. _Built-in Patterns: https://imagemagick.org/script/formats.php#builtin-images

Checkout :ref:`open_pseudo` for some examples.


ImageMagick-7 Support
---------------------

.. versionadded:: 0.5.0

The release of Wand 0.5 now supports both versions of ImageMagick-6 &
ImageMagick-7. ImageMagick-7 introduces some key behavior changes, and some
care should go into any application that was previously written for
ImageMagick-6 before upgrading system libraries.

To understand the fundamental changes, please review
`Porting to ImageMagick Version 7`_ for a more definitive overview.

.. _Porting to ImageMagick Version 7: https://www.imagemagick.org/script/porting.php

Notes on Porting 6 to 7
^^^^^^^^^^^^^^^^^^^^^^^

A few key changes worth reviewing.


HDRI by Default
'''''''''''''''
Vanilla installs of ImageMagick-7 include HDRI enabled by default. Users may
experience increased depth of color, but with reduced performance during
certain color manipulation routines. Max color-values should never be
hard-coded, but rely on :attr:`Image.quantum_range <wand.image.BaseImage.quantum_range>` to ensure
consistent results. It is also possible to experience color-value underflow /
overflow during arithmetic operations when upgrading.

An example of an underflow between versions::

    # ImageMagick-6
    with Image(width=1, height=1, background=Color("gray5")) as canvas:
        canvas.evaluate("subtract", canvas.quantum_range * 0.07)
        print(canvas[0, 0]) #=> srgb(0,0,0)

    # ImageMagick-7
    with Image(width=1, height=1, background=Color("gray5")) as canvas:
        canvas.evaluate("subtract", canvas.quantum_range * 0.07)
        print(canvas[0, 0]) #=> srgb(-1.90207%,-1.90207%,-1.90207%)

The majority of the image-manipulation methods are guarded against overflows by
internal clamping_ routines, but folks working directly with
:meth:`Image.evaluate() <wand.image.BaseImage.evaluate>`,
:meth:`Image.function() <wand.image.BaseImage.function>`, and
:meth:`Image.composite_channel() <wand.image.BaseImage.composite_channel>` should take caution.
Method :meth:`Image.clamp() <wand.image.BaseImage.clamp>` as been provided for
this task.::

    with Image(width=1, height=1, background=Color("gray5")) as canvas:
        canvas.evaluate("subtract", canvas.quantum_range * 0.07)
        canvas.clamp()
        print(canvas[0, 0]) #=> srgb(0,0,0)


.. _clamping: https://en.wikipedia.org/wiki/Clamping_(graphics)

Image Color-Channel Awareness
'''''''''''''''''''''''''''''
With ImageMagick-7, colors have descriptive traits, and are managed through
channel-masks. An elegant solution to manage active color channels, and
simplify core library functions.

Users implementing :meth:`Image.composite_channel() <wand.image.BaseImage.composite_channel>` should review
previous solutions of composite ``"copy..."`` operators as the behavior may
have changed.

You can play around with the effects of channel masks with
:c:func:`MagickSetImageChannelMask` function. For example::

    from wand.image import Image, CHANNELS
    from wand.api import library

    with Image(filename="rose:") as img:
        # Isolate only Red & Green channels
        active_mask = CHANNELS["red"] | CHANNELS["green"]
        previous_mask = library.MagickSetImageChannelMask(img.wand, active_mask)
        img.evaluate("rightshift", 1)
        # Restore previous channels
        library.MagickSetImageChannelMask(img.wand, previous_mask)
        img.save(filename="blue_rose.png")


Alpha Replaces Opacity & Matte
''''''''''''''''''''''''''''''
Opacity methods & enumerated value have been renamed to alpha with
ImageMagick-7. Although the majority of the functionalities are the same, user
are responsible for checking the library version before calling an opacity
method / enumerated value.

For example::

    from wand.version import MAGICK_VERSION_NUMBER
    from wand.image import Image

    with Image(filename="wizard:") as img:
        image_type = "truecoloralpha"      # IM7 enum
        if MAGICK_VERSION_NUMBER < 0x700:  # Backwards support for IM6
            image_type = "truecolormatte"
        img.type = image_type

The reference documentation have been updated to note specific values
available per ImageMagick versions.

.. note::

    For "What's New in Wand 0.4", see `previous announcements`_.

    .. _previous announcements: 0.4.html
