Code Monkey home page Code Monkey logo

django-imagefit's Introduction

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

  • only 1 image file exists on the server, therefore it's always easy to replace and adapt the image per template or zone.
  • no model to adapt for large image and thumbnail that may vary when redesigning the website.
  • perfect match with mediaqueries to adapt on mobile, tablets and multi-size screens.
  • better quality than html/css resizing and no large file download, great for lower bandwidth.

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

  • For creating specific model fields that resize image when model saves, see django-imagekit
  • If you wish to avoid very large image on the server, consider resizing your original image before uploading it

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="{{ "/static/image.png"|resize:'thumbnail' }}" />
<img src="{{ "/static/image.png"|resize:'320x240' }}" />
<img src="{{ "/static/image.png"|resize:'320x240,C' }}" />
<img src="{{ "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

  • Refactor views.resize
  • Make resize quality/speed configurable
  • More examples for doc
  • enable URL images in addition to system files

Imagefit Developers

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

django-imagefit's People

Contributors

aropan avatar arski avatar bencipher avatar davidfischer-ch avatar dekan avatar eugenepyvovarov avatar movermeyer avatar nebuchadrezzar avatar reallinfo avatar rezemika avatar saeschdivara avatar shourav9884 avatar vinyll avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

django-imagefit's Issues

Encoding error when pip-installing Python 3.5.1

When pip installing with python 3, it generates the following error:

Collecting django-imagefit
  Using cached django-imagefit-0.4.tar.gz
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-gnsjpefu/django-imagefit/setup.py", line 10, in <module>
        long_description=open('README.md').read(),
      File "/.../lib/python3.5/encodings/ascii.py", line 26, in decode
        return codecs.ascii_decode(input, self.errors)[0]
    UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 1518: ordinal not in range(128)

----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-gnsjpefu/django-imagefit/

AttributeError with Django 1.10+

The middleware management changed after Django 1.10, the MIDDLEWARE_CLASSES variable became MIDDLEWARE. An AttributeError is raised when trying to run a Django project using the MIDDLEWARE variable.

File ".../venv/lib/python3.5/site-packages/imagefit/conf.py", line 38, in ImagefitConf
    if not 'django.middleware.http.ConditionalGetMiddleware' in settings.MIDDLEWARE_CLASSES:
File ".../venv/lib/python3.5/site-packages/django/conf/__init__.py", line 57, in __getattr__
    val = getattr(self._wrapped, name)
AttributeError: 'Settings' object has no attribute 'MIDDLEWARE_CLASSES'

Image not rendering

Tried using this app to resize one image in my static files. The image didn't render.

Configurations:
Django: 2.0.3
Python 3.6.4

in settings.py
IMAGEFIT_ROOT = "myproject"
IMAGEFIT_CACHE_ENABLED = False

The html page where I tried using Imagfit
{% load static %}
{% load imagefit %}
{% with 'image/person_pic/'|add:person.pic as person_image %}
<img src="{% static person_image|resize:'thumbnail' %}">

When I checked, the image source comes out to:
/static/%255Eimagefit/resize/thumbnail/image/person_pic/{insert person_id}.png

when I removed the "resize:'thumbnail', the image renders properly.

Update test from Travis CI

A few things about the tests:

  • travis-ci.org as moved to .com with a few changes
  • test are not passing anymore while changes do not reflect any breaking change: b8389b7...master

Eventually consider moving to Circle CI or Github Actions?

PRs are welcome 🙏

Internal Server Error

Internal Server Error: /imagefit/resize/320x240/media/banners/Paytm.JPG
Traceback (most recent call last):
File "/home/narsing/.local/lib/python3.5/site-packages/PIL/ImageFile.py", line 466, in _save
fh = fp.fileno()
io.UnsupportedOperation: fileno

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/narsing/Desktop/couponsrack/src/django-imagefit/imagefit/views.py", line 66, in resize
image.save()
File "/home/narsing/Desktop/couponsrack/src/django-imagefit/imagefit/models.py", line 85, in save
self.pil.save(image_str, ext_to_format(self.cached_name))
File "/home/narsing/.local/lib/python3.5/site-packages/PIL/Image.py", line 1698, in save
save_handler(self, fp, filename)
File "/home/narsing/.local/lib/python3.5/site-packages/PIL/JpegImagePlugin.py", line 725, in _save
ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize)
File "/home/narsing/.local/lib/python3.5/site-packages/PIL/ImageFile.py", line 481, in _save
fp.write(d)
TypeError: string argument expected, got 'bytes'[14/Nov/2016 17:06:21] "GET /media/stores/1mg.jpg HTTP/1.1" 200 16329

EXIF rotation information lost

Hi,

it seems JPEG images with EXIF rotation info are messed up after resizing. This can be easily fixed by rotating the image after resizing based on the information found in EXIF tags:

try:
    from exifread import process_file # This is for newer Ubuntus
except ImportError:
    from EXIF import process_file # This is for Ubuntu 14.04

tags = process_file(open("path/to/filename.jpg"))
orientation = tags.get("Image Orientation")

if orientation:
    j, = orientation.values
    if j == 6:
        print "rotated 270 degrees"
    elif j == 8:
        print "rotated 90 degrees"
    elif j == 3:
        print "rotated 180 degrees"

Also to speed up resizing/rotation you could take a look at epeg at https://github.com/mattes/epeg

TypeError: was_modified_since() takes from 0 to 2 positional arguments but 3 were given

[02/Aug/2023 08:19:34] "GET /imagefit/media_resize/600x600/products_images/0515-2.png HTTP/1.1" 500 95555
Internal Server Error: /imagefit/media_resize/600x600/products_images/0500-2.png
Traceback (most recent call last):
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/imagefit/views.py", line 45, in resize
if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
TypeError: was_modified_since() takes from 0 to 2 positional arguments but 3 were given

Warning logs

I really don't know why this warning is being logged, can you please explain what the issue is and maybe we can write a test for it?

Here are my usages:
article.feature_img.url|resize:'320x240,C'
article.feature_img.url |resize:'800x420,C'
post.feature_img.url|resize:'thumbnail'

Also, I discover that without the Crop flag, the size is not enforced but when i add the Crop tag, the image fades.

imagefit\views.py", line 61, in resize
    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured:  "385770" is neither a "WIDTHxHEIGHT" format nor a key in IMAGEFIT_PRESETS.
Internal Server Error: /imagefit/resize/385770//media/feature_default.jpg

RuntimeError: Settings already configured.

Watching for file changes with StatReloader
Exception in thread django-main-thread:
Traceback (most recent call last):
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/threading.py", line 973, in _bootstrap_inner
self.run()
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/utils/autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/core/management/commands/runserver.py", line 125, in inner_run
autoreload.raise_last_exception()
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/utils/autoreload.py", line 87, in raise_last_exception
raise _exception[1]
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/core/management/init.py", line 394, in execute
autoreload.check_errors(django.setup)()
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/utils/autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/init.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/apps/registry.py", line 116, in populate
app_config.import_models()
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/apps/config.py", line 269, in import_models
self.models_module = import_module(models_module_name)
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/importlib/init.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "", line 1030, in _gcd_import
File "", line 1007, in _find_and_load
File "", line 986, in _find_and_load_unlocked
File "", line 680, in _load_unlocked
File "", line 850, in exec_module
File "", line 228, in _call_with_frames_removed
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/imagefit/models.py", line 2, in
from imagefit.conf import ext_to_format, settings
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/imagefit/conf.py", line 6, in
settings.configure()
File "/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/django/conf/init.py", line 139, in configure
raise RuntimeError("Settings already configured.")
RuntimeError: Settings already configured.
/Users/matteolucchesi/PycharmProjects/asa-backend/venv/lib/python3.9/site-packages/urllib3/init.py:34: NotOpenSSLWarning: urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 2.8.3'. See: urllib3/urllib3#3020
warnings.warn(

Another README/code inconsistency

It is stated in the README that presets can be overriden by adding a custom IMAGEFIT_PRESETS dictionary to one's settings.py. However, the code is looking for IMAGEFIT_SIZES in conf.py - IMAGEFIT_PRESETS = getattr(settings, 'IMAGEFIT_SIZES', {

Doesn't support S3 Image backend right?

Hi, I'm trying to use your package with django-s3direct and it is raising a file error.

Internal Server Error: /imagefit/resize/150x150,C/https://s3.amazonaws.com/wRCTXuPgbEOtbTzhRI8Ht.png
Traceback (most recent call last):
File "/home/manu/.virtualenvs/project/lib/python3.5/site-packages/django/core/handlers/exception. py", line 35, in inner
response = get_response(request)
File "/home/manu/.virtualenvs/project/lib/python3.5/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/manu/.virtualenvs/project/lib/python3.5/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/manu/.virtualenvs/project/lib/python3.5/site-packages/imagefit/views.py", line 40, in resize
image = Image(path=os.path.join(prefix, url))
File "/home/manu/.virtualenvs/project/lib/python3.5/site-packages/imagefit/models.py", line 21, in init
self.pil = PilImage.open(path)
File "/home/manu/.virtualenvs/project/lib/python3.5/site-packages/PIL/Image.py", line 2548, in open
fp = builtins.open(filename, "rb")
FileNotFoundError: [Errno 2] No such file or directory: 'https://s3.amazonaws.com/ wRCTXuPgbEOtbTzhRI8Ht.png'

Not working on Nginx server

Every time I open website, it gives me an error in console says:

(index):1 503 (Service Temporarily Unavailable)

The image is still there but it didn't open

Cache not enabled by default

Your README seems to claim it is, but the default setting in the code is IMAGEFIT_CACHE_ENABLED = getattr(settings, 'IMAGEFIT_CACHE_ENABLED', False) - is that a bug or maybe a slight inaccuracy in the readme?

Cheers

Original Cache Settings Overrided

The code in conf.py is overriding original cache settings of Django, causing the 'default' value of cache lost.
settings.CACHES = ...

pip install failing

Good day, I have tried to install using

pip install django-imagefit

Getting the following error:

pip install django-imagefit
Collecting django-imagefit
Using cached django-imagefit-0.6.1.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "/tmp/pip-build-gov7zs6k/django-imagefit/setup.py", line 10, in
long_description=open('README.md').read(),
File "/home/dbworksc/virtualenv/zimphoto__html/3.5/lib64/python3.5/encodings/ascii.py", line 26, in decode
return codecs.ascii_decode(input, self.errors)[0]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 418: ordinal not in range(128)

----------------------------------------

Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-gov7zs6k/django-imagefit/

Latest version not compatible with Django 4

The README states that the package is compatible with Django 4, yet the latest release of the package use django.conf.urls.url() which was deprecated in Django 3.0, and is removed in Django 4.0+. Is the project still maintained? No new releases to pip since 2018.

ImportError: cannot import name 'url' from 'django.conf.urls' (/usr/local/lib/python3.9/site-packages/django/conf/urls/__init__.py)

Need to use io.BytesIO instead of io.StringIO in models.py

Currently using Python 3.2, Pillow 2.4.0, Django 1.6, and bleeding edge version of django-imagefit.

Calling media_resize in template on image produces following error:

Exception Type: AttributeError
Exception Value: type object '_io.StringIO' has no attribute 'StringIO'
Exception Location: /home/matthew/Environments/django1.6_dev/src/django-imagefit/imagefit/models.py in render, line 75

Upon inspection, io.StringIO does indeed not have any attribute StringIO in Python 3.x. I renamed this to StringIO() as indicated in the docs and received the following error:

Exception Type: TypeError
Exception Value: string argument expected, got 'bytes'
Exception Location: /home/matthew/Environments/django1.6_dev/lib/python3.2/site-packages/PIL/PngImagePlugin.py in _save, line 546

Switching StringIO out for BytesIO in def render() in models.py fixed the problem and rendered the image through the resizing filter in the template.

There are no tests for me to use to verify this is the correct solution. Do you think you could test this fix for use in Python 3.2 or greater?

New logo for Imagefit

Hello I wanted to contribute to ImageFit. I designed a logo for it. If you like it, I'll send you files and pr.

Also, If you have a logo idea you want, I can design it.

imagefit

Migrate to Django 3

Django 3 has changed quite a few things in the way reusable apps work.
This project could be readapted for Django 3 in that sense (AppConfig is an example).

Update for django 4.2

I'm using this library in one of my projects and would like to use it with django 4.2.

2 Things is noticed need to be updated:
In conf.py add this line:
if not settings.configured:
settings.configure()

In models.py change the line (54):
from ANTIALIAS to PilImage.LANCZOS)

I would be really happy if you could change that and push it to pypi as an upgrade.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.