From 609dd3b4952d54510a3c03fa68c8eff5c9027feb Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 7 May 2020 19:18:19 +0200 Subject: [PATCH] Increase image quality of downscaled images from 70 to 95 --- api/config/settings/common.py | 5 +- api/funkwhale_api/cli/main.py | 1 + api/funkwhale_api/cli/media.py | 58 ++++++++++++++++++++ api/funkwhale_api/common/scripts/__init__.py | 2 - api/funkwhale_api/common/utils.py | 12 ++++ changes/changelog.d/thunbnails.enhancement | 1 + changes/notes.rst | 13 +++++ 7 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 api/funkwhale_api/cli/media.py create mode 100644 changes/changelog.d/thunbnails.enhancement diff --git a/api/config/settings/common.py b/api/config/settings/common.py index 9ba1ecd09..492d67ca1 100644 --- a/api/config/settings/common.py +++ b/api/config/settings/common.py @@ -1211,7 +1211,10 @@ VERSATILEIMAGEFIELD_RENDITION_KEY_SETS = { ("medium_square_crop", "crop__200x200"), ], } -VERSATILEIMAGEFIELD_SETTINGS = {"create_images_on_demand": False} +VERSATILEIMAGEFIELD_SETTINGS = { + "create_images_on_demand": False, + "jpeg_resize_quality": env.int("THUMBNAIL_JPEG_RESIZE_QUALITY", default=95), +} RSA_KEY_SIZE = 2048 # for performance gain in tests, since we don't need to actually create the # thumbnails diff --git a/api/funkwhale_api/cli/main.py b/api/funkwhale_api/cli/main.py index 9bad5a8eb..1453ca5d2 100644 --- a/api/funkwhale_api/cli/main.py +++ b/api/funkwhale_api/cli/main.py @@ -3,6 +3,7 @@ import sys from . import base from . import library # noqa +from . import media # noqa from . import users # noqa from rest_framework.exceptions import ValidationError diff --git a/api/funkwhale_api/cli/media.py b/api/funkwhale_api/cli/media.py new file mode 100644 index 000000000..c50df6b77 --- /dev/null +++ b/api/funkwhale_api/cli/media.py @@ -0,0 +1,58 @@ +import click + +from django.core.cache import cache +from django.conf import settings + +from versatileimagefield.image_warmer import VersatileImageFieldWarmer +from versatileimagefield import settings as vif_settings + +from funkwhale_api.common import utils as common_utils +from funkwhale_api.common.models import Attachment + +from . import base + + +@base.cli.group() +def media(): + """Manage media files (avatars, covers, attachments…)""" + pass + + +@media.command("generate-thumbnails") +def generate_thumbnails(): + """ + Generate thumbnails for all images (avatars, covers, etc.). + + This can take a long time and generate a lot of I/O depending of the size + of your library. + """ + MODELS = [ + (Attachment, "file", "attachment_square"), + ] + for model, attribute, key_set in MODELS: + click.echo( + "Generating thumbnails for {}.{}…".format(model._meta.label, attribute) + ) + qs = model.objects.exclude(**{"{}__isnull".format(attribute): True}) + qs = qs.exclude(**{attribute: ""}) + cache_key = "*{}{}*".format( + settings.MEDIA_URL, vif_settings.VERSATILEIMAGEFIELD_SIZED_DIRNAME + ) + entries = cache.keys(cache_key) + if entries: + click.echo( + " Clearing {} cache entries: {}…".format(len(entries), cache_key) + ) + for keys in common_utils.batch(iter(entries)): + cache.delete_many(keys) + warmer = VersatileImageFieldWarmer( + instance_or_queryset=qs, + rendition_key_set=key_set, + image_attr=attribute, + verbose=True, + ) + click.echo(" Creating images") + num_created, failed_to_create = warmer.warm() + click.echo( + " {} created, {} in error".format(num_created, len(failed_to_create)) + ) diff --git a/api/funkwhale_api/common/scripts/__init__.py b/api/funkwhale_api/common/scripts/__init__.py index 7c468d984..42160e30d 100644 --- a/api/funkwhale_api/common/scripts/__init__.py +++ b/api/funkwhale_api/common/scripts/__init__.py @@ -1,5 +1,4 @@ from . import create_actors -from . import create_image_variations from . import django_permissions_to_user_permissions from . import migrate_to_user_libraries from . import delete_pre_017_federated_uploads @@ -8,7 +7,6 @@ from . import test __all__ = [ "create_actors", - "create_image_variations", "django_permissions_to_user_permissions", "migrate_to_user_libraries", "delete_pre_017_federated_uploads", diff --git a/api/funkwhale_api/common/utils.py b/api/funkwhale_api/common/utils.py index 2a91524d5..5d7d401d7 100644 --- a/api/funkwhale_api/common/utils.py +++ b/api/funkwhale_api/common/utils.py @@ -23,6 +23,18 @@ from django.utils import timezone logger = logging.getLogger(__name__) +def batch(iterable, n=1): + has_entries = True + while has_entries: + current = [] + for i in range(0, n): + try: + current.append(next(iterable)) + except StopIteration: + has_entries = False + yield current + + def rename_file(instance, field_name, new_name, allow_missing_file=False): field = getattr(instance, field_name) current_name, extension = os.path.splitext(field.name) diff --git a/changes/changelog.d/thunbnails.enhancement b/changes/changelog.d/thunbnails.enhancement new file mode 100644 index 000000000..a402c654a --- /dev/null +++ b/changes/changelog.d/thunbnails.enhancement @@ -0,0 +1 @@ +Increased quality of JPEG thumbnails diff --git a/changes/notes.rst b/changes/notes.rst index 96ac3d765..ee0375658 100644 --- a/changes/notes.rst +++ b/changes/notes.rst @@ -5,3 +5,16 @@ Next release notes Those release notes refer to the current development branch and are reset after each release. + + +Increased quality of JPEG thumbnails [manual action required] +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Default quality for JPEG thumbnails was increased from 70 to 95, as 70 was producing visible artifacts in resized images. + +Because of this change, existing thumbnails will not load, and you will need to: + +1. delete the ``__sized__`` directory in your ``MEDIA_ROOT`` directory +2. run ``python manage.py fw media generate-thumbnails`` to regenerate thumbnails with the enhanced quality + +If you don't want to regenerate thumbnails, you can keep the old ones by adding ``THUMBNAIL_JPEG_RESIZE_QUALITY=70`` to your .env file.