Search code examples
pythonimageimagemagickimagemagick-convertwand

Frames not disappearing in python wand


As per hint from here, I tried to create a gif with 2 dissimilar images as below. It works, but one frame is not disappearing to show another frame. Why would this happen and how to rectify?

from wand.image import Image as Image2

with Image2() as wand:
    # Add new frames into sequance
    with Image2(blob=d2) as one:
        wand.sequence.append(one)
    with Image2(blob=d3) as two:
        wand.sequence.append(two)

    # Create progressive delay for each frame
    for cursor in range(2):
        with wand.sequence[cursor] as frame:
            frame.delay = 100
    # Set layer type
    wand.type = 'optimize'
    wand.save(filename='animated.gif')

display(Image('animated.gif'))

Current output:
img


Solution

  • Updated answer

    ... I got error using that ...

    Looks like hardcoded validation values does not allow this technique to be leveraged. This is a bug, and I'll submit a patch upstream.

    @ -2548,7 +2548,7 @@ class BaseImage(Resource):
             .. versionadded:: 0.4.3
    
             """
    -        if method not in ['merge', 'flatten', 'mosaic']:
    +        if method not in IMAGE_LAYER_METHOD:
                 raise TypeError('method must be one of: merge, flatten, mosaic')
    

    Currently, doesn't implement the C-API methods MagickSetImageDispose, or MagickExtentImage which is what I believe you need. Although it's fairly easy to implement those methods, you may be stuck with rebuilding each image - frame-by-frame.

    from wand.image import Image as Image2
    from wand.color import Color
    from wand.compat import nested
    
    with nested(Image2(),
                Image2(filename='d2.gif'),
                Image2(filename='d3.gif')) as (wand, one, two):
        width = max(one.width, two.width)
        height = max(one.height, two.height)
        # Rebuild images with full extent of frame
        with Image2(width=width, height=height, background=Color('WHITE')) as f1:
            f1.composite(one, 0, 0)
            wand.sequence.append(f1)
        with Image2(width=width, height=height, background=Color('WHITE')) as f2:
            f2.composite(two, 0, 0)
            wand.sequence.append(f2)
        # Create progressive delay for each frame
        for cursor in range(2):
            with wand.sequence[cursor] as frame:
                frame.delay = 100
        wand.type = 'optimize'
        wand.save(filename='animated.gif')
    

    Original answer DO NOT USE!


    You want to call wand.image.Image.merge_layers method, not wand.image.Image.type property.

    Try the following...

    with Image2() as wand:
        # Add new frames into sequance
        with Image2(blob=d2) as one:
            wand.sequence.append(one)
        with Image2(blob=d3) as two:
            wand.sequence.append(two)
    
        # Create progressive delay for each frame
        for cursor in range(2):
            with wand.sequence[cursor] as frame:
                frame.delay = 100
        # Set layer type
        wand.merge_layers('optimize')  # or 'optimizeimage', or 'composite'
        wand.save(filename='animated.gif')