_imgfield is now a property of ImageSpec

Moved _imgfield from ImageModel to ImageSpec. Theoretically, this will allow you
to have specs that use different image fields on the same model.
This commit is contained in:
Matthew Tretter 2011-09-10 00:24:37 -04:00
parent 5e00de5204
commit 4c78f2d24c
4 changed files with 47 additions and 36 deletions

View file

@ -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'<a href="%s"><img src="%s"></a>' % \
(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()

View file

@ -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"""

View file

@ -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 = []

View file

@ -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):