Skip to main content

Image field for Django

Project description

https://github.com/matthiask/django-imagefield/workflows/Tests/badge.svg Documentation Status

Heavily based on django-versatileimagefield, but with a few important differences:

  • The amount of code is kept at a minimum. django-versatileimagefield has several times as much code (without tests).

  • Generating images on-demand inside rendering code is made hard on purpose. Instead, images are generated when models are saved and also by running the management command process_imagefields.

  • django-imagefield does not depend on a fast storage or a cache to be and stay fast, at least as long as the image width and height is saved in the database. An important part of this is never determining whether a processed image exists in the hot path at all (except if you force it).

  • django-imagefield fails early when image data is incomplete or not processable by Pillow for some reason.

  • django-imagefield allows adding width, height and PPOI (primary point of interest) fields to the model by adding auto_add_fields=True to the field instead of boringly and verbosingly adding them yourself.

Replacing existing uses of django-versatileimagefield requires the following steps:

  • from imagefield.fields import ImageField as VersatileImageField, PPOIField

  • Specify the image sizes by either providing ImageField(formats=...) or adding the IMAGEFIELD_FORMATS setting. The latter overrides the former if given.

  • Convert template code to access the new properties (e.g. instance.image.square instead of instance.image.crop.200x200 when using the IMAGEFIELD_FORMATS setting below).

  • When using django-imagefield with a PPOI, make sure that the PPOI field is also added to ModelAdmin or InlineModelAdmin fieldsets, otherwise you’ll just see the image, but no PPOI picker. Contrary to django-versatileimagefield the PPOI field is editable itself, which avoids apart from other complexities a pitfall with inline form change detection.

  • Add "imagefield" to INSTALLED_APPS.

If you used e.g. instance.image.crop.200x200 and instance.image.thumbnail.800x500 before, you should add the following setting:

IMAGEFIELD_FORMATS = {
    # image field path, lowercase
    'yourapp.yourmodel.image': {
        'square': ['default', ('crop', (200, 200))],
        'full': ['default', ('thumbnail', (800, 500))],

        # The 'full' spec is equivalent to the following format
        # specification in terms of image file produced (the
        # resulting file name is different though):
        # 'full': [
        #     'autorotate', 'process_jpeg', 'process_png',
        #     'process_gif', 'autorotate',
        #     ('thumbnail', (800, 500)),
        # ],
        # Note that the exact list of default processors may
        # change in the future.
    },
}

After running ./manage.py process_imagefields --all once you can now use use instance.image.square and instance.image.thumbnail in templates instead. Note that the properties on the image file do by design not check whether thumbs exist.

Image processors

django-imagefield uses an image processing pipeline modelled after Django’s middleware.

The following processors are available out of the box:

  • autorotate: Autorotates an image by reading the EXIF data.

  • process_jpeg: Converts non-RGB images to RGB, activates progressive encoding and sets quality to a higher value of 90.

  • process_png: Converts PNG images with palette to RGBA.

  • process_gif: Preserves transparency and palette data in resized images.

  • preserve_icc_profile: As the name says.

  • thumbnail: Resizes images to not exceed a bounding box.

  • crop: Crops an image to the given dimensions, also takes the PPOI (primary point of interest) information into account if provided.

  • default: The combination of autorotate, process_jpeg, process_gif, process_png and preserve_icc_profile. Additional default processors may be added in the future. It is recommended to use default instead of adding the processors one-by-one.

Processors can be specified either using their name alone, or if they take arguments, using a tuple where the first entry is the processors’ name and the rest are positional arguments.

You can easily register your own processors or even override built-in processors if you want to:

from imagefield.processing import register

# You could also write a class with a __call__ method, but I really
# like the simplicity of functions.

@register
def my_processor(get_image, ...):
    def processor(image, context):
        # read some information from the image...
        # or maybe modify it, but it's mostly recommended to modify
        # the image after calling get_image

        image = get_image(image, context)

        # modify the image, and return it...
        modified_image = ...
        # maybe modify the context...
        return modified_image
    return processor

The processor’s name is taken directly from the registered object.

An example processor which converts images to grayscale would look as follows:

from PIL import ImageOps
from imagefield.processing import register

@register
def grayscale(get_image):
    def processor(image, context):
        image = get_image(image, context)
        return ImageOps.grayscale(image)
    return processor

Now include "grayscale" in the processing spec for the image where you want to use it.

The processing context

The context is a namespace with the following attributes (feel free to add your own):

  • processors: The list of processors.

  • name: The name of the resulting image relative to its storages’ root.

  • extension: The extension of the source and target.

  • ppoi: The primary point of interest as a list of two floats between 0 and 1.

  • save_kwargs: A dictionary of keyword arguments to pass to PIL.Image.save.

The ppoi, extension, processors and name attributes cannot be modified when running processors anymore. Under some circumstances extension and name will not even be there.

If you want to modify the extension or file type, or create a different processing pipeline depending on facts not known when configuring settings you can use a callable instead of the list of processors. The callable will receive the fieldfile and the context instance and must at least set the context’s processors attribute to something sensible. Just as an example here’s an image field which always returns JPEG thumbnails:

from imagefield.processing import register

@register
def force_jpeg(get_image):
    def processor(image, context):
        image = get_image(image, context)
        context.save_kwargs["format"] = "JPEG"
        context.save_kwargs["quality"] = 90
        return image
    return processor

def jpeg_processor_spec(fieldfile, context):
    context.extension = ".jpg"
    context.processors = [
        "force_jpeg",
        "autorotate",
        ("thumbnail", (200, 200)),
    ]

class Model(...):
    image = ImageField(..., formats={"thumb": jpeg_processor_spec})

Of course you can also access the model instance through the field file by way of its fieldfile.instance attribute and use those informations to customize the pipeline.

Development

django-imagefield uses pre-commit to keep the code clean and formatted.

The easiest way to build the documentation and run the test suite is also by using tox:

tox -e docs  # Open docs/build/html/index.html
tox -l  # To show the available combinations of Python and Django

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_imagefield-0.17.0.tar.gz (15.6 kB view details)

Uploaded Source

Built Distribution

django_imagefield-0.17.0-py3-none-any.whl (19.3 kB view details)

Uploaded Python 3

File details

Details for the file django_imagefield-0.17.0.tar.gz.

File metadata

  • Download URL: django_imagefield-0.17.0.tar.gz
  • Upload date:
  • Size: 15.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.24.1

File hashes

Hashes for django_imagefield-0.17.0.tar.gz
Algorithm Hash digest
SHA256 27c4db1359b8ff0c98809d1cac1387b31fde1e80ce211a4be935c5216959714e
MD5 b6b1380b049a205f515ed6e96fe3f514
BLAKE2b-256 9cd5668e65be53581e0a26f5a8ed991039d85d7ac76bfe29ea0ac1a6a176c23f

See more details on using hashes here.

File details

Details for the file django_imagefield-0.17.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_imagefield-0.17.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e9bd84c0f9ce52b2046daa9e4441336e98c34dd8454f3111c56b62d1e826ec10
MD5 b895009a144d653270fa2037b3a5ee60
BLAKE2b-256 8cda0e4bc30a0c3f239fb41115c3b1293f66e705b9e0e26e8abfc145f5409aea

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page