fdintino / pillow-avif-plugin

A pillow plugin that adds avif support via libavif
BSD 2-Clause "Simplified" License
77 stars 12 forks source link

Issues with Converting GIFs with Alpha Channels to AVIF Format #46

Open wooeorbs opened 3 months ago

wooeorbs commented 3 months ago

I apologize in advance as I am not fluent in English and have to rely on a translation tool to communicate.

I've encountered an issue where the alpha channel is not preserved when converting GIFs with alpha channels to the AVIF format using the following code:

image.save(image_path_out + '.avif', 'AVIF', save_all=True, speed=0, subsampling="4:2:0", quality=75)

To address this, I tried the following approach:

if "transparency" in image.info:
    frames = []
    for frame in ImageSequence.Iterator(image):
        frame = frame.convert('RGBA')
        frames.append(frame)
    frames[0].save(image_path_out + '.avif', save_all=True, append_images=frames[1:], speed=0, subsampling="4:2:0", quality=75)
else:
    image.save(image_path_out + '.avif', 'AVIF', save_all=True, speed=0, subsampling="4:2:0", quality=75)

This method successfully preserved the alpha channel, but the playback was much faster than expected.

When I tried saving the frames with the duration specified as below, the playback speed appeared normal:

def animation_frame(image):
    frames = []
    durations = []
    last_duration = 100

    for frame in ImageSequence.Iterator(image):
        if "transparency" in image.info:
            frame = frame.convert('RGBA')
        frames.append(frame.copy())

        current_duration = frame.info.get('duration', last_duration)
        durations.append(current_duration)

        last_duration = current_duration

    return frames, durations

    frames[0].save(image_path_out + '.avif', save_all=True, append_images=frames[1:], duration=durations, speed=0, subsampling="4:2:0", quality=75)

I am unsure if this is the correct approach. According to an issue thread (https://github.com/fdintino/pillow-avif-plugin/issues/14), playback issues might arise from viewers or players that do not support the image sequence mode correctly. When I directly convert and view the result in Chrome using HTML, the playback is significantly slower. In contrast, other viewers play it much faster. Including duration=image.info['duration'] seems to smooth out playback in both Chrome and other viewers.

I am unclear whether I am doing something wrong. It would be ideal if a straightforward conversion could yield a proper result without specifying additional options. For converting JPG to AVIF, chroma subsampling wasn't automatically handled, so I utilized ExifTool to read the original specifications. Based on those, the automatically adjusts the subsampling to match the original, whether it's 4:4:4 or 4:2:0. Additionally, for JPGs and PNGs in grayscale mode, the code also needed to include a conversion to chroma subsampling YUV400.

Interestingly, converting PNGs with alpha channels automatically optimizes and converts without these issues. Why does converting GIFs with alpha channels not automatically preserve these channels, and why doesn't it play back correctly? Additionally, I'm curious why, when converting JPG to AVIF, the chroma subsampling isn't automatically adjusted to match the original's specifications, such as maintaining 4:4:4 if that's what the source uses. Is there something I am missing, or is this an issue with the current implementation?