sorl-thumbnail icon indicating copy to clipboard operation
sorl-thumbnail copied to clipboard

No way to address issues with images provided to get_thumbnail()

Open RevolutionTech opened this issue 4 years ago • 1 comments

sorl-thumbnail does not provide any way to catch and address errors when attempting to read invalid images using get_thumbnail(). I noticed that the project has a THUMBNAIL_DEBUG setting to address this problem, but it appears to only apply to template tags and not when using the low-level API directly.

Here is my specific use case: I have a Django REST Framework serializer for users that contains a photo field which produces a URL to a thumbnail of the user's photo. Here is the current code:

from django.contrib.staticfiles.storage import staticfiles_storage
from rest_framework import serializers
from sorl.thumbnail import get_thumbnail

class UserSerializer(serializers.ModelSerializer):
    photo = serializers.SerializerMethodField("get_photo_url")
    
    class Meta:
        model = User
        fields = ("first_name", "last_name", "photo")

    def get_photo_url(self, obj):
        try:
            photo = obj.photo
        except Photo.DoesNotExist:
            return staticfiles_storage.url("img/person-outline.png")
        else:
            # broken images cause errors to be logged, but those errors are not propagated here
            thumbnail = get_thumbnail(photo.img, "135x135", crop="center")
            return self.context["request"].build_absolute_uri(thumbnail.url)

If there is something wrong with the image provided to get_thumbnail(), perhaps it doesn't exist or cannot be read as an image, that exception is not propagated here. Instead, errors are logged and a dummy thumbnail is used instead.

I'd like to detect when this happens so that I can I can provide a static image instead, as you can see I am doing when the Photo instance for the user does not exist (ie. the user has never uploaded a photo). I could use the THUMBNAIL_DUMMY_SOURCE setting to achieve this, but that is a global setting and I have a similar paradigm when serializing other types of objects other than users. I don't want to share the same thumbnail for each of these cases, I want a different thumbnail for each type.

The only solution I can think of that I could apply right now would be to always inspect the image file before providing it to get_thumbnail(), but obviously this is very inefficient.

If THUMBNAIL_DEBUG was changed to apply when using the low-level API, this would solve my problem, but honestly it wouldn't be an ideal solution. I'd rather not raise errors across the entire application, but instead I think it would be better to be able to opt into raising errors in specific contexts. For instance, a kwarg raise_errors could be added to get_thumbnail():

try:
    thumbnail = get_thumbnail(photo.img, "135x135", raise_errors=True, crop="center")
except IOError:
    ...  # handle invalid file

Does this request make sense? Have I missed anything? Perhaps there is a feature in sorl-thumbnail I am not aware of that satisfies my use case? Regardless, thank you very much for reading. I appreciate your time.

RevolutionTech avatar Aug 23 '20 00:08 RevolutionTech

In my case, this was the error message if I called the get_thumbnail function: 'NoneType' object has no attribute 'build_absolute_uri'

The error's reason: There was no request object in the serializer's context dictionary.

The solution: In the View, I call the serializer with serializer = TheSerializer(instance, data=data, context=self.get_serializer_context()) or serializer = TheSerializer(instance, data=data, context={'request': request})

I hope this will help to somebody :)

hunasdf avatar Apr 29 '21 10:04 hunasdf