Django Daguerre¶
Django Daguerre makes it easy to adjust images on-the-fly without slowing down your templates and without needing to generate everything ahead of time with a cron job. You don’t need to make any changes to your models; it Just Works.
{% load daguerre %}
<img src="{% adjust my_model.image "fill" width=200 height=400 %}" />
{% adjust_bulk my_queryset "method.image" "fill" width=200 height=400 as adjusted_list %}
{% for my_model, image in adjusted_list %}
<img src="{{ image }}" />
{% endfor %}
Code: | http://github.com/littleweaver/django-daguerre |
---|---|
Docs: | http://readthedocs.org/docs/django-daguerre/ |
Build status: |
Contents¶
Installation and Setup¶
Requirements¶
- Python 2.6+, 3.3+
- Pillow 2.3.0+
- Django 1.6+
- Six 1.3.0+
Daguerre may work with earlier versions of these packages, but it is untested.
Installation¶
You can install the latest version of Daguerre using pip:
pip install django-daguerre
You can clone the repository yourself at https://github.com/littleweaver/django-daguerre.
Setup¶
Ensure that 'daguerre' is in your project’s INSTALLED_APPS:
INSTALLED_APPS = (
'daguerre',
...
)
Add the following or similar anywhere in your URLconf:
urlpatterns = patterns('',
url(r'^daguerre/', include('daguerre.urls')),
...
)
Using daguerre¶
{% adjust %}¶
The easiest way to use Daguerre is through the {% adjust %} template tag:
{% load daguerre %}
<img src="{% adjust my_model.image 'fill' width=128 height=256 %}" />
daguerre works directly with any ImageField (or storage path). There is no magic. You don’t need to change your models. It Just Works.
Daguerre provides a number of built-in adjustments (such as ‘fill’) which can be used with the {% adjust %} out of the box, as well as an API for registering custom adjustments.
Take this picture:
Let’s use {% adjust %} with width 200 (25%) and height 300 (50%), with three of the built-in adjustments.
“fit” | “fill” | “crop” |
---|---|---|
Fits the entire image into the given dimensions without distorting it. | Fills the entire space given by the dimensions by cropping to the same width/height ratio and then scaling down or up. | Crops the image to the given dimensions without any resizing. |
Chaining Adjustments¶
You can also use the {% adjust %} tag to chain multiple adjustments. Take the following:
{% load daguerre %}
{% adjust my_model.image 'ratiocrop' ratio='16:9' 'fit' width=200 %}
This tag first crops the image to a 16:9 ratio, then scales as much as needed to fit within a 200-pixel width. In other words:
See also
daguerre.adjustments for more built-in adjustments.
Getting adjusted width and height¶
{% load daguerre %}
{% adjust my_model.image 'fit' width=128 height=128 as image %}
<img src="{{ image }}" width={{ image.width }} height={{ image.height }} />
The object being set to the image context variable is an AdjustmentInfoDict instance. In addition to rendering as the URL for an image, this object provides access to some other useful pieces of information—in particular, the width and height that the adjusted image will have, based on the width and height of the original image and the parameters given to the tag. This can help you avoid changes to page flow as adjusted images load.
Let’s be lazy¶
So the {% adjust %} tag renders as a URL to adjusted image, right? Yes, but as lazily as possible. If the adjustment has already been performed, the adjusted image’s URL is fetched from the database. If the adjustment has not been performed, the tag renders as a URL to a view which, when accessed, will create an adjusted version of the image and return a redirect to the adjusted image’s actual URL.
This does have the downside of requiring an additional request/response cycle when unadjusted images are fetched by the user – but it has the upside that no matter how many {% adjust %} tags you have on a page, the initial load of the page won’t be slowed down by (potentially numerous, potentially expensive) image adjustments.
Note
The adjustment view has some light security in place to make sure that users can’t run arbitrary image resizes on your servers.
{% adjust_bulk %}¶
If you are using a large number of similar adjustments in one template - say, looping over a queryset and adjusting the same attribute each time - you can save yourself queries by using {% adjust_bulk %}.
{% load daguerre %}
{% adjust_bulk my_queryset "method.image" "fill" width=200 height=400 as adjusted_list %}
{% for my_model, image in adjusted_list %}
<img src="{{ image }}" />
{% endfor %}
The syntax is similar to {% adjust %}, except that:
- as <varname> is required.
- an iterable (my_queryset) and a lookup to be performed on each item in the iterable ("method.image") are provided in place of an image file or storage path. (If the iterable is an iterable of image files or storage paths, the lookup is not required.)
Editing Areas¶
Daguerre provides a widget which can be used with any ImageField to edit Areas for that image file. Using this widget with a ModelAdmin is as simple as defining appropriate formfield_overrides.
from daguerre.widgets import AreaWidget
class YourModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.ImageField: {'widget': AreaWidget},
}
...
After you define Areas for an image in the admin, adjustments that remove parts of the image (such as crop and fill) can take them into account and protect those parts of the image during processing. Otherwise, any cropping will be done evenly from opposing sides.
Management commands¶
./manage.py daguerre clean¶
Cleans out extra or invalid data stored by daguerre:
- AdjustedImages and Areas that reference storage paths which no longer exist.
- Duplicate AdjustedImages.
- Adjusted image files which don’t have an associated AdjustedImage.
- AdjustedImage instances with missing adjusted image files.
./manage.py daguerre preadjust [--remove] [--nocreate]¶
Looks for a DAGUERRE_PREADJUSTMENTS setting using the following structure:
from daguerre.adjustments import Fit, Fill
DAGUERRE_PREADJUSTMENTS = (
('myapp.MyModel',
[Fit(width=800, height=500)],
'template.style.lookup'),
(OtherModel.objects.filter(field=value),
[Fill(width=300, height=216)].
'template.style.lookup'),
...
)
Essentially, this is expected to be an iterable of tuples, where each tuple contains three items:
- '<applabel>.<model>', a model class, a queryset, or any iterable.
- A non-empty iterable of adjustment instances to be applied to each image.
- A template-style lookup (or None).
Each time the command is run, the first item will be used to generate a fresh iterable of model instances. The lookup will be applied to each instance to get an ImageFile or storage path, which will then have the list of adjustments applied it to create a new adjusted version of the image, if one doesn’t exist already. (This is essentially the same functionality as the {% adjust_bulk %} template tag.)
If --remove is specified, the command will delete all AdjustedImage instances which would not be generated by the parameters specified in DAGUERRE_PREADJUSTMENTS.
If --nocreate is specified, the command will not create any new AdjustedImage instances. This can be used with --remove to just prune instances that aren’t specified in DAGUERRE_PREADJUSTMENTS without creating new pre-adjusted instances. Specifying --nocreate without --remove makes this command a no-op.
API Docs¶
Adjustments¶
Daguerre provides a variety of adjustments to use when processing images, as well as an API for registering custom adjustments.
- class daguerre.adjustments.Adjustment(**kwargs)¶
Base class for all adjustments which can be carried out on an image. The adjustment itself represents a set of parameters, which can then be applied to images (taking areas into account if applicable).
Adjustment subclasses need to define two methods: calculate() and adjust(). If the method doesn’t use areas, you can set the uses_areas attribute on the method to False to optimize adjustment.
Parameters: kwargs – The requested kwargs for the adjustment. The keys must be in parameters or the adjustment is invalid. - adjust(image, areas=None)¶
Manipulates and returns the image. Must be implemented by subclasses.
Parameters: - image – PIL Image which will be adjusted.
- areas – iterable of Area instances to be considered in performing the adjustment.
- calculate(dims, areas=None)¶
Calculates the dimensions of the adjusted image without actually manipulating the image. By default, just returns the given dimensions.
Parameters: - dims – (width, height) tuple of the current image dimensions.
- areas – iterable of Area instances to be considered in calculating the adjustment.
- parameters = ()¶
Accepted parameters for this adjustment - for example, "width", "height", "color", "unicorns", etc.
Built-In Adjustments¶
- class daguerre.adjustments.Fit(**kwargs)¶
Resizes an image to fit entirely within the given dimensions without cropping and maintaining the width/height ratio.
If neither width nor height is specified, this adjustment will simply return a copy of the image.
- parameters = ('width', 'height')¶
- class daguerre.adjustments.Fill(**kwargs)¶
Crops the image to the requested ratio (using the same logic as Crop to protect Area instances which are passed in), then resizes it to the actual requested dimensions. If width or height is not given, then the unspecified dimension will be allowed to expand up to max_width or max_height, respectively.
- parameters = ('width', 'height', 'max_width', 'max_height')¶
- class daguerre.adjustments.Crop(**kwargs)¶
Crops an image to the given width and height, without scaling it. Area instances which are passed in will be protected as much as possible during the crop.
- parameters = ('width', 'height')¶
- class daguerre.adjustments.RatioCrop(**kwargs)¶
Crops an image to the given aspect ratio, without scaling it. Area instances which are passed in will be protected as much as possible during the crop.
- parameters = ('ratio',)¶
ratio should be formatted as "<width>:<height>"
- class daguerre.adjustments.NamedCrop(**kwargs)¶
Crops an image to the given named area, without scaling it. Area instances which are passed in will be protected as much as possible during the crop.
If no area with the given name exists, this adjustment is a no-op.
- parameters = ('name',)¶
When used with the template tag, these adjustments should be referred to by their lowercase name:
{% adjust image "fit" width=300 %}
See Using daguerre for examples.
Custom Adjustments¶
You can easily add custom adjustments for your particular project. For example, an adjustment to make an image grayscale might look something like this:
# Somewhere that will be imported.
from daguerre.adjustments import Adjustment, registry
from PIL import ImageOps
@registry.register
class GrayScale(Adjustment):
def adjust(self, image, areas=None):
return ImageOps.grayscale(image)
adjust.uses_areas = False
Now you can use your adjustment in templates:
{% adjust image "grayscale" %}