swingmx / swingmusic

Swing Music is a beautiful, self-hosted music player for your local audio files. Like a cooler Spotify ... but bring your own music.
https://swingmx.com
MIT License
718 stars 41 forks source link

[Bug] Ridiculous converted playlist gif sizes #98

Closed cwilvx closed 1 year ago

cwilvx commented 1 year ago

Images used as playlist banner images are optimized by being converted to the webp format. Gifs are also given the same treatment.

Given the way gifs are handled, sometimes when high quality gifs are submited, the optimized "webp gif" is way more heavy than the original.

For comparison, a 4MB gif might result into a 17MB webp file. The expected size would be something like 1MB or less.

Here is the code that handles saving the submited image file:

# app/lib/playlistlib.py

def save_p_image(file, pid: str):
    """
    Saves a playlist banner image and returns the filepath.
    """
    img = Image.open(file)

    random_str = "".join(random.choices(string.ascii_letters + string.digits, k=5))

    img_path = pid + str(random_str) + ".webp"

    full_img_path = os.path.join(settings.APP_DIR, "images", "playlists", img_path)

    if file.content_type == "image/gif":
        frames = []

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

        frames[0].save(full_img_path, save_all=True, append_images=frames[1:])

        return img_path

    img.save(full_img_path, "webp")

    return img_path

The following gif was the 4MB file mentioned ealier. You can use it for testing.

723262

crackheadakira commented 1 year ago

Reading the docs for PIL says that you can use save_all() to save the WebP file if the systems WebP library is v0.50 or later, but you are just using the GIF saving function, so you could try Image.save_all() as that has a minimize_size option.

I'll go and see if I can get it to work.

(note: i don't know python beyond the basics)

cwilvx commented 1 year ago

If you can get it working, feel free to open a pull request. We'll be glad to have your contributions.

crackheadakira commented 1 year ago

So, I checked on the client to see what the max size the image was displayed at was, and it seemed to be 974x288, so I ended up resizing the image, but also adding a compression parameters to the save file. But this gives negligible size compression. Original: 4.1MiB Compressed: 3.5MiB


def save_p_image(file, pid: str):
    """
    Saves a playlist banner image and returns the filepath.
    """
    img = Image.open(file)

    random_str = "".join(random.choices(string.ascii_letters + string.digits, k=5))

    img_path = pid + str(random_str) + ".webp"

    aspect_ratio = img.width / img.height

    full_img_path = os.path.join(settings.APP_DIR, "images", "playlists", img_path)

    if file.content_type == "image/gif":
        frames = []

        for frame in ImageSequence.Iterator(img):
            frames.append(frame.resize((974, int(974 / aspect_ratio))))

        frames[0].save(full_img_path, save_all=True, append_images=frames[1:], loop=0, quality=80, minimize_size=True)

        return img_path

    img.save(full_img_path, "webp")

    return img_path
cwilvx commented 1 year ago

I don't know about resizing the gif, given that when the Extend app to full screen width option is enabled in the settings page, the resized image will be faded for large screens. eg. 2k or 4k monitors.

Is it possible to save the gif in webp format without loosing quality and getting a reasonable sized image? In the worst case scenario, almost same size as original doesn't seem that bad.

crackheadakira commented 1 year ago

If it's going to be similar to the original size, the best scenario is just directly uploading the gif file, as every other option I tried still resulted in a webp file larger than the original.

cwilvx commented 1 year ago

For the main playlist image, saving the original file seems like the best fit for now. For the thumbnail, the resized webp file has no size problem.

Since this bug does not happen to all gifs, what about checking the webp gif image size and if it's bigger than the original, we save the original?

But ... saving the gif in webp takes a lot of time (I'm assuming it's because of breaking it down into frames then rebuilding it in a new format). Saving the original gif might solve both the size problem and the time problem.

What is the better option here?

crackheadakira commented 1 year ago

Well, in the scenarios where the webp gif file size becomes smaller, by how much does it actually decrease? If it's still negligible then just saving the original file, but otherwise if they are good enough numbers then comparing the webp gif and original gif file sizes.