troggle-unchained/imagekit/specs.py

120 lines
3.4 KiB
Python
Raw Permalink Normal View History

""" ImageKit image specifications
All imagekit specifications must inherit from the ImageSpec class. Models
inheriting from ImageModel will be modified with a descriptor/accessor for each
spec found.
"""
import os
from StringIO import StringIO
from imagekit.lib import *
from imagekit.utils import img_to_fobj
from django.core.files.base import ContentFile
class ImageSpec(object):
pre_cache = False
quality = 70
increment_count = False
processors = []
@classmethod
def name(cls):
return getattr(cls, 'access_as', cls.__name__.lower())
@classmethod
def process(cls, image, obj):
processed_image = image.copy()
for proc in cls.processors:
processed_image = proc.process(processed_image, obj)
return processed_image
class Accessor(object):
def __init__(self, obj, spec):
self._img = None
self._obj = obj
self.spec = spec
def _get_imgfile(self):
format = self._img.format or 'JPEG'
if format != 'JPEG':
imgfile = img_to_fobj(self._img, format)
else:
imgfile = img_to_fobj(self._img, format,
quality=int(self.spec.quality),
optimize=True)
return imgfile
def _create(self):
if self._exists():
return
# process the original image file
fp = self._obj._imgfield.storage.open(self._obj._imgfield.name)
fp.seek(0)
fp = StringIO(fp.read())
try:
self._img = self.spec.process(Image.open(fp), self._obj)
# save the new image to the cache
content = ContentFile(self._get_imgfile().read())
self._obj._imgfield.storage.save(self.name, content)
except IOError:
pass
def _delete(self):
self._obj._imgfield.storage.delete(self.name)
def _exists(self):
return self._obj._imgfield.storage.exists(self.name)
def _basename(self):
filename, extension = \
os.path.splitext(os.path.basename(self._obj._imgfield.name))
return self._obj._ik.cache_filename_format % \
{'filename': filename,
'specname': self.spec.name(),
'extension': extension.lstrip('.')}
@property
def name(self):
return os.path.join(self._obj._ik.cache_dir, self._basename())
@property
def url(self):
self._create()
if self.spec.increment_count:
fieldname = self._obj._ik.save_count_as
if fieldname is not None:
current_count = getattr(self._obj, fieldname)
setattr(self._obj, fieldname, current_count + 1)
self._obj.save(clear_cache=False)
return self._obj._imgfield.storage.url(self.name)
@property
def file(self):
self._create()
return self._obj._imgfield.storage.open(self.name)
@property
def image(self):
if self._img is None:
self._create()
if self._img is None:
self._img = Image.open(self.file)
return self._img
@property
def width(self):
return self.image.size[0]
@property
def height(self):
return self.image.size[1]
class Descriptor(object):
def __init__(self, spec):
self._spec = spec
def __get__(self, obj, type=None):
return Accessor(obj, self._spec)