Search code examples
pythonpython-imaging-library

PIL not saving animated files as animated .webp


This is a part of a function, it all works and 'saving as animated image' gets printed out to console. However, the saved image is a still one. It is not animated (it is .webp though).

try:
    with Image.open(avatar) as img:
        img = ImageOps.exif_transpose(img)

        if is_animated_image(img) and not permissions.Flags.enhanced_profile in user_permissions:
            response.add_errors('avatar', ["You need the enhanced profile premium feature to upload animated avatars."])
            response.status = status.HTTP_400_BAD_REQUEST

            return response

        width, height = img.size

        if width != height:
            print('resize_avatar')
            return resize_avatar(img, is_animated_image(img), attachment_name)

        if is_animated_image(img):
            print('saving as animated image')

            frames = []

            for frame in ImageSequence.Iterator(img):
                frames.append(frame)

            frames[0].save(
                f'{config.media_source}avatars/{attachment_name}',
                format='webp',
                save_all=True,
                append_images=frames[:1],
                loop=0,
            )
        else:
            img.save(f'{config.media_source}avatars/{attachment_name}', format='webp', save_all=True)

        response.status = status.HTTP_200_OK
        response.data = {'attachment_name' : attachment_name}

        return response

except Exception as e:
    functions.log_error("UPLOAD_AVATAR_ERROR", str(e))

    response.add_errors('avatar', ["Something went wrong, the developers have been notified."])
    response.status = status.HTTP_400_BAD_REQUEST

    return response

Solution

  • So this code actually contained 2 issues.

    1. The code in a way was fine. I was yelling about how I couldn't save 1 frame. But I had all rights to yell because I did in fact upload a gif and as explained in point 2, I was convinced I was working with an animated file. Where did it go wrong? Right at the beginning. img = ImageOps.exif_transpose(img) does not support images with more than 1 frame. It works, but would only apply changes to the first frame and forget about the other frames. So in fact I was trying to store 1 frame thinking I still had my original gif.
    2. The is_animated_image actually counted for 1 or more and not more than 1 frames. So I could have figured out earlier there was an issue if I wasn't so convinced this function only returned True when we had more than 1 frame.

    Thanks @Mark Setchel for making me deep dive more in my code.