vinyll / django-imagefit

Resize an image on render. Preserve your original file on your system.
BSD 3-Clause "New" or "Revised" License
84 stars 40 forks source link
crop django image-manipulation optimization pil resizing-images

django-imagefit

Django Image Fit - Resize an image on the fly

Build Status

Imagefit allows you to render an image in a template and specify its dimensions. It preserves the original image file.

It is compatible with various sources of images such as django-filebrowser's FileBrowseField, user uploaded images, static images, …

Works on Python 3.x; Django 4. Compatible with Django 4.2. For previous versions of Django please refer to version 0.7.0 and previous versions of Pil.

Benefits

Quick tour

Example 1: render /static/myimage.png image at a maximum size of 200 x 150 px:

{{ "/static/myimage.png"|resize:"200x150" }}

Example 2: render model's news.image as a thumbnail:

{{ news.image|resize:"thumbnail" }}

Example 3: render /static/myimage.png image at a maximum cropped size of 150 x 150 px:

{{ "/static/myimage.png"|resize:"150x150,C" }}

Example 4: render https://example.com/test.png image at a maximum cropped size of 150 x 150 px:

{{ "https://example.com/test.png"|external_resize:"150x150,C" }}

What this is not

Installation

Download

Via pip latest version

pip install django-imagefit

or the bleeding edge version

pip install -e git+https://github.com/vinyll/django-imagefit.git#egg=django-imagefit

update INSTALLED_APPS

In settings.py, add imagefit in your INSTALLED_APPS

INSTALLED_APPS = (
    …,
    'imagefit',
)

And add the path relative to your project (see configuration below)

IMAGEFIT_ROOT = "public"

urls.py

Imagefit is a resize service, therefore include its urls.

Prefix it with whatever you want (here "imagefit" for example):

from django.urls import re_path

urlpatterns = urlpatterns('',
    …
    re_path(r'^imagefit/', include('imagefit.urls')),
)

Congratulations, you're all set!

Usage

your_template.html

{% load imagefit %}

<img src="https://github.com/vinyll/django-imagefit/raw/master/{{ "/static/image.png"|resize:'thumbnail' }}" />
<img src="https://github.com/vinyll/django-imagefit/raw/master/{{ "/static/image.png"|resize:'320x240' }}" />
<img src="https://github.com/vinyll/django-imagefit/raw/master/{{ "/static/image.png"|resize:'320x240,C' }}" />
<img src="https://github.com/vinyll/django-imagefit/raw/master/{{ "https://example.com/test.png"|external_resize:'320x240' }}" />

This will display your /static/image.png:

  1. in the thumbnail format (80 x 80 px)
  2. resized in a custom 320 x 240 pixels
  3. resized and cropped in a custom 320 x 240 pixels

the ,C modifier stands for Cropping

Configuration

Root path

You should most probably customize the path to the root folder of your images. The url your specify in your model will be concatenated to this IMAGEFIT_ROOT to find the appropriate image on your system.

The path will be relative to the project folder.

If starting with a "/", it will be an absolute path (quid about Windows).

IMAGEFIT_ROOT = "public"

So with this example the image url "/static/image.png" would be pointing to /PATH/TO/YOUR/PROJECT/public/static/image.png

Templatetags

resize(value, size)  # path is relative to you settings.IMAGE_ROOT
static_resize(value, size)  # path is relative to you settings.STATIC_ROOT
media_resize(value, size)  # path is relative to you settings.MEDIA_ROOT
external_resize(value, size) # path is an http/https url

Can be used in templates as so :

{{ "/static/logo.png"|resize:'320x240' }}
{{ "logo.png"|static_resize:'320x240' }}
{{ "user_avatar.png"|media_resize:'320x240' }}
{{ "https://example.com/test.png"|external_resize:'320x240' }}

Presets

Presets are configuration names that hold width and height (and maybe more later on). Imagefit is already shipped with 3 presets : thumbnail (80x80), medium (320x240) and original (no resizing).

You may override them or create new ones through settings.py

Custom presets examples :

IMAGEFIT_PRESETS = {
    'thumbnail': {'width': 64, 'height': 64, 'crop': True},
    'my_preset1': {'width': 300, 'height': 220},
    'my_preset2': {'width': 100},
}

Cache

Because resizing an image on the fly is a big process, django cache is enabled by default.

Therefore you are strongly invited to set your imagefit cache preferences to False for local development.

You can customize the default cache preferences by overriding default values described below via settings.py :

# enable/disable server cache
IMAGEFIT_CACHE_ENABLED = True
# set the cache name specific to imagefit with the cache dict
IMAGEFIT_CACHE_BACKEND_NAME = 'imagefit'
CACHES = {
    'imagefit': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': os.path.join(tempfile.gettempdir(), 'django_imagefit')
        }
    }

Note that CACHES default values will be merge with yours from settings.py

Formats

Imagefit uses PIL to resize and crop the images and this library requires to specify the format of the output file. Imagefit allows you to specify an output format depending of the output filename. Please note that the the output extension is left unchanged.

You can customize the default mapping by overriding default values described below via settings.py :

# Example extension -> format.
IMAGEFIT_EXT_TO_FORMAT = {'.jpg': 'jpeg', '.bmp': 'png'}
# Disallow the fall-back to a default format: Raise an exception in such case.
IMAGEFIT_EXT_TO_FORMAT_DEFAULT = None

Expires Header

Django Imagefit comes with Expires header to tell the browser whether it should request the resource from the server or use the cached version.
This has two core benefits. The browser will be using the cached version of the resource in the second load and page load will be much faster. Also, it will require fewer requests to the server.

As a page score parameter, static resources used in a web page should be containing an Expires information for better performance.

The default value of the expires header is set to 30 days from now. You can override this value via settings.py as:

IMAGEFIT_EXPIRE_HEADER = 3600  # for 1 hour

Troubleshooting

"decoder jpeg not available" on Mac OSX

You may have installed PIL through pip or easy_install that does not install libjpeg dependency.

If so :

  1. Uninstall pil via pip
  2. Install pip via homebrew: brew install pil
  3. Reinstall pil via pip: pip install pil

Todo

Imagefit Developers

Aka note to self: Deploy to pypi using make deploy.