2009-01-04 18:30:03 +00:00
|
|
|
""" ImageKit image specifications
|
2009-01-04 17:38:06 +00:00
|
|
|
|
2009-01-04 18:30:03 +00:00
|
|
|
All imagekit specifications must inherit from the ImageSpec class. Models
|
2009-01-14 16:09:17 +00:00
|
|
|
inheriting from ImageModel will be modified with a descriptor/accessor for each
|
2009-01-04 18:30:03 +00:00
|
|
|
spec found.
|
2009-01-04 17:38:06 +00:00
|
|
|
|
|
|
|
|
"""
|
2009-01-04 22:14:13 +00:00
|
|
|
import os
|
2011-09-19 01:08:49 +00:00
|
|
|
import datetime
|
2009-02-04 19:38:30 +00:00
|
|
|
from StringIO import StringIO
|
2009-06-04 15:47:16 +00:00
|
|
|
from imagekit import processors
|
2009-01-08 21:11:15 +00:00
|
|
|
from imagekit.lib import *
|
2009-01-08 20:04:20 +00:00
|
|
|
from imagekit.utils import img_to_fobj
|
2009-01-08 17:45:06 +00:00
|
|
|
from django.core.files.base import ContentFile
|
2011-09-19 01:08:49 +00:00
|
|
|
from django.utils.encoding import force_unicode, smart_str
|
2009-01-04 22:14:13 +00:00
|
|
|
|
2009-06-04 15:06:11 +00:00
|
|
|
|
2009-01-04 18:30:03 +00:00
|
|
|
class ImageSpec(object):
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2011-09-10 04:25:27 +00:00
|
|
|
image_field = None
|
2011-09-08 19:52:09 +00:00
|
|
|
processors = []
|
|
|
|
|
pre_cache = False
|
|
|
|
|
quality = 70
|
|
|
|
|
increment_count = False
|
2011-09-10 03:23:27 +00:00
|
|
|
storage = None
|
2011-09-08 19:52:09 +00:00
|
|
|
|
|
|
|
|
def __init__(self, processors=None, **kwargs):
|
|
|
|
|
if processors:
|
|
|
|
|
self.processors = processors
|
|
|
|
|
self.__dict__.update(kwargs)
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2011-09-10 04:24:37 +00:00
|
|
|
def _get_imgfield(self, obj):
|
2011-09-10 04:25:27 +00:00
|
|
|
field_name = getattr(self, 'image_field', None) or obj._ik.default_image_field
|
|
|
|
|
return getattr(obj, field_name)
|
2011-09-10 04:24:37 +00:00
|
|
|
|
2011-09-08 13:15:08 +00:00
|
|
|
def process(self, image, obj):
|
2009-06-04 15:06:11 +00:00
|
|
|
fmt = image.format
|
|
|
|
|
img = image.copy()
|
2011-09-08 13:15:08 +00:00
|
|
|
for proc in self.processors:
|
2011-09-10 04:24:37 +00:00
|
|
|
img, fmt = proc.process(img, fmt, obj, self)
|
2009-06-04 15:06:11 +00:00
|
|
|
img.format = fmt
|
2009-06-04 15:47:16 +00:00
|
|
|
return img, fmt
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2011-09-20 19:42:28 +00:00
|
|
|
def contribute_to_class(self, cls, name):
|
|
|
|
|
setattr(cls, name, Descriptor(self, name))
|
|
|
|
|
|
2009-01-04 18:30:03 +00:00
|
|
|
|
|
|
|
|
class Accessor(object):
|
2011-09-08 12:30:54 +00:00
|
|
|
def __init__(self, obj, spec, property_name):
|
2009-01-04 18:30:03 +00:00
|
|
|
self._img = None
|
2009-06-04 15:47:16 +00:00
|
|
|
self._fmt = None
|
2009-01-04 18:30:03 +00:00
|
|
|
self._obj = obj
|
|
|
|
|
self.spec = spec
|
2011-09-08 12:30:54 +00:00
|
|
|
self.property_name = property_name
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2009-01-08 20:04:20 +00:00
|
|
|
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
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2011-09-10 04:24:37 +00:00
|
|
|
@property
|
|
|
|
|
def _imgfield(self):
|
|
|
|
|
return self.spec._get_imgfield(self._obj)
|
|
|
|
|
|
2009-01-08 17:45:06 +00:00
|
|
|
def _create(self):
|
2011-09-10 04:24:37 +00:00
|
|
|
if self._imgfield:
|
2011-02-11 19:58:36 +00:00
|
|
|
if self._exists():
|
|
|
|
|
return
|
2011-02-11 20:11:20 +00:00
|
|
|
# process the original image file
|
|
|
|
|
try:
|
2011-09-10 04:24:37 +00:00
|
|
|
fp = self._imgfield.storage.open(self._imgfield.name)
|
2011-02-11 20:11:20 +00:00
|
|
|
except IOError:
|
|
|
|
|
return
|
|
|
|
|
fp.seek(0)
|
|
|
|
|
fp = StringIO(fp.read())
|
|
|
|
|
self._img, self._fmt = self.spec.process(Image.open(fp), self._obj)
|
|
|
|
|
# save the new image to the cache
|
|
|
|
|
content = ContentFile(self._get_imgfile().read())
|
2011-09-08 13:15:58 +00:00
|
|
|
self._storage.save(self.name, content)
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2009-01-08 17:45:06 +00:00
|
|
|
def _delete(self):
|
2011-09-10 04:24:37 +00:00
|
|
|
if self._imgfield:
|
2011-08-26 14:42:14 +00:00
|
|
|
try:
|
2011-09-08 13:15:58 +00:00
|
|
|
self._storage.delete(self.name)
|
2011-08-26 14:42:14 +00:00
|
|
|
except (NotImplementedError, IOError):
|
|
|
|
|
return
|
2009-01-08 17:45:06 +00:00
|
|
|
|
|
|
|
|
def _exists(self):
|
2011-09-10 04:24:37 +00:00
|
|
|
if self._imgfield:
|
2011-09-08 13:15:58 +00:00
|
|
|
return self._storage.exists(self.name)
|
2009-01-08 17:45:06 +00:00
|
|
|
|
2009-07-19 19:26:53 +00:00
|
|
|
@property
|
|
|
|
|
def name(self):
|
2011-09-19 01:08:49 +00:00
|
|
|
filename = self._imgfield.name
|
|
|
|
|
if filename:
|
|
|
|
|
cache_to = getattr(self.spec, 'cache_to', None) or \
|
|
|
|
|
getattr(self._obj._ik, 'default_cache_to', None)
|
|
|
|
|
|
|
|
|
|
if not cache_to:
|
|
|
|
|
raise Exception('No cache_to or default_cache_to value specified')
|
|
|
|
|
if callable(cache_to):
|
|
|
|
|
extension = os.path.splitext(filename)[1]
|
|
|
|
|
for processor in self.spec.processors:
|
|
|
|
|
if isinstance(processor, processors.Format):
|
|
|
|
|
extension = processor.extension
|
|
|
|
|
new_filename = force_unicode(datetime.datetime.now().strftime( \
|
|
|
|
|
smart_str(cache_to(self._obj, self._imgfield.name, \
|
|
|
|
|
self.property_name, extension.lstrip('.')))))
|
2011-02-11 19:58:36 +00:00
|
|
|
else:
|
2011-09-19 01:08:49 +00:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
return new_filename
|
2009-01-04 18:30:03 +00:00
|
|
|
|
2011-09-08 13:15:58 +00:00
|
|
|
@property
|
|
|
|
|
def _storage(self):
|
2011-09-10 03:23:27 +00:00
|
|
|
return getattr(self.spec, 'storage', None) or \
|
|
|
|
|
getattr(self._obj._ik, 'default_storage', None) or \
|
|
|
|
|
self._imgfield.storage
|
2011-09-08 13:15:58 +00:00
|
|
|
|
2009-01-04 18:30:03 +00:00
|
|
|
@property
|
|
|
|
|
def url(self):
|
2011-02-11 00:23:36 +00:00
|
|
|
if not self.spec.pre_cache:
|
|
|
|
|
self._create()
|
2009-01-06 19:00:53 +00:00
|
|
|
if self.spec.increment_count:
|
2009-01-04 18:30:03 +00:00
|
|
|
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)
|
2009-01-08 21:42:26 +00:00
|
|
|
self._obj.save(clear_cache=False)
|
2011-09-08 13:15:58 +00:00
|
|
|
return self._storage.url(self.name)
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2009-01-08 17:45:06 +00:00
|
|
|
@property
|
|
|
|
|
def file(self):
|
|
|
|
|
self._create()
|
2011-09-08 13:15:58 +00:00
|
|
|
return self._storage.open(self.name)
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2009-01-04 18:30:03 +00:00
|
|
|
@property
|
|
|
|
|
def image(self):
|
2011-02-11 00:23:36 +00:00
|
|
|
if not self._img:
|
2009-01-08 17:45:06 +00:00
|
|
|
self._create()
|
2011-02-11 00:23:36 +00:00
|
|
|
if not self._img:
|
2009-01-14 16:13:31 +00:00
|
|
|
self._img = Image.open(self.file)
|
2009-01-04 18:30:03 +00:00
|
|
|
return self._img
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2009-01-04 18:30:03 +00:00
|
|
|
@property
|
|
|
|
|
def width(self):
|
|
|
|
|
return self.image.size[0]
|
2009-12-19 16:01:54 +00:00
|
|
|
|
2009-01-04 18:30:03 +00:00
|
|
|
@property
|
|
|
|
|
def height(self):
|
|
|
|
|
return self.image.size[1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Descriptor(object):
|
2011-09-08 12:30:54 +00:00
|
|
|
def __init__(self, spec, property_name):
|
|
|
|
|
self._property_name = property_name
|
2009-01-04 18:30:03 +00:00
|
|
|
self._spec = spec
|
|
|
|
|
|
|
|
|
|
def __get__(self, obj, type=None):
|
2011-09-08 12:30:54 +00:00
|
|
|
return Accessor(obj, self._spec, self._property_name)
|