diff --git a/README.rst b/README.rst index 3e6d21c..a70f395 100644 --- a/README.rst +++ b/README.rst @@ -51,6 +51,17 @@ an ImageFile-like object (just like with a normal 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``:: + + from django.db import models + from imagekit.models.fields import ProcessedImageField + + class Photo(models.Model): + processed_image = ImageSpecField(format='JPEG', options={'quality': 90}) + +See the class documentation for details. + Processors ---------- @@ -78,7 +89,8 @@ The ``thumbnail`` property will now return a cropped image:: 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. +original. (If you only need to save the processed image, and not the original, +pass processors to a ``ProcessedImageField`` instead of an ``ImageSpecField``.) The ``imagekit.processors`` module contains processors for many common image manipulations, like resizing, rotating, and color adjustments. However, @@ -122,6 +134,36 @@ 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:: + + 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:: + + IMAGEKIT_DEFAULT_IMAGE_CACHE_BACKEND = 'path.to.MyImageCacheBackend' + + Contributing ------------ diff --git a/docs/changelog.rst b/docs/changelog.rst index 742ad29..9257870 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,70 @@ Changelog ========= +v2.0.0 +------ + +- Added the concept of image cache backends. Image cache backends assume + control of validating and invalidating the cached images from `ImageSpec` in + versions past. The default backend maintins the current behavior: invalidating + an image deletes it, while validating checks whether the file exists and + creates the file if it doesn't. One can create custom image cache backends to + control how their images are cached (e.g., Celery, etc.). + + ImageKit ships with three built-in backends: + + - ``imagekit.imagecache.PessimisticImageCacheBackend`` - A very safe image + cache backend. Guarantees that files will always be available, but at the + cost of hitting the storage backend. + - ``imagekit.imagecache.NonValidatingImageCacheBackend`` - A backend that is + super optimistic about the existence of spec files. It will hit your file + storage much less frequently than the pessimistic backend, but it is + technically possible for a cache file to be missing after validation. + - ``imagekit.imagecache.celery.CeleryImageCacheBackend`` - A pessimistic cache + state backend that uses celery to generate its spec images. Like + ``PessimisticCacheStateBackend``, this one checks to see if the file + exists on validation, so the storage is hit fairly frequently, but an + image is guaranteed to exist. However, while validation guarantees the + existence of *an* image, it does not necessarily guarantee that you will + get the correct image, as the spec may be pending regeneration. In other + words, while there are ``generate`` tasks in the queue, it is possible to + get a stale spec image. The tradeoff is that calling ``invalidate()`` + won't block to interact with file storage. + +- Some of the processors have been renamed and several new ones have been added: + + - ``imagekit.processors.ResizeToFill`` - (previously + ``imagekit.processors.resize.Crop``) Scales the image to fill the provided + dimensions and then trims away the excess. + - ``imagekit.processors.ResizeToFit`` - (previously + ``imagekit.processors.resize.Fit``) Scale to fit the provided dimensions. + - ``imagekit.processors.SmartResize`` - Like ``ResizeToFill``, but crops using + entroy (``SmartCrop``) instead of an anchor argument. + - ``imagekit.processors.BasicCrop`` - Crop using provided box. + - ``imagekit.processors.SmartCrop`` - (previously + ``imagekit.processors.resize.SmartCrop``) Crop to provided size, trimming + based on entropy. + - ``imagekit.processors.TrimBorderColor`` - Trim the specified color from the + specified sides. + - ``imagekit.processors.AddBorder`` - Add a border of specific color and + thickness to an image. + - ``imagekit.processors.Resize`` - Scale to the provided dimensions (can distort). + - ``imagekit.processors.ResizeToCover`` - Scale to the smallest size that will + cover the specified dimensions. Used internally by ``Fill`` and + ``SmartFill``. + - ``imagekit.processors.ResizeCanvas`` - Takes an image an resizes the canvas, + using a specific background color if the new size is larger than the current + image. + +- ``mat_color`` has been added as an arguemnt to ``ResizeToFit``. If set, the + the target image size will be enforced and the specified color will be + used as background color to pad the image. + +- We now use `Tox`_ to automate testing. + +.. _`Tox`: http://pypi.python.org/pypi/tox + + v1.1.0 ------ @@ -15,6 +79,7 @@ v1.1.0 - The private ``_Resize`` class has been removed. + v1.0.3 ------ @@ -30,6 +95,7 @@ v1.0.3 - Fixed PIL zeroing out files when write mode is enabled. + v1.0.2 ------ @@ -42,6 +108,7 @@ v1.0.2 - Fixed a regression from the 0.4.x series in which ImageKit was unable to convert a PNG file in ``P`` or "palette" mode to JPEG. + v1.0.1 ------ @@ -51,6 +118,7 @@ v1.0.1 - Fixed the included admin template not being found when ImageKit was and the packaging of the included admin templates. + v1.0 ---- diff --git a/imagekit/__init__.py b/imagekit/__init__.py index 1ce4055..d525af2 100644 --- a/imagekit/__init__.py +++ b/imagekit/__init__.py @@ -1,6 +1,6 @@ __title__ = 'django-imagekit' __author__ = 'Justin Driscoll, Bryan Veloso, Greg Newman, Chris Drackett, Matthew Tretter, Eric Eldredge' -__version__ = (2, 0, 0, 'rc', 1) +__version__ = (2, 0, 0, 'final', 0) __license__ = 'BSD'