Easy thumbnails for Django

Overview

Easy Thumbnails

Build Status

A powerful, yet easy to implement thumbnailing application for Django 1.11+

Below is a quick summary of usage. For more comprehensive information, view the full documentation online or the peruse the project's docs directory.

Installation

Run pip install easy-thumbnails.

Add easy_thumbnails to your INSTALLED_APPS setting:

INSTALLED_APPS = (
    ...
    'easy_thumbnails',
)

Run manage.py migrate easy_thumbnails.

Example usage

Thumbnail options can be predefined in settings.THUMBNAIL_ALIASES or just specified in the template or Python code when run.

Using a predefined alias

Given the following setting:

THUMBNAIL_ALIASES = {
    '': {
        'avatar': {'size': (50, 50), 'crop': True},
    },
}

Template:

{% load thumbnail %}
<img src="{{ profile.photo|thumbnail_url:'avatar' }}" alt="" />

Python:

from easy_thumbnails.files import get_thumbnailer
thumb_url = get_thumbnailer(profile.photo)['avatar'].url

Manually specifying size / options

Template:

{% load thumbnail %}
<img src="{% thumbnail profile.photo 50x50 crop %}" alt="" />

Python:

from easy_thumbnails.files import get_thumbnailer
options = {'size': (100, 100), 'crop': True}
thumb_url = get_thumbnailer(profile.photo).get_thumbnail(options).url

Using in combination with other thumbnailers

Alternatively, you load the templatetags by {% load easy_thumbnails_tags %} instead of traditional {% load thumbnail %}. It's especially useful in projects that do make use of multiple thumbnailer libraries that use the same name (thumbnail) for the templatetag module:

{% load easy_thumbnails_tags %}
<img src="{% thumbnail profile.photo 50x50 crop %}" alt="" />

Fields

You can use ThumbnailerImageField (or ThumbnailerField) for easier access to retrieve or generate thumbnail images.

For example:

from easy_thumbnails.fields import ThumbnailerImageField

class Profile(models.Model):
    user = models.OneToOneField('auth.User')
    photo = ThumbnailerImageField(upload_to='photos', blank=True)

Accessing the field's predefined alias in a template:

{% load thumbnail %}
<img src="{{ profile.photo.avatar.url }}" alt="" />

Accessing the field's predefined alias in Python code:

thumb_url = profile.photo['avatar'].url

Thumbnail options

crop

Before scaling the image down to fit within the size bounds, it first cuts the edges of the image to match the requested aspect ratio.

Use crop="smart" to try to keep the most interesting part of the image,

Use crop="0,10" to crop from the left edge and a 10% offset from the top edge. Crop from a single edge by leaving dimension empty (e.g. crop=",0"). Offset from the right / bottom by using negative numbers (e.g., crop="-0,-10").

Often used with the upscale option, which will allow enlarging of the image during scaling.

quality=XX

Changes the quality of the output JPEG thumbnail. Defaults to 85.

In Python code, this is given as a separate option to the get_thumbnail method rather than just alter the other

Other options

Valid thumbnail options are determined by the "thumbnail processors" installed.

See the reference documentation for a complete list of options provided by the default thumbnail processors.

Comments
  • white space on image, need zoom

    white space on image, need zoom

    Hi, can you check this page: http://dreamtravel.rs/sr-latn/destinacije/ i need that images to be full width and height, with zoom? I use it like this:

    <img src="{% thumbnail article.thumbnail 966x330 upscale %}">
    <img src="{% thumbnail category.image 406x200 crop upscale %}">
    

    Tried with crop and upscale, but doesn't work. What is solution for this?

    opened by mirzadelic 22
  • Easy thumbnails with remote storages like S3

    Easy thumbnails with remote storages like S3

    Hi,

    I'm using amazon S3 as remote storage and easy-thumbnails for creating thumbnails. However, easy-thumbnails queries to db for each thumbnail and it is so slow to check existency and modified time of image for every thumbnail. Thus this makes using remote storage and easy-thumbnails together so slow. Actually, I think this is already a known issue.

    I've forked your project and made some fixes for these issues. If you want to check, https://github.com/aykutozat/easy-thumbnails.

    Basically, I changed your get_modtime methods for remote storages, it solved the query problem. However, checking the path and modified time of the image was still consuming much time. So I cache the modified time of thumbnails and source images.

    Apart from all of these, there is still a problem which is saving the thumbnails into remote storage which consumes much time as well. I'm thinking of using celery for this issue. I will use user's local storage(media folder) for "temporary thumbnails" at first creation(or even maybe base64 format of the image can be used not sure) and pass the "real creation" to celery and after it creates the thumbnail, it will also delete the created "temporary thumbnail" from user's local storage.

    I didn't want to open a pull request because I'm using cache which you may not like and I also want to add celery thing. However I wanted to take your opinions on my suggestions.

    Thanks.

    opened by aykut 21
  • S3BotoStorage performance issues

    S3BotoStorage performance issues

    I am using easy-thumbnails 1.1 with THUMBNAIL_DEFAULT_STORAGE = 'storages.backends.s3boto.S3BotoStorage'

    I have noticed that the time consumed by the get_thumbnailer is 4 time slower then using a local storage.

    In my API I have to return about 20 thumbnails, and I build the with the following code:

    try:
        avatar = request.build_absolute_uri(
            get_thumbnailer(friendship.friend.get_profile().avatar)['iPhoneAvatar'].url
        )
    except InvalidImageFormatError:
        self.logger.error("Error loading avatar for user %s" % friendship.friend.username)
        avatar = None
    

    Am I doing anything wrong? Is there any way to optimize the performances?

    opened by facconi 17
  • InvalidImageFormatError: The source file does not appear to be an image

    InvalidImageFormatError: The source file does not appear to be an image

    I'm getting the following error when trying to output a thumbnail in my Django template:

    InvalidImageFormatError at /search/
    The source file does not appear to be an image
    

    This is happening with both JPEGs and PNGs. Here's how my template looks:

    {% load thumbnail %}
    {% thumbnail profile.profile_photo 220x160 %}
    

    I have THUMBNAIL_DEBUG = True in my settings file and easy_thumbnails added to my installed apps.

    In my requirements.txt:

    Pillow==2.2.1
    easy-thumbnails==1.4
    

    And before people say I don't have png/jpeg support with Pillow/PIL here's a pip install -r requirements.txt:

    Installing collected packages: PIL
      Running setup.py develop for PIL
    
        --------------------------------------------------------------------
        PIL 1.2a0 SETUP SUMMARY
        --------------------------------------------------------------------
        version       1.2a0
        platform      Python 2.7.3 (default, Apr 10 2013, 06:20:15)
                      [GCC 4.6.3] on linux2
        --------------------------------------------------------------------
        --- TKINTER support available
        --- JPEG support available
        *** WEBP support not available
        --- ZLIB (PNG/ZIP) support available
        --- FREETYPE2 support available
        *** LITTLECMS support not available
        --------------------------------------------------------------------
        To add a missing option, make sure you have the required
        library, and set the corresponding ROOT variable in the
        setup.py script.
    
        To check the build, run the selftest.py script.
        Creating /home/robbie/git/myproject/venv/lib/python2.7/site-packages/PIL.egg-link (link to .)
        PIL 1.2a0 is already the active version in easy-install.pth
    

    So JPEG and PNG support are available. I'm also able to access the uploaded image from the browser by pointing to it's MEDIA_URL path. What gives?

    edit: I also get the same error when trying to load a 3rd party image such as

    {% thumbnail "http://www.gravatar.com/avatar/00000000000000000000000000000000?d=mm" 160x160 %}
    
    opened by robpodosek 16
  • Add an Image to ThumbnailerImageField using the resize_source={

    Add an Image to ThumbnailerImageField using the resize_source={"size": (150, 150)} argument.

    I have a Profile model that looks something like this :

    class Profile(Model):
        user = models.OneToOneField(User)
        avatar = ThumbnailerImageField(verbose_name=_("avatar"),
        upload_to="avatar",
        resize_source={"size": (150, 150)},   # <= This is the line that cause the problem
        blank=True, null=True)
       .....
    

    Then somewhere in my I try to fetch an image from THE internet (aka Facebook :-) ) and stick it on the models. This blows in a mysterious way as soon as I add the resize_source argument.

    The code look like something like this :

    In [1]: from StringIO import StringIO
    In [2]: from backstage.apps.accounts.models import Profile 
    In [3]: from django.core.files.base import ContentFile
    In [4]: from urllib2 import urlopen
    In [5]: avatar_url = 'http://graph.facebook.com/100001437656687/picture?type=large'
    In [6]: buffer = StringIO(urlopen(avatar_url, timeout=5).read())
    In [7]: profile=Profile.objects.all()[1]
    In [9]: profile.avatar.save('thefile.jpg', ContentFile(buffer.read()))
    

    And the traceback is :

    ---------------------------------------------------------------------------
    InvalidImageFormatError                   Traceback (most recent call last)
    /srv/webapps/project/local/lib/python2.7/site-packages/django/core/management/commands/shell.pyc in <module>()
    ----> 1 profile.avatar.save('thefile.jpg', ContentFile(buffer.read()))
    
    /srv/webapps/project/local/lib/python2.7/site-packages/easy_thumbnails/files.pyc in save(self, name, content, *args, **kwargs)
        519                 options['quality'] = self.thumbnail_quality
        520             import ipdb; ipdb.set_trace()
    --> 521             content = Thumbnailer(content).generate_thumbnail(options)
        522         super(ThumbnailerImageFieldFile, self).save(name, content, *args,
        523                                                     **kwargs)
    
    /srv/webapps/project/local/lib/python2.7/site-packages/easy_thumbnails/files.pyc in generate_thumbnail(self, thumbnail_options)
        258         if image is None:
        259             raise exceptions.InvalidImageFormatError(
    --> 260                 "The source file does not appear to be an image")
        261 
        262         thumbnail_image = engine.process_image(image, thumbnail_options,
    
    InvalidImageFormatError: The source file does not appear to be an image
    
    

    This is akward because the file that I am grabbing seems to be a perfectly valid Image. Removing the resize_source argument make the issue not visible. And replacing the ThumbnailerImageField by a django's ImageField also works fine.

    Am I doing something wrong in my save or is this a limitation/bug in easy-thumbnails. Thanks

    opened by yml 16
  • Postprocessor

    Postprocessor

    This PR fixes some issues from #257.

    Additionally, I added an optional postprocessor for image optimization. It can be activated by adding:

    INSTALLED_APPS = (
        ...
        'easy_thumbnails.optimize'
        ...
    )
    

    and using the setting:

    THUMBNAIL_OPTIMIZE_COMMAND = {
        'png': '/opt/local/bin/optipng {filename}',
        'gif': '/opt/local/bin/optipng {filename}',
        'jpeg': '/opt/local/bin/jpegoptim {filename}',
    }
    

    Sure, this could be installed as a 3rd party app, but consider that

    • developers are strongly encouraged to optimize images after upload, so the audience is almost the entire user base of easy_thumbnail.
    • this app contains less than 50 lines of code. Installing another micro-app from PyPI certainly is more embarrassing than getting some additional code, which in a few cases, might not be used.

    Of course, if you don't like this embedded app approach, I'll move the optimizer into a micro-app. Docs and unittests will come.

    BTW: I did not like the approach of image_diet, therefore I reused the idea from my previous patch. This one honors the storage object.

    opened by jrief 15
  • Support for animated GIF images

    Support for animated GIF images

    Hi Chris,

    After a long long night I finally managed to add support for animated GIF images to easy-thumbnails.

    It uses images2gif.py to extract all frames as PIL images. These frame images get processed by the thumbnail processors like every other still image. After they have been processed they get merged into one animated GIF (see Thumbnailer.generate_thumbnail).

    Some animated GIFs react very badly to "resample=Image.ANTIALIAS" when resized. Therefore, I had to add a new "resample" kwarg to the default scale_and_crop processor (see easy_thumbnails/processors.py:158). This kwarg can be used to override the default behavior of Image.ANTIALIAS to Image.NEAREST. The NEAREST resample mode gets set explicitly when a GIF is getting processed (see easy_thumbnails/files.py:301). The downside is that resized GIFs do not have the best quality but the compatibility is improved. Maybe this is something that the user can specify in the Django settings (quality or compatibility)?

    I thought this feature would be nice to have in the official version of easy-thumbnails. So feel free to add it! If you have any questions, do not hesitate to contact me!

    Cheers Pascal

    opened by anvio 15
  • Overriding filename generation

    Overriding filename generation

    Hi, Is there a (quite) simple way to override thumbnail file names ? I prefer using a hash as a suffix instead of a string containing every thumbnail option.

    I've taken a look at get_thumbnail_name but don't really know what to do from there.

    opened by artscoop 12
  • Invalid Images

    Invalid Images

    easy_thumbnails used to raise an IOError when an invalid image was uploaded and save()'d. This behaviour changed around alpha 4 to this error

    File "/home/pascal/yoosello/lib/python2.6/site-packages/easy_thumbnails/engine.py", line 30, in process_image
        image = processor(image, **processor_options)
    File "/home/pascal/yoosello/lib/python2.6/site-packages/easy_thumbnails/processors.py", line 52, in colorspace
        if im.mode in ('L', 'RGB'):
    AttributeError: 'NoneType' object has no attribute 'mode'
    

    I made a patch that simply checks for the image object to be not None and raise a TypeError otherwise.

    opened by passy 12
  • Migration 0010 fails, when using MySQL

    Migration 0010 fails, when using MySQL

    Hey,

    the south migration with mysql fails with the current alpha-12 version.

    easy_thumbnails:0010_rename_storage ! Error found during real run of migration! Aborting.

    [...] File "/home/daniel/.virtualenvs/myenv/lib/python2.6/site-packages/easy_thumbnails/migrations/0010_rename_storage.py", line 13, in forwards db.drop_foreign_key('easy_thumbnails_source', 'storage_new_id') [...] raise ValueError("Cannot find a FOREIGN KEY constraint on table %s, column %s" % (table_name, column)) ValueError: Cannot find a FOREIGN KEY constraint on table easy_thumbnails_source, column storage_new_id

    opened by dbanck 12
  • Database Cache of thumbnails always fails (thumbnail_exists)

    Database Cache of thumbnails always fails (thumbnail_exists)

    The for loop in get_existing_thumbnail calls repeatedly thumbnail_exists (terrible performance, see https://github.com/SmileyChris/easy-thumbnails/blob/master/easy_thumbnails/files.py#L381). The first of names does not exist but the second. Database and filesystem cache always fails, both are polled on every request. The JPG thumbnail can never be created as the PNG one already exists, nevertheless the check is done every time.

    2014-01-14 00:32:07.622 get_existing_thumbnail NAMES [u'thumbnails/public/[email protected]__75x47_q85.jpg', u'thumbnails/public/[email protected]__75x47_q85.png'

    opened by katzlbt 10
  • Parameter 'quality' is not passed to pillow if WEBP format is used

    Parameter 'quality' is not passed to pillow if WEBP format is used

    After commit https://github.com/SmileyChris/easy-thumbnails/commit/7b9719e379916b19945623b8d3299a279e38c395, parameter 'quality' is not passed to pillow for any format except of 'JPEG'.

    opened by mireq 3
  • Django 4.1 template tag 'thumbnail' conflict with sorl-thumbnails

    Django 4.1 template tag 'thumbnail' conflict with sorl-thumbnails

    Django 4.1 added a system check to find duplicate template tags at startup. If easy-thumbnails and sorl-thumbnails are installed in the same project, it will detect the possible clash and will exit with an error. This happens even if the tags are not used in any template.

    SystemCheckError: System check identified some issues:
    
    ERRORS:
    ?: (templates.E003) 'thumbnail' is used for multiple template tag modules: 'easy_thumbnails.templatetags.thumbnail', 'sorl.thumbnail.templatetags.thumbnail'
    

    I've added a minimal reproduction here: https://github.com/MarcoGlauser/template_tag_conflict Simply run a manage.py command like makemigrations

    opened by MarcoGlauser 0
  • Imoprt error

    Imoprt error

    Facing import error while running migrate command for filer in Django application

    error location "easy_thumbnails/engine.py"

    Possible cause of errors was:

    --file is importing modules using keywords that are not supported or depreciated now. --Using different versions of libraries that are depreciated.

    I want to contribute to fix it

    Screenshot (178)

    opened by developervick 0
  • ContentFile without a name breaks easy_thumbnails

    ContentFile without a name breaks easy_thumbnails

    Hi there,

    we had the issue that easy_thumbnail raised a 500 error (expected str, bytes or os.PathLike object, not NoneType) because our custom adapter to a cloud storage just returned a ContentFile without a name. We corrected this for ourselves by setting the name to ContentFile. Nevertheless it might be of interest to check if a name is set in eady_thumbnails at the following line of code:

    https://github.com/SmileyChris/easy-thumbnails/blob/92060b9fd7b617cab1ac88d149dc5021d43b35c3/easy_thumbnails/files.py#L120

    Regards

    opened by SachaMPS 0
  • Template fails to render due to ZeroDivisionError when input is corrupted

    Template fails to render due to ZeroDivisionError when input is corrupted

    I accidentally ingested some bad images which are invalid data. Instead of failing silently as per normal, I end up with an uncaught exception when I try to render my page due to a ZeroDivisionError. This is very disruptive, and seems to go against the stated goal of the package to fail silently. Could I request error handling when source_x or source_y is zero?

      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/django/template/base.py", line 1038, in render
        output = self.filter_expression.resolve(context)
      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/django/template/base.py", line 728, in resolve
        new_obj = func(obj, *arg_vals)
      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/easy_thumbnails/templatetags/thumbnail.py", line 301, in thumbnail_url
        raise e
      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/easy_thumbnails/templatetags/thumbnail.py", line 298, in thumbnail_url
        thumb = get_thumbnailer(source)[alias]
      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/easy_thumbnails/files.py", line 344, in __getitem__
        return self.get_thumbnail(options, silent_template_exception=True)
      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/easy_thumbnails/files.py", line 508, in get_thumbnail
        thumbnail = self.generate_thumbnail(
      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/easy_thumbnails/files.py", line 389, in generate_thumbnail
        thumbnail_image = engine.process_image(image, thumbnail_options,
      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/easy_thumbnails/engine.py", line 35, in process_image
        image = processor(image, **processor_options)
      File "/Users/bixbyr/anaconda3/envs/Shelterware_v2/lib/python3.8/site-packages/easy_thumbnails/processors.py", line 179, in scale_and_crop
        scale = min(target_x / source_x, target_y / source_y)
    ZeroDivisionError: float division by zero
    
    opened by bixbyr 0
django-quill-editor makes Quill.js easy to use on Django Forms and admin sites

django-quill-editor django-quill-editor makes Quill.js easy to use on Django Forms and admin sites No configuration required for static files! The ent

lhy 139 Dec 5, 2022
Django-Audiofield is a simple app that allows Audio files upload, management and conversion to different audio format (mp3, wav & ogg), which also makes it easy to play audio files into your Django application.

Django-Audiofield Description: Django Audio Management Tools Maintainer: Areski Contributors: list of contributors Django-Audiofield is a simple app t

Areski Belaid 167 Nov 10, 2022
Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project

Django URL Shortener Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project Install this package to your Dja

Rishav Sinha 4 Nov 18, 2021
Full-text multi-table search application for Django. Easy to install and use, with good performance.

django-watson django-watson is a fast multi-model full-text search plugin for Django. It is easy to install and use, and provides high quality search

Dave Hall 1.1k Dec 22, 2022
🏭 An easy-to-use implementation of Creation Methods for Django, backed by Faker.

Django-fakery An easy-to-use implementation of Creation Methods (aka Object Factory) for Django, backed by Faker. django_fakery will try to guess the

Flavio Curella 93 Oct 12, 2022
Meta package to combine turbo-django and stimulus-django

Hotwire + Django This repository aims to help you integrate Hotwire with Django ?? Inspiration might be taken from @hotwired/hotwire-rails. We are sti

Hotwire for Django 31 Aug 9, 2022
django-reversion is an extension to the Django web framework that provides version control for model instances.

django-reversion django-reversion is an extension to the Django web framework that provides version control for model instances. Requirements Python 3

Dave Hall 2.8k Jan 2, 2023
Django-environ allows you to utilize 12factor inspired environment variables to configure your Django application.

Django-environ django-environ allows you to use Twelve-factor methodology to configure your Django application with environment variables. import envi

Daniele Faraglia 2.7k Jan 7, 2023
Rosetta is a Django application that eases the translation process of your Django projects

Rosetta Rosetta is a Django application that facilitates the translation process of your Django projects. Because it doesn't export any models, Rosett

Marco Bonetti 909 Dec 26, 2022
Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly.

Cookiecutter Django Powered by Cookiecutter, Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly. Documentati

Daniel Feldroy 10k Dec 31, 2022
Django project starter on steroids: quickly create a Django app AND generate source code for data models + REST/GraphQL APIs (the generated code is auto-linted and has 100% test coverage).

Create Django App ?? We're a Django project starter on steroids! One-line command to create a Django app with all the dependencies auto-installed AND

imagine.ai 68 Oct 19, 2022
A Django chatbot that is capable of doing math and searching Chinese poet online. Developed with django, channels, celery and redis.

Django Channels Websocket Chatbot A Django chatbot that is capable of doing math and searching Chinese poet online. Developed with django, channels, c

Yunbo Shi 8 Oct 28, 2022
A handy tool for generating Django-based backend projects without coding. On the other hand, it is a code generator of the Django framework.

Django Sage Painless The django-sage-painless is a valuable package based on Django Web Framework & Django Rest Framework for high-level and rapid web

sageteam 51 Sep 15, 2022
A beginner django project and also my first Django project which involves shortening of a longer URL into a short one using a unique id.

Django-URL-Shortener A beginner django project and also my first Django project which involves shortening of a longer URL into a short one using a uni

Rohini Rao 3 Aug 8, 2021
Dockerizing Django with Postgres, Gunicorn, Nginx and Certbot. A fully Django starter project.

Dockerizing Django with Postgres, Gunicorn, Nginx and Certbot ?? Features A Django stater project with fully basic requirements for a production-ready

null 8 Jun 27, 2022
pytest-django allows you to test your Django project/applications with the pytest testing tool.

pytest-django allows you to test your Django project/applications with the pytest testing tool.

pytest-dev 1.1k Dec 14, 2022
APIs for a Chat app. Written with Django Rest framework and Django channels.

ChatAPI APIs for a Chat app. Written with Django Rest framework and Django channels. The documentation for the http end points can be found here This

Victor Aderibigbe 18 Sep 9, 2022
django-dashing is a customisable, modular dashboard application framework for Django to visualize interesting data about your project. Inspired in the dashboard framework Dashing

django-dashing django-dashing is a customisable, modular dashboard application framework for Django to visualize interesting data about your project.

talPor Solutions 703 Dec 22, 2022
Django-MySQL extends Django's built-in MySQL and MariaDB support their specific features not available on other databases.

Django-MySQL The dolphin-pony - proof that cute + cute = double cute. Django-MySQL extends Django's built-in MySQL and MariaDB support their specific

Adam Johnson 504 Jan 4, 2023