diff --git a/imagekit/models.py b/imagekit/models.py index 382636b..879bdbe 100644 --- a/imagekit/models.py +++ b/imagekit/models.py @@ -70,7 +70,7 @@ class ImageModel(models.Model): abstract = True def admin_thumbnail_view(self): - if not self._imgfield: + if not self._imgfields: return None prop = getattr(self, self._ik.admin_thumbnail_property, None) if prop is None: @@ -82,17 +82,13 @@ class ImageModel(models.Model): (escape(self.get_absolute_url()), escape(prop.url)) else: return u'' % \ - (escape(self._imgfield.url), escape(prop.url)) + (escape(self._get_imgfield(self).url), escape(prop.url)) admin_thumbnail_view.short_description = _('Thumbnail') admin_thumbnail_view.allow_tags = True class IKOptions: pass - @property - def _imgfield(self): - return getattr(self, self._ik.image_field) - def _clear_cache(self): for spec in self._ik.specs: prop = getattr(self, spec.name()) @@ -105,14 +101,20 @@ class ImageModel(models.Model): prop._create() def save_image(self, name, image, save=True, replace=True): - if self._imgfield and replace: - self._imgfield.delete(save=False) - if hasattr(image, 'read'): - data = image.read() - else: - data = image - content = ContentFile(data) - self._imgfield.save(name, content, save) + imgfields = self._imgfields + for imgfield in imgfields: + if imgfield and replace: + imgfield.delete(save=False) + if hasattr(image, 'read'): + data = image.read() + else: + data = image + content = ContentFile(data) + imgfield.save(name, content, save) + + @property + def _imgfields(self): + return set([spec._get_imgfield(self) for spec in self._ik.specs]) def save(self, clear_cache=True, *args, **kwargs): super(ImageModel, self).save(*args, **kwargs) @@ -121,10 +123,11 @@ class ImageModel(models.Model): if is_new_object: clear_cache = False - if self._imgfield: + imgfields = self._imgfields + for imgfield in imgfields: spec = self._ik.preprocessor_spec if spec is not None: - newfile = self._imgfield.storage.open(str(self._imgfield)) + newfile = imgfield.storage.open(str(imgfield)) img = Image.open(newfile) img, format = spec.process(img, self) if format != 'JPEG': @@ -135,10 +138,10 @@ class ImageModel(models.Model): optimize=True) content = ContentFile(imgfile.read()) newfile.close() - name = str(self._imgfield) - self._imgfield.storage.delete(name) - self._imgfield.storage.save(name, content) - if self._imgfield: + name = str(imgfield) + imgfield.storage.delete(name) + imgfield.storage.save(name, content) + if self._imgfields: if clear_cache: self._clear_cache() self._pre_cache() diff --git a/imagekit/options.py b/imagekit/options.py index d0deaea..92e25cb 100644 --- a/imagekit/options.py +++ b/imagekit/options.py @@ -7,7 +7,7 @@ class Options(object): """ Class handling per-model imagekit options """ - + admin_thumbnail_property = 'admin_thumbnail' """The name of the spec to be used by the admin_thumbnail_view""" diff --git a/imagekit/processors.py b/imagekit/processors.py index 484ddb1..26beaa5 100644 --- a/imagekit/processors.py +++ b/imagekit/processors.py @@ -11,7 +11,7 @@ from imagekit.lib import * class ImageProcessor(object): """ Base image processor class """ - def process(self, img, fmt, obj): + def process(self, img, fmt, obj, spec): return img, fmt @@ -23,7 +23,7 @@ class Adjust(ImageProcessor): self.contrast = contrast self.sharpness = sharpness - def process(self, img, fmt, obj): + def process(self, img, fmt, obj, spec): img = img.convert('RGB') for name in ['Color', 'Brightness', 'Contrast', 'Sharpness']: factor = getattr(self, name.lower()) @@ -39,7 +39,7 @@ class Format(ImageProcessor): format = 'JPEG' extension = 'jpg' - def process(self, img, fmt, obj): + def process(self, img, fmt, obj, spec): return img, self.format @@ -48,7 +48,7 @@ class Reflection(ImageProcessor): size = 0.0 opacity = 0.6 - def process(self, img, fmt, obj): + def process(self, img, fmt, obj, spec): # convert bgcolor string to rgb value background_color = ImageColor.getrgb(self.background_color) # handle palleted images @@ -102,7 +102,7 @@ class _Resize(ImageProcessor): if upscale is not None: self.upscale = upscale - def process(self, img, fmt, obj): + def process(self, img, fmt, obj, spec): cur_width, cur_height = img.size if self.crop: crop_horz = getattr(obj, obj._ik.crop_horz_field, 1) @@ -180,10 +180,10 @@ class Transpose(ImageProcessor): method = 'auto' - def process(self, img, fmt, obj): + def process(self, img, fmt, obj, spec): if self.method == 'auto': try: - orientation = Image.open(obj._imgfield.file)._getexif()[0x0112] + orientation = Image.open(spec._get_imgfield(obj).file)._getexif()[0x0112] ops = self.EXIF_ORIENTATION_STEPS[orientation] except: ops = [] diff --git a/imagekit/specs.py b/imagekit/specs.py index 0bdef69..c99b627 100644 --- a/imagekit/specs.py +++ b/imagekit/specs.py @@ -15,6 +15,7 @@ from django.core.files.base import ContentFile class ImageSpec(object): + image_field = 'original_image' # TODO: Get rid of this. It can be specified in a SpecDefaults nested class. processors = [] pre_cache = False quality = 70 @@ -25,11 +26,14 @@ class ImageSpec(object): self.processors = processors self.__dict__.update(kwargs) + def _get_imgfield(self, obj): + return getattr(obj, self.image_field) + def process(self, image, obj): fmt = image.format img = image.copy() for proc in self.processors: - img, fmt = proc.process(img, fmt, obj) + img, fmt = proc.process(img, fmt, obj, self) img.format = fmt return img, fmt @@ -52,13 +56,17 @@ class Accessor(object): optimize=True) return imgfile + @property + def _imgfield(self): + return self.spec._get_imgfield(self._obj) + def _create(self): - if self._obj._imgfield: + if self._imgfield: if self._exists(): return # process the original image file try: - fp = self._obj._imgfield.storage.open(self._obj._imgfield.name) + fp = self._imgfield.storage.open(self._imgfield.name) except IOError: return fp.seek(0) @@ -69,20 +77,20 @@ class Accessor(object): self._storage.save(self.name, content) def _delete(self): - if self._obj._imgfield: + if self._imgfield: try: self._storage.delete(self.name) except (NotImplementedError, IOError): return def _exists(self): - if self._obj._imgfield: + if self._imgfield: return self._storage.exists(self.name) @property def name(self): - if self._obj._imgfield.name: - filepath, basename = os.path.split(self._obj._imgfield.name) + if self._imgfield.name: + filepath, basename = os.path.split(self._imgfield.name) filename, extension = os.path.splitext(basename) for processor in self.spec.processors: if isinstance(processor, processors.Format): @@ -107,7 +115,7 @@ class Accessor(object): @property def _storage(self): - return getattr(self._obj._ik, 'storage', self._obj._imgfield.storage) + return getattr(self._obj._ik, 'storage', self._imgfield.storage) @property def url(self):