mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-03-16 21:30:23 +00:00
481 lines
17 KiB
ReStructuredText
481 lines
17 KiB
ReStructuredText
|Build Status|_
|
|
|
|
.. |Build Status| image:: https://travis-ci.org/matthewwithanm/django-imagekit.svg?branch=develop
|
|
.. _Build Status: https://travis-ci.org/matthewwithanm/django-imagekit
|
|
|
|
ImageKit is a Django app for processing images. Need a thumbnail? A
|
|
black-and-white version of a user-uploaded image? ImageKit will make them for
|
|
you. If you need to programatically generate one image from another, you need
|
|
ImageKit.
|
|
|
|
ImageKit comes with a bunch of image processors for common tasks like resizing
|
|
and cropping, but you can also create your own. For an idea of what's possible,
|
|
check out the `Instakit`__ project.
|
|
|
|
**For the complete documentation on the latest stable version of ImageKit, see**
|
|
`ImageKit on RTD`_.
|
|
|
|
.. _`ImageKit on RTD`: http://django-imagekit.readthedocs.org
|
|
__ https://github.com/fish2000/instakit
|
|
|
|
|
|
Installation
|
|
============
|
|
|
|
1. Install `PIL`_ or `Pillow`_. (If you're using an ``ImageField`` in Django,
|
|
you should have already done this.)
|
|
2. ``pip install django-imagekit``
|
|
3. Add ``'imagekit'`` to your ``INSTALLED_APPS`` list in your project's settings.py
|
|
|
|
.. note:: If you've never seen Pillow before, it considers itself a
|
|
more-frequently updated "friendly" fork of PIL that's compatible with
|
|
setuptools. As such, it shares the same namespace as PIL does and is a
|
|
drop-in replacement.
|
|
|
|
.. _`PIL`: http://pypi.python.org/pypi/PIL
|
|
.. _`Pillow`: http://pypi.python.org/pypi/Pillow
|
|
|
|
|
|
Usage Overview
|
|
==============
|
|
|
|
.. _specs:
|
|
|
|
Specs
|
|
-----
|
|
|
|
You have one image and you want to do something to it to create another image.
|
|
But how do you tell ImageKit what to do? By defining an image spec.
|
|
|
|
An **image spec** is a type of **image generator** that generates a new image
|
|
from a source image.
|
|
|
|
|
|
Defining Specs In Models
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The easiest way to use define an image spec is by using an ImageSpecField on
|
|
your model class:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.db import models
|
|
from imagekit.models import ImageSpecField
|
|
from imagekit.processors import ResizeToFill
|
|
|
|
class Profile(models.Model):
|
|
avatar = models.ImageField(upload_to='avatars')
|
|
avatar_thumbnail = ImageSpecField(source='avatar',
|
|
processors=[ResizeToFill(100, 50)],
|
|
format='JPEG',
|
|
options={'quality': 60})
|
|
|
|
profile = Profile.objects.all()[0]
|
|
print(profile.avatar_thumbnail.url) # > /media/CACHE/images/982d5af84cddddfd0fbf70892b4431e4.jpg
|
|
print(profile.avatar_thumbnail.width) # > 100
|
|
|
|
As you can probably tell, ImageSpecFields work a lot like Django's
|
|
ImageFields. The difference is that they're automatically generated by
|
|
ImageKit based on the instructions you give. In the example above, the avatar
|
|
thumbnail is a resized version of the avatar image, saved as a JPEG with a
|
|
quality of 60.
|
|
|
|
Sometimes, however, you don't need to keep the original image (the avatar in
|
|
the above example); when the user uploads an image, you just want to process it
|
|
and save the result. In those cases, you can use the ``ProcessedImageField``
|
|
class:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.db import models
|
|
from imagekit.models import ProcessedImageField
|
|
from imagekit.processors import ResizeToFill
|
|
|
|
class Profile(models.Model):
|
|
avatar_thumbnail = ProcessedImageField(upload_to='avatars',
|
|
processors=[ResizeToFill(100, 50)],
|
|
format='JPEG',
|
|
options={'quality': 60})
|
|
|
|
profile = Profile.objects.all()[0]
|
|
print(profile.avatar_thumbnail.url) # > /media/avatars/MY-avatar.jpg
|
|
print(profile.avatar_thumbnail.width) # > 100
|
|
|
|
This is pretty similar to our previous example. We don't need to specify a
|
|
"source" any more since we're not processing another image field, but we do need
|
|
to pass an "upload_to" argument. This behaves exactly as it does for Django
|
|
ImageFields.
|
|
|
|
.. note::
|
|
|
|
You might be wondering why we didn't need an "upload_to" argument for our
|
|
ImageSpecField. The reason is that ProcessedImageFields really are just like
|
|
ImageFields—they save the file path in the database and you need to run
|
|
syncdb (or create a migration) when you add one to your model.
|
|
|
|
ImageSpecFields, on the other hand, are virtual—they add no fields to your
|
|
database and don't require a database. This is handy for a lot of reasons,
|
|
but it means that the path to the image file needs to be programmatically
|
|
constructed based on the source image and the spec.
|
|
|
|
|
|
Defining Specs Outside of Models
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Defining specs as models fields is one very convenient way to process images,
|
|
but it isn't the only way. Sometimes you can't (or don't want to) add fields to
|
|
your models, and that's okay. You can define image spec classes and use them
|
|
directly. This can be especially useful for doing image processing in views—
|
|
particularly when the processing being done depends on user input.
|
|
|
|
.. code-block:: python
|
|
|
|
from imagekit import ImageSpec
|
|
from imagekit.processors import ResizeToFill
|
|
|
|
class Thumbnail(ImageSpec):
|
|
processors = [ResizeToFill(100, 50)]
|
|
format = 'JPEG'
|
|
options = {'quality': 60}
|
|
|
|
It's probably not surprising that this class is capable of processing an image
|
|
in the exact same way as our ImageSpecField above. However, unlike with the
|
|
image spec model field, this class doesn't define what source the spec is acting
|
|
on, or what should be done with the result; that's up to you:
|
|
|
|
.. code-block:: python
|
|
|
|
source_file = open('/path/to/myimage.jpg', 'rb')
|
|
image_generator = Thumbnail(source=source_file)
|
|
result = image_generator.generate()
|
|
|
|
.. note::
|
|
|
|
You don't have to use ``open``! You can use whatever File-like object you
|
|
want—including a model's ``ImageField``.
|
|
|
|
The result of calling ``generate()`` on an image spec is a file-like object
|
|
containing our resized image, with which you can do whatever you want. For
|
|
example, if you wanted to save it to disk:
|
|
|
|
.. code-block:: python
|
|
|
|
dest = open('/path/to/dest.jpg', 'wb')
|
|
dest.write(result.read())
|
|
dest.close()
|
|
|
|
|
|
Using Specs In Templates
|
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
If you have a model with an ImageSpecField or ProcessedImageField, you can
|
|
easily use those processed image just as you would a normal image field:
|
|
|
|
.. code-block:: html
|
|
|
|
<img src="{{ profile.avatar_thumbnail.url }}" />
|
|
|
|
(This is assuming you have a view that's setting a context variable named
|
|
"profile" to an instance of our Profile model.)
|
|
|
|
But you can also generate processed image files directly in your template—from
|
|
any image—without adding anything to your model. In order to do this, you'll
|
|
first have to define an image generator class (remember, specs are a type of
|
|
generator) in your app somewhere, just as we did in the last section. You'll
|
|
also need a way of referring to the generator in your template, so you'll need
|
|
to register it.
|
|
|
|
.. code-block:: python
|
|
|
|
from imagekit import ImageSpec, register
|
|
from imagekit.processors import ResizeToFill
|
|
|
|
class Thumbnail(ImageSpec):
|
|
processors = [ResizeToFill(100, 50)]
|
|
format = 'JPEG'
|
|
options = {'quality': 60}
|
|
|
|
register.generator('myapp:thumbnail', Thumbnail)
|
|
|
|
.. note::
|
|
|
|
You can register your generator with any id you want, but choose wisely!
|
|
If you pick something too generic, you could have a conflict with another
|
|
third-party app you're using. For this reason, it's a good idea to prefix
|
|
your generator ids with the name of your app. Also, ImageKit recognizes
|
|
colons as separators when doing pattern matching (e.g. in the generateimages
|
|
management command), so it's a good idea to use those too!
|
|
|
|
.. warning::
|
|
|
|
This code can go in any file you want—but you need to make sure it's loaded!
|
|
In order to keep things simple, ImageKit will automatically try to load an
|
|
module named "imagegenerators" in each of your installed apps. So why don't
|
|
you just save yourself the headache and put your image specs in there?
|
|
|
|
Now that we've created an image generator class and registered it with ImageKit,
|
|
we can use it in our templates!
|
|
|
|
|
|
generateimage
|
|
"""""""""""""
|
|
|
|
The most generic template tag that ImageKit gives you is called "generateimage".
|
|
It requires at least one argument: the id of a registered image generator.
|
|
Additional keyword-style arguments are passed to the registered generator class.
|
|
As we saw above, image spec constructors expect a source keyword argument, so
|
|
that's what we need to pass to use our thumbnail spec:
|
|
|
|
.. code-block:: html
|
|
|
|
{% load imagekit %}
|
|
|
|
{% generateimage 'myapp:thumbnail' source=source_file %}
|
|
|
|
This will output the following HTML:
|
|
|
|
.. code-block:: html
|
|
|
|
<img src="/media/CACHE/images/982d5af84cddddfd0fbf70892b4431e4.jpg" width="100" height="50" />
|
|
|
|
You can also add additional HTML attributes; just separate them from your
|
|
keyword args using two dashes:
|
|
|
|
.. code-block:: html
|
|
|
|
{% load imagekit %}
|
|
|
|
{% generateimage 'myapp:thumbnail' source=source_file -- alt="A picture of Me" id="mypicture" %}
|
|
|
|
Not generating HTML image tags? No problem. The tag also functions as an
|
|
assignment tag, providing access to the underlying file object:
|
|
|
|
.. code-block:: html
|
|
|
|
{% load imagekit %}
|
|
|
|
{% generateimage 'myapp:thumbnail' source=source_file as th %}
|
|
<a href="{{ th.url }}">Click to download a cool {{ th.width }} x {{ th.height }} image!</a>
|
|
|
|
|
|
thumbnail
|
|
"""""""""
|
|
|
|
Because it's such a common use case, ImageKit also provides a "thumbnail"
|
|
template tag:
|
|
|
|
.. code-block:: html
|
|
|
|
{% load imagekit %}
|
|
|
|
{% thumbnail '100x50' source_file %}
|
|
|
|
Like the generateimage tag, the thumbnail tag outputs an <img> tag:
|
|
|
|
.. code-block:: html
|
|
|
|
<img src="/media/CACHE/images/982d5af84cddddfd0fbf70892b4431e4.jpg" width="100" height="50" />
|
|
|
|
Comparing this syntax to the generateimage tag above, you'll notice a few
|
|
differences.
|
|
|
|
First, we didn't have to specify an image generator id; unless we tell it
|
|
otherwise, thumbnail tag uses the generator registered with the id
|
|
"imagekit:thumbnail". **It's important to note that this tag is *not* using the
|
|
Thumbnail spec class we defined earlier**; it's using the generator registered
|
|
with the id "imagekit:thumbnail" which, by default, is
|
|
``imagekit.generatorlibrary.Thumbnail``.
|
|
|
|
Second, we're passing two positional arguments (the dimensions and the source
|
|
image) as opposed to the keyword arguments we used with the generateimage tag.
|
|
|
|
Like with the generateimage tag, you can also specify additional HTML attributes
|
|
for the thumbnail tag, or use it as an assignment tag:
|
|
|
|
.. code-block:: html
|
|
|
|
{% load imagekit %}
|
|
|
|
{% thumbnail '100x50' source_file -- alt="A picture of Me" id="mypicture" %}
|
|
{% thumbnail '100x50' source_file as th %}
|
|
|
|
|
|
Using Specs in Forms
|
|
^^^^^^^^^^^^^^^^^^^^
|
|
|
|
In addition to the model field above, there's also a form field version of the
|
|
``ProcessedImageField`` class. The functionality is basically the same (it
|
|
processes an image once and saves the result), but it's used in a form class:
|
|
|
|
.. code-block:: python
|
|
|
|
from django import forms
|
|
from imagekit.forms import ProcessedImageField
|
|
from imagekit.processors import ResizeToFill
|
|
|
|
class ProfileForm(forms.Form):
|
|
avatar_thumbnail = ProcessedImageField(spec_id='myapp:profile:avatar_thumbnail',
|
|
processors=[ResizeToFill(100, 50)],
|
|
format='JPEG',
|
|
options={'quality': 60})
|
|
|
|
The benefit of using ``imagekit.forms.ProcessedImageField`` (as opposed to
|
|
``imagekit.models.ProcessedImageField`` above) is that it keeps the logic for
|
|
creating the image outside of your model (in which you would use a normal Django
|
|
ImageField). You can even create multiple forms, each with their own
|
|
ProcessedImageField, that all store their results in the same image field.
|
|
|
|
|
|
Processors
|
|
----------
|
|
|
|
So far, we've only seen one processor: ``imagekit.processors.ResizeToFill``. But
|
|
ImageKit is capable of far more than just resizing images, and that power comes
|
|
from its processors.
|
|
|
|
Processors take a PIL image object, do something to it, and return a new one.
|
|
A spec can make use of as many processors as you'd like, which will all be run
|
|
in order.
|
|
|
|
.. code-block:: python
|
|
|
|
from imagekit import ImageSpec
|
|
from imagekit.processors import TrimBorderColor, Adjust
|
|
|
|
class MySpec(ImageSpec):
|
|
processors = [
|
|
TrimBorderColor(),
|
|
Adjust(contrast=1.2, sharpness=1.1),
|
|
]
|
|
format = 'JPEG'
|
|
options = {'quality': 60}
|
|
|
|
The ``imagekit.processors`` module contains processors for many common
|
|
image manipulations, like resizing, rotating, and color adjustments. However,
|
|
if they aren't up to the task, you can create your own. All you have to do is
|
|
define a class that implements a ``process()`` method:
|
|
|
|
.. code-block:: python
|
|
|
|
class Watermark(object):
|
|
def process(self, image):
|
|
# Code for adding the watermark goes here.
|
|
return image
|
|
|
|
That's all there is to it! To use your fancy new custom processor, just include
|
|
it in your spec's ``processors`` list:
|
|
|
|
.. code-block:: python
|
|
|
|
from imagekit import ImageSpec
|
|
from imagekit.processors import TrimBorderColor, Adjust
|
|
from myapp.processors import Watermark
|
|
|
|
class MySpec(ImageSpec):
|
|
processors = [
|
|
TrimBorderColor(),
|
|
Adjust(contrast=1.2, sharpness=1.1),
|
|
Watermark(),
|
|
]
|
|
format = 'JPEG'
|
|
options = {'quality': 60}
|
|
|
|
Note that when you import a processor from ``imagekit.processors``, imagekit
|
|
in turn imports the processor from `PILKit`_. So if you are looking for
|
|
available processors, look at PILKit.
|
|
|
|
.. _`PILKit`: https://github.com/matthewwithanm/pilkit
|
|
|
|
|
|
Admin
|
|
-----
|
|
|
|
ImageKit also contains a class named ``imagekit.admin.AdminThumbnail``
|
|
for displaying specs (or even regular ImageFields) in the
|
|
`Django admin change list`_. AdminThumbnail is used as a property on
|
|
Django admin classes:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.contrib import admin
|
|
from imagekit.admin import AdminThumbnail
|
|
from .models import Photo
|
|
|
|
class PhotoAdmin(admin.ModelAdmin):
|
|
list_display = ('__str__', 'admin_thumbnail')
|
|
admin_thumbnail = AdminThumbnail(image_field='thumbnail')
|
|
|
|
admin.site.register(Photo, PhotoAdmin)
|
|
|
|
To use specs defined outside of models:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.contrib import admin
|
|
from imagekit.admin import AdminThumbnail
|
|
from imagekit import ImageSpec
|
|
from imagekit.processors import ResizeToFill
|
|
from imagekit.cachefiles import ImageCacheFile
|
|
|
|
from .models import Photo
|
|
|
|
class AdminThumbnailSpec(ImageSpec):
|
|
processors = [ResizeToFill(100, 30)]
|
|
format = 'JPEG'
|
|
options = {'quality': 60 }
|
|
|
|
def cached_admin_thumb(instance):
|
|
# `image` is the name of the image field on the model
|
|
cached = ImageCacheFile(AdminThumbnailSpec(instance.image))
|
|
# only generates the first time, subsequent calls use cache
|
|
cached.generate()
|
|
return cached
|
|
|
|
class PhotoAdmin(admin.ModelAdmin):
|
|
list_display = ('__str__', 'admin_thumbnail')
|
|
admin_thumbnail = AdminThumbnail(image_field=cached_admin_thumb)
|
|
|
|
admin.site.register(Photo, PhotoAdmin)
|
|
|
|
|
|
AdminThumbnail can even use a custom template. For more information, see
|
|
``imagekit.admin.AdminThumbnail``.
|
|
|
|
.. _`Django admin change list`: https://docs.djangoproject.com/en/dev/intro/tutorial02/#customize-the-admin-change-list
|
|
|
|
|
|
Management Commands
|
|
-------------------
|
|
|
|
ImageKit has one management command—`generateimages`—which will generate cache
|
|
files for all of your registered image generators. You can also pass it a list
|
|
of generator ids in order to generate images selectively.
|
|
|
|
|
|
Community
|
|
=========
|
|
|
|
Please use `the GitHub issue tracker <https://github.com/matthewwithanm/django-imagekit/issues>`_
|
|
to report bugs with django-imagekit. `A mailing list <https://groups.google.com/forum/#!forum/django-imagekit>`_
|
|
also exists to discuss the project and ask questions, as well as the official
|
|
`#imagekit <irc://irc.freenode.net/imagekit>`_ channel on Freenode.
|
|
|
|
|
|
Contributing
|
|
============
|
|
|
|
We love contributions! And you don't have to be an expert with the library—or
|
|
even Django—to contribute either: ImageKit's processors are standalone classes
|
|
that are completely separate from the more intimidating internals of Django's
|
|
ORM. If you've written a processor that you think might be useful to other
|
|
people, open a pull request so we can take a look!
|
|
|
|
You can also check out our list of `open, contributor-friendly issues`__ for
|
|
ideas.
|
|
|
|
Check out our `contributing guidelines`__ for more information about pitching in
|
|
with ImageKit.
|
|
|
|
|
|
__ https://github.com/matthewwithanm/django-imagekit/issues?labels=contributor-friendly&state=open
|
|
__ https://github.com/matthewwithanm/django-imagekit/blob/develop/CONTRIBUTING.rst
|