From 70f80ba7fa942abf58afe0c153956b43de053f58 Mon Sep 17 00:00:00 2001 From: Bryan Veloso Date: Fri, 23 Mar 2012 14:32:52 -0700 Subject: [PATCH 1/5] Bumping an version number. --- imagekit/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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' From 2d02e02b8cfd3b45294c85efa310952effed809a Mon Sep 17 00:00:00 2001 From: Bryan Veloso Date: Fri, 23 Mar 2012 16:42:14 -0700 Subject: [PATCH 2/5] Intial pass of the 2.0 release notes. --- docs/changelog.rst | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index 742ad29..f27de82 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,68 @@ Changelog ========= +v2.0.0 +------ + +- Added the concept of cache state backends. Cache state backends assume + control of an image's CRUD actions from `ImageSpec` in versions past. The + default backend maintins the current behavior: invalidating an image and + deleting it, then validating that it creates the file if it doesn't already + exist. One can create custom cache state backends to control how their + images are cached (e.g., Celery, etc.). + + ImageKit ships with three built-in backends: + + - ``imagecache.base.PessimisticImageCacheBackend`` - A very safe image cache + backend. Guarantees that files will always be available, but at the cost + of hitting the storage backend. + - ``imagecache.base.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. + - ``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. + +- ``resize.Crop`` has been renamed to ``reszie.Fill``. Using ``resize.Crop`` + will throw a ``DeprecationWarning``. + +- New processors have been added: + + - ``crop.BasicCrop`` - Crop using provided box. + - ``crop.SmartCrop`` - Crop to provided size, trimming based on entropy. + - ``crop.TrimBorderColor`` - Trim the specified color from the specified + sides. + - ``resize.AddBorder`` - Add a border of specific color and size to an + image. + - ``resize.Resize`` - Scale to the provided dimensions (can distort). + - ``resize.ResizeToCover`` - Scale to the smallest size that will cover + the specified dimensions. Used internally by ``Fill`` and ``SmartFill``. + - ``resize.ResizeToFill`` - Scale to fill the provided dimensions, + trimming away excess using ``Crop``. + - ``resize.ResizeToFit`` - Scale to fit the provided dimensions. + - ``resize.ResizeCanvas`` - Takes an image an resizes the canvas, using a + specific background color if the new size is larger than the current + image. + - ``resize.SmartFill`` - Scale to fill the provided dimensions, trimming + away excess using ``SmartCrop``. + +- ``mat_color`` has been added as an arguemnt to the ``ResizeProcessor``. If + set, 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 +77,7 @@ v1.1.0 - The private ``_Resize`` class has been removed. + v1.0.3 ------ @@ -30,6 +93,7 @@ v1.0.3 - Fixed PIL zeroing out files when write mode is enabled. + v1.0.2 ------ @@ -42,6 +106,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 +116,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 ---- From e7fe6d1d980913bc6db664806f31c7aa36b97e4d Mon Sep 17 00:00:00 2001 From: Bryan Veloso Date: Fri, 23 Mar 2012 16:47:46 -0700 Subject: [PATCH 3/5] Spelling error. --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index f27de82..8e94df0 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -31,7 +31,7 @@ v2.0.0 get a stale spec image. The tradeoff is that calling `invalidate()` won't block to interact with file storage. -- ``resize.Crop`` has been renamed to ``reszie.Fill``. Using ``resize.Crop`` +- ``resize.Crop`` has been renamed to ``resize.Fill``. Using ``resize.Crop`` will throw a ``DeprecationWarning``. - New processors have been added: From 8aafc3681ac54c63e886fa82d58c05796a2ec2d4 Mon Sep 17 00:00:00 2001 From: Matthew Tretter Date: Sat, 24 Mar 2012 18:40:00 -0400 Subject: [PATCH 4/5] Some changelog corrections --- docs/changelog.rst | 74 ++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 8e94df0..9257870 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,58 +4,60 @@ Changelog v2.0.0 ------ -- Added the concept of cache state backends. Cache state backends assume - control of an image's CRUD actions from `ImageSpec` in versions past. The - default backend maintins the current behavior: invalidating an image and - deleting it, then validating that it creates the file if it doesn't already - exist. One can create custom cache state backends to control how their - images are cached (e.g., Celery, etc.). +- 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: - - ``imagecache.base.PessimisticImageCacheBackend`` - A very safe image cache - backend. Guarantees that files will always be available, but at the cost - of hitting the storage backend. - - ``imagecache.base.NonValidatingImageCacheBackend`` - A backend that is + - ``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. - - ``imagecache.celery.CeleryImageCacheBackend`` - A pessimistic cache state - backend that uses celery to generate its spec images. Like + - ``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()` + 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. -- ``resize.Crop`` has been renamed to ``resize.Fill``. Using ``resize.Crop`` - will throw a ``DeprecationWarning``. +- Some of the processors have been renamed and several new ones have been added: -- New processors have been added: - - - ``crop.BasicCrop`` - Crop using provided box. - - ``crop.SmartCrop`` - Crop to provided size, trimming based on entropy. - - ``crop.TrimBorderColor`` - Trim the specified color from the specified - sides. - - ``resize.AddBorder`` - Add a border of specific color and size to an + - ``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. - - ``resize.Resize`` - Scale to the provided dimensions (can distort). - - ``resize.ResizeToCover`` - Scale to the smallest size that will cover - the specified dimensions. Used internally by ``Fill`` and ``SmartFill``. - - ``resize.ResizeToFill`` - Scale to fill the provided dimensions, - trimming away excess using ``Crop``. - - ``resize.ResizeToFit`` - Scale to fit the provided dimensions. - - ``resize.ResizeCanvas`` - Takes an image an resizes the canvas, using a - specific background color if the new size is larger than the current - image. - - ``resize.SmartFill`` - Scale to fill the provided dimensions, trimming - away excess using ``SmartCrop``. -- ``mat_color`` has been added as an arguemnt to the ``ResizeProcessor``. If - set, the target image size will be enforced and the specified color will be +- ``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. From 479270e498a063408b6c576a4bc9c328b4faa3da Mon Sep 17 00:00:00 2001 From: Matthew Tretter Date: Sat, 24 Mar 2012 19:03:24 -0400 Subject: [PATCH 5/5] Introduction to image cache backends --- README.rst | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 5a2ea01..4180705 100644 --- a/README.rst +++ b/README.rst @@ -51,6 +51,17 @@ an ImageFile-like object (just like with a normal Check out ``imagekit.models.fields.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 ------------