Update docs

This will be great when 3.0 is ready, but it'll
also serve as a nice guide for us as we develop.
This commit is contained in:
Matthew Tretter 2012-10-14 22:28:48 -04:00
parent 93409c8f05
commit 5fe5a73cb1

View file

@ -1,6 +1,7 @@
ImageKit is a Django app that helps you to add variations of uploaded images
to your models. These variations are called "specs" and can include things
like different sizes (e.g. thumbnails) and black and white versions.
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.
**For the complete documentation on the latest stable version of ImageKit, see**
`ImageKit on RTD`_. Our `changelog is also available`_.
@ -10,10 +11,10 @@ like different sizes (e.g. thumbnails) and black and white versions.
Installation
------------
============
1. Install `PIL`_ or `Pillow`_. If you're using an ``ImageField`` in Django,
you should have already done this.
1. Install `PIL`_ or `Pillow`_. (If you're using an ``ImageField`` in Django,
you should have already done this.)
2. ``pip install django-imagekit``
(or clone the source and put the imagekit module on your path)
3. Add ``'imagekit'`` to your ``INSTALLED_APPS`` list in your project's settings.py
@ -27,11 +28,90 @@ Installation
.. _`Pillow`: http://pypi.python.org/pypi/Pillow
Adding Specs to a Model
-----------------------
Usage Overview
==============
Much like ``django.db.models.ImageField``, Specs are defined as properties
of a model class:
Specs
-----
You have one image and you want to do something to it to create another image.
That's the basic use case of ImageKit. But how do you tell ImageKit what to do?
By defining an "image spec." Specs are instructions for creating a new image
from an existing one, and there are a few ways to define one. The most basic
way is by defining an ``ImageSpec`` subclass:
.. code-block:: python
from imagekit import ImageSpec
from imagekit.processors import ResizeToFill
class Thumbnail(ImageSpec):
processors = [ResizeToFill(100, 50)]
format = 'JPEG'
options = {'quality': 60}
Now that you've defined a spec, it's time to use it. The nice thing about specs
is that they can be used in many different contexts.
Sometimes, you may want to just use a spec to generate a new image file. This
might be useful, for example, in view code, or in scripts:
.. code-block:: python
????????
More often, however, you'll want to register your spec with ImageKit:
.. code-block:: python
from imagekit import specs
specs.register('myapp:fancy_thumbnail', Thumbnail)
Once a spec is registered with a unique name, you can start to take advantage of
ImageKit's powerful utilities to automatically generate images for you...
.. note:: You might be wondering why we bother with the id string instead of
just passing the spec itself. The reason is that these ids allow users to
easily override specs defined in third party apps. That way, it doesn't
matter if "django-badblog" says its thumbnails are 200x200, you can just
register your own spec (using the same id the app uses) and have whatever
size thumbnails you want.
In Templates
^^^^^^^^^^^^
One utility ImageKit provides for processing images is a template tag:
.. code-block:: html
{% load imagekit %}
{% spec 'myapp:fancy_thumbnail' source_image alt='A picture of me' %}
Output:
.. code-block:: html
<img src="/static/CACHE/ik/982d5af84cddddfd0fbf70892b4431e4.jpg" width="100" height="50" alt="A picture of me" />
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 %}
{% spec 'myapp:fancy_thumbnail' source_image as th %}
<a href="{{ th.url }}">Click to download a cool {{ th.width }} x {{ th.height }} image!</a>
In Models
^^^^^^^^^
Specs can also be used to add ``ImageField``-like fields that expose the result
of applying a spec to another one of your model's fields:
.. code-block:: python
@ -39,73 +119,111 @@ of a model class:
from imagekit.models import ImageSpecField
class Photo(models.Model):
original_image = models.ImageField(upload_to='photos')
formatted_image = ImageSpecField(image_field='original_image', format='JPEG',
options={'quality': 90})
Accessing the spec through a model instance will create the image and return
an ImageFile-like object (just like with a normal
``django.db.models.ImageField``):
.. code-block:: python
avatar = models.ImageField(upload_to='avatars')
avatar_thumbnail = ImageSpecField(id='myapp:fancy_thumbnail', image_field='avatar')
photo = Photo.objects.all()[0]
photo.original_image.url # > '/media/photos/birthday.tiff'
photo.formatted_image.url # > '/media/cache/photos/birthday_formatted_image.jpeg'
print photo.avatar_thumbnail.url # > /static/CACHE/ik/982d5af84cddddfd0fbf70892b4431e4.jpg
print photo.avatar_thumbnail.width # > 100
Check out ``imagekit.models.ImageSpecField`` for more information.
If you only want to save the processed image (without maintaining the original),
you can use a ``ProcessedImageField``:
Since defining a spec, registering it, and using it in a single model field is
such a common usage, ImakeKit provides a shortcut that allow you to skip
writing a subclass of ``ImageSpec``:
.. code-block:: python
from django.db import models
from imagekit.models.fields import ProcessedImageField
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
class Photo(models.Model):
processed_image = ProcessedImageField(format='JPEG', options={'quality': 90})
avatar = models.ImageField(upload_to='avatars')
avatar_thumbnail = ImageSpecField(processors=[ResizeToFill(100, 50)],
format='JPEG',
options={'quality': 60},
image_field='avatar')
See the class documentation for details.
photo = Photo.objects.all()[0]
print photo.avatar_thumbnail.url # > /static/CACHE/ik/982d5af84cddddfd0fbf70892b4431e4.jpg
print photo.avatar_thumbnail.width # > 100
This has the exact same behavior as before, but the spec definition is inlined.
Since no ``id`` is provided, one is automatically generated based on the app
name, model, and field.
Specs can also be used in models to add ``ImageField``-like fields that process
a user-provided image without saving the original:
.. code-block:: python
from django.db import models
from imagekit.models import ProcessedImageField
class Photo(models.Model):
avatar_thumbnail = ProcessedImageField(spec_id='myapp:fancy_thumbnail',
upload_to='avatars')
photo = Photo.objects.all()[0]
print photo.avatar_thumbnail.url # > /static/avatars/MY-avatar_3.jpg
print photo.avatar_thumbnail.width # > 100
Like with ``ImageSpecField``, the ``ProcessedImageField`` constructor also
has a shortcut version that allows you to inline spec definitions.
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
class AvatarForm(forms.Form):
avatar_thumbnail = ProcessedImageField(spec_id='myapp:fancy_thumbnail')
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.
As with the model field classes, ``imagekit.forms.ProcessedImageField`` also
has a shortcut version that allows you to inline spec definitions.
Processors
----------
The real power of ImageKit comes from processors. Processors take an image, do
something to it, and return the result. By providing a list of processors to
your spec, you can expose different versions of the original image:
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 django.db import models
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill, Adjust
from imagekit import ImageSpec
from imagekit.processors import TrimBorderColor, Adjust
class Photo(models.Model):
original_image = models.ImageField(upload_to='photos')
thumbnail = ImageSpecField([Adjust(contrast=1.2, sharpness=1.1),
ResizeToFill(50, 50)], image_field='original_image',
format='JPEG', options={'quality': 90})
The ``thumbnail`` property will now return a cropped image:
.. code-block:: python
photo = Photo.objects.all()[0]
photo.thumbnail.url # > '/media/cache/photos/birthday_thumbnail.jpeg'
photo.thumbnail.width # > 50
photo.original_image.width # > 1000
The original image is not modified; ``thumbnail`` is a new file that is the
result of running the ``imagekit.processors.ResizeToFill`` processor on the
original. (If you only need to save the processed image, and not the original,
pass processors to a ``ProcessedImageField`` instead of an ``ImageSpecField``.)
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
implement a ``process()`` method:
define a class that implements a ``process()`` method:
.. code-block:: python
@ -114,10 +232,23 @@ implement a ``process()`` method:
# Code for adding the watermark goes here.
return image
class Photo(models.Model):
original_image = models.ImageField(upload_to='photos')
watermarked_image = ImageSpecField([Watermark()], image_field='original_image',
format='JPEG', options={'quality': 90})
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}
Admin
@ -134,12 +265,10 @@ Django admin classes:
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)
AdminThumbnail can even use a custom template. For more information, see
@ -148,40 +277,6 @@ AdminThumbnail can even use a custom template. For more information, see
.. _`Django admin change list`: https://docs.djangoproject.com/en/dev/intro/tutorial02/#customize-the-admin-change-list
Image Cache Backends
--------------------
Whenever you access properties like ``url``, ``width`` and ``height`` of an
``ImageSpecField``, its cached image is validated; whenever you save a new image
to the ``ImageField`` your spec uses as a source, the spec image is invalidated.
The default way to validate a cache image is to check to see if the file exists
and, if not, generate a new one; the default way to invalidate the cache is to
delete the image. This is a very simple and straightforward way to handle cache
validation, but it has its drawbacks—for example, checking to see if the image
exists means frequently hitting the storage backend.
Because of this, ImageKit allows you to define custom image cache backends. To
be a valid image cache backend, a class must implement three methods:
``validate``, ``invalidate``, and ``clear`` (which is called when the image is
no longer needed in any form, i.e. the model is deleted). Each of these methods
must accept a file object, but the internals are up to you. For example, you
could store the state (valid, invalid) of the cache in a database to avoid
filesystem access. You can then specify your image cache backend on a per-field
basis:
.. code-block:: python
class Photo(models.Model):
...
thumbnail = ImageSpecField(..., image_cache_backend=MyImageCacheBackend())
Or in your ``settings.py`` file if you want to use it as the default:
.. code-block:: python
IMAGEKIT_DEFAULT_IMAGE_CACHE_BACKEND = 'path.to.MyImageCacheBackend'
Community
---------
@ -199,7 +294,3 @@ 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!
ImageKit's image cache backends are also fairly isolated from the ImageKit guts.
If you've fine-tuned one to work perfectly for a popular file storage backend,
let us take a look! Maybe other people could use it.