# 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 0.5 series.

## Numpy I/O

Added in version 0.5.3.

Instances of Wand’s `Image` can be created directly from a `numpy.array` object, or other objects that implements array interface protocol.

    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 `Image` into an array.

    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

Added in version 0.5.1.

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

    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 `ResourceLimits` for more details.

## Import & Extract Profiles

Added in version 0.5.1.

Embedded profiles, like ICC, can be accessed via `Image.profiles` dictionary.

    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 `ProfileDict` for more details.

## Pseudo Images

Added in version 0.5.0.

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

Checkout Open a Pseudo Image for some examples.

## ImageMagick-7 Support

Added in version 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.

### Notes on Porting 6 t0 7

A few key changes worth reviewing.

#### HDRI by Default

Vanilla installs of ImageMagick-7 include HDRI enabled by default. Users may experiences increase depth of color, but with reduced performances during certain color manipulation routines. Max color-values should never be hard-coded, but rely on `Image.quantum_range` to ensure consistent results. It is also possible to experiences 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 `Image.evaluate()`, `Image.function()`, and `Image.composite_channel()` should take caution. Method `Image.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)

#### 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 `Image.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 `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.