mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-03-16 21:30:23 +00:00
Some docs
This commit is contained in:
parent
f94b7276b3
commit
58e1c7f7e0
2 changed files with 233 additions and 82 deletions
269
README.rst
269
README.rst
|
|
@ -36,10 +36,87 @@ 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:
|
||||
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/generated/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
|
||||
|
||||
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
|
||||
``ImageField``s.
|
||||
|
||||
.. 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
|
||||
|
||||
|
|
@ -51,51 +128,109 @@ way is by defining an ``ImageSpec`` subclass:
|
|||
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:
|
||||
It's probaby 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
|
||||
|
||||
spec = Thumbnail()
|
||||
new_file = spec.apply(source_file)
|
||||
source_file = open('/path/to/myimage.jpg')
|
||||
image_generator = Thumbnail(source=source_file)
|
||||
result = image_generator.generate()
|
||||
|
||||
More often, however, you'll want to register your spec with ImageKit:
|
||||
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
|
||||
|
||||
from imagekit import specs
|
||||
specs.register(Thumbnail, 'myapp:fancy_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.
|
||||
dest = open('/path/to/dest.jpg', 'w')
|
||||
dest.write(result.read())
|
||||
dest.close()
|
||||
|
||||
|
||||
In Templates
|
||||
^^^^^^^^^^^^
|
||||
Using Specs In Templates
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
One utility ImageKit provides for processing images is a template tag:
|
||||
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
|
||||
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 %}
|
||||
|
||||
{% spec 'myapp:fancy_thumbnail' source_image alt='A picture of me' %}
|
||||
{% generateimage 'myapp:thumbnail' source=source_image %}
|
||||
|
||||
Output:
|
||||
This will output the following HTML:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<img src="/media/CACHE/ik/982d5af84cddddfd0fbf70892b4431e4.jpg" width="100" height="50" alt="A picture of me" />
|
||||
<img src="/media/generated/iimages/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_image -- 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:
|
||||
|
|
@ -104,72 +239,42 @@ assignment tag, providing access to the underlying file object:
|
|||
|
||||
{% load imagekit %}
|
||||
|
||||
{% spec 'myapp:fancy_thumbnail' source_image as th %}
|
||||
{% generateimage 'myapp:thumbnail' source=source_image as th %}
|
||||
<a href="{{ th.url }}">Click to download a cool {{ th.width }} x {{ th.height }} image!</a>
|
||||
|
||||
|
||||
In Models
|
||||
^^^^^^^^^
|
||||
thumbnail
|
||||
"""""""""
|
||||
|
||||
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:
|
||||
Because it's such a common use case, ImageKit also provides a "thumbnail"
|
||||
template tag.
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: html
|
||||
|
||||
from django.db import models
|
||||
from imagekit.models import ImageSpecField
|
||||
{% load imagekit %}
|
||||
|
||||
class Photo(models.Model):
|
||||
avatar = models.ImageField(upload_to='avatars')
|
||||
avatar_thumbnail = ImageSpecField(id='myapp:fancy_thumbnail', source='avatar')
|
||||
{% thumbnail '100x50' source_image %}
|
||||
|
||||
photo = Photo.objects.all()[0]
|
||||
print photo.avatar_thumbnail.url # > /media/CACHE/ik/982d5af84cddddfd0fbf70892b4431e4.jpg
|
||||
print photo.avatar_thumbnail.width # > 100
|
||||
.. note::
|
||||
|
||||
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``:
|
||||
Comparing this syntax to the generateimage tag above, you'll notice a few
|
||||
differences.
|
||||
|
||||
.. code-block:: python
|
||||
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". (A custom id can be specified by passing an argument
|
||||
before the dimensions.) **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``.
|
||||
|
||||
from django.db import models
|
||||
from imagekit.models import ImageSpecField
|
||||
from imagekit.processors import ResizeToFill
|
||||
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. Interally, however, the tag is parsing our positional
|
||||
arguments and passing them as keyword arguments to our generator class.
|
||||
|
||||
class Photo(models.Model):
|
||||
avatar = models.ImageField(upload_to='avatars')
|
||||
avatar_thumbnail = ImageSpecField(processors=[ResizeToFill(100, 50)],
|
||||
format='JPEG',
|
||||
options={'quality': 60},
|
||||
source='avatar')
|
||||
|
||||
photo = Photo.objects.all()[0]
|
||||
print photo.avatar_thumbnail.url # > /media/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 # > /media/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
|
||||
|
|
|
|||
|
|
@ -1,9 +1,29 @@
|
|||
"""
|
||||
Functions responsible for returning filenames for the given image generator.
|
||||
Users are free to define their own functions; these are just some some sensible
|
||||
choices.
|
||||
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
import os
|
||||
from ..utils import format_to_extension, suggest_extension
|
||||
|
||||
|
||||
def source_name_as_path(generator):
|
||||
"""
|
||||
A namer that, given the following source file name::
|
||||
|
||||
photos/thumbnails/bulldog.jpg
|
||||
|
||||
will generate a name like this::
|
||||
|
||||
/path/to/generated/images/photos/thumbnails/bulldog/5ff3233527c5ac3e4b596343b440ff67.jpg
|
||||
|
||||
where "/path/to/generated/images/" is the value specified by the
|
||||
``IMAGEKIT_GENERATEDFILE_DIR`` setting.
|
||||
|
||||
"""
|
||||
source_filename = getattr(generator.source, 'name', None)
|
||||
|
||||
if source_filename is None or os.path.isabs(source_filename):
|
||||
|
|
@ -21,6 +41,19 @@ def source_name_as_path(generator):
|
|||
|
||||
|
||||
def source_name_dot_hash(generator):
|
||||
"""
|
||||
A namer that, given the following source file name::
|
||||
|
||||
photos/thumbnails/bulldog.jpg
|
||||
|
||||
will generate a name like this::
|
||||
|
||||
/path/to/generated/images/photos/thumbnails/bulldog.5ff3233527c5.jpg
|
||||
|
||||
where "/path/to/generated/images/" is the value specified by the
|
||||
``IMAGEKIT_GENERATEDFILE_DIR`` setting.
|
||||
|
||||
"""
|
||||
source_filename = getattr(generator.source, 'name', None)
|
||||
|
||||
if source_filename is None or os.path.isabs(source_filename):
|
||||
|
|
@ -39,6 +72,19 @@ def source_name_dot_hash(generator):
|
|||
|
||||
|
||||
def hash(generator):
|
||||
"""
|
||||
A namer that, given the following source file name::
|
||||
|
||||
photos/thumbnails/bulldog.jpg
|
||||
|
||||
will generate a name like this::
|
||||
|
||||
/path/to/generated/images/5ff3233527c5ac3e4b596343b440ff67.jpg
|
||||
|
||||
where "/path/to/generated/images/" is the value specified by the
|
||||
``IMAGEKIT_GENERATEDFILE_DIR`` setting.
|
||||
|
||||
"""
|
||||
format = getattr(generator, 'format', None)
|
||||
ext = format_to_extension(format) if format else ''
|
||||
return os.path.normpath(os.path.join(settings.IMAGEKIT_GENERATEDFILE_DIR,
|
||||
|
|
|
|||
Loading…
Reference in a new issue