diff --git a/imagekit/conf.py b/imagekit/conf.py index 51ddf55..4f3b95c 100644 --- a/imagekit/conf.py +++ b/imagekit/conf.py @@ -3,3 +3,4 @@ from appconf import AppConf class ImageKitConf(AppConf): DEFAULT_IMAGE_CACHE_BACKEND = 'imagekit.imagecache.PessimisticImageCacheBackend' + CACHE_DIR = 'CACHE/images' diff --git a/imagekit/generators.py b/imagekit/generators.py index 046f0c0..344fc67 100644 --- a/imagekit/generators.py +++ b/imagekit/generators.py @@ -1,8 +1,11 @@ +from django.conf import settings +from hashlib import md5 import os +import pickle from .lib import StringIO from .processors import ProcessorPipeline from .utils import (img_to_fobj, open_image, IKContentFile, extension_to_format, - UnknownExtensionError) + suggest_extension, UnknownExtensionError) class SpecFileGenerator(object): @@ -14,14 +17,18 @@ class SpecFileGenerator(object): self.autoconvert = autoconvert self.storage = storage + def get_processors(self, source_file): + processors = self.processors + if callable(processors): + processors = processors(source_file) + return processors + def process_content(self, content, filename=None, source_file=None): img = open_image(content) original_format = img.format # Run the processors - processors = self.processors - if callable(processors): - processors = processors(source_file) + processors = self.get_processors(source_file) img = ProcessorPipeline(processors or []).process(img) options = dict(self.options or {}) @@ -42,6 +49,25 @@ class SpecFileGenerator(object): content = IKContentFile(filename, imgfile.read(), format=format) return img, content + def generate_filename(self, source_file): + source_filename = source_file.name + filename = None + if source_filename: + hash = md5(''.join([ + pickle.dumps(self.get_processors(source_file)), + self.format, + pickle.dumps(self.options), + str(self.autoconvert), + ])).hexdigest() + extension = suggest_extension(source_filename, self.format) + + filename = os.path.normpath(os.path.join( + settings.IMAGEKIT_CACHE_DIR, + os.path.splitext(source_filename)[0], + '%s%s' % (hash, extension))) + + return filename + def generate_file(self, filename, source_file, save=True): """ Generates a new image file by processing the source file and returns diff --git a/imagekit/models/fields/__init__.py b/imagekit/models/fields/__init__.py index b2cceda..faa5fb5 100644 --- a/imagekit/models/fields/__init__.py +++ b/imagekit/models/fields/__init__.py @@ -17,8 +17,8 @@ class ImageSpecField(object): """ def __init__(self, processors=None, format=None, options=None, - image_field=None, pre_cache=None, storage=None, cache_to=None, - autoconvert=True, image_cache_backend=None): + image_field=None, pre_cache=None, storage=None, autoconvert=True, + image_cache_backend=None): """ :param processors: A list of processors to run on the original image. :param format: The format of the output file. If not provided, @@ -33,21 +33,6 @@ class ImageSpecField(object): original image. :param storage: A Django storage system to use to save the generated image. - :param cache_to: Specifies the filename to use when saving the image - cache file. This is modeled after ImageField's ``upload_to`` and - can be either a string (that specifies a directory) or a - callable (that returns a filepath). Callable values should - accept the following arguments: - - - instance -- The model instance this spec belongs to - - path -- The path of the original image - - specname -- the property name that the spec is bound to on - the model instance - - extension -- A recommended extension. If the format of the - spec is set explicitly, this suggestion will be - based on that format. if not, the extension of the - original file will be passed. You do not have to use - this extension, it's only a recommendation. :param autoconvert: Specifies whether automatic conversion using ``prepare_image()`` should be performed prior to saving. :param image_cache_backend: An object responsible for managing the state @@ -71,7 +56,6 @@ class ImageSpecField(object): autoconvert=autoconvert, storage=storage) self.image_field = image_field self.storage = storage - self.cache_to = cache_to self.image_cache_backend = image_cache_backend or \ get_default_image_cache_backend() diff --git a/imagekit/models/fields/files.py b/imagekit/models/fields/files.py index d6f3dc2..c213ac3 100644 --- a/imagekit/models/fields/files.py +++ b/imagekit/models/fields/files.py @@ -1,10 +1,4 @@ -import os -import datetime - from django.db.models.fields.files import ImageField, ImageFieldFile -from django.utils.encoding import force_unicode, smart_str - -from ...utils import suggest_extension class ImageSpecFieldFile(ImageFieldFile): @@ -89,52 +83,13 @@ class ImageSpecFieldFile(ImageFieldFile): if save: self.instance.save() - def _default_cache_to(self, instance, path, specname, extension): - """ - Determines the filename to use for the transformed image. Can be - overridden on a per-spec basis by setting the cache_to property on - the spec. - - """ - filepath, basename = os.path.split(path) - filename = os.path.splitext(basename)[0] - new_name = '%s_%s%s' % (filename, specname, extension) - return os.path.join('cache', filepath, new_name) - @property def name(self): """ - Specifies the filename that the cached image will use. The user can - control this by providing a `cache_to` method to the ImageSpecField. + Specifies the filename that the cached image will use. """ - name = getattr(self, '_name', None) - if not name: - filename = self.source_file.name - new_filename = None - if filename: - cache_to = self.field.cache_to or self._default_cache_to - - if not cache_to: - raise Exception('No cache_to or default_cache_to value' - ' specified') - if callable(cache_to): - suggested_extension = suggest_extension( - self.source_file.name, self.field.generator.format) - new_filename = force_unicode( - datetime.datetime.now().strftime( - smart_str(cache_to(self.instance, - self.source_file.name, self.attname, - suggested_extension)))) - else: - dir_name = os.path.normpath( - force_unicode(datetime.datetime.now().strftime( - smart_str(cache_to)))) - filename = os.path.normpath(os.path.basename(filename)) - new_filename = os.path.join(dir_name, filename) - - self._name = new_filename - return self._name + return self.field.generator.generate_filename(self.source_file) @name.setter def name(self, value):