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

New 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

New 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

New 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

New in version 0.5.0.

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

Checkout Open a Pseudo Image for some examples.

ImageMagick-7 Support

New 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.