1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 | from django.db.models.fields.files import ImageField, ImageFieldFile
from django.core.files.base import File, ContentFile
class ImageVariation(File):
variation_suffix = 'variation'
def __init__(self, instance):
self.field = instance.field
self.instance = instance.instance
self.storage = getattr(self, 'storage', instance.storage)
name = getattr(self.instance, self.field.name) or u''
self._name = self.get_variation_name(unicode(name))
self._closed = False
def get_variation_name(self, name):
try:
dot_index = name.rindex('.')
except:
name = '%s%s' % (name, self.variation_suffix)
else:
name = '%s%s%s' % (name[:dot_index], self.variation_suffix, name[dot_index:])
return name
def save(self, name, content):
self.storage.save(self.name, content)
def delete(self):
self.close()
self.storage.delete(self.name)
def _require_file(self):
if not self:
raise ValueError("The '%s' attribute has no file associated with it." % self.field.name)
def _get_file(self):
self._require_file()
if not hasattr(self, '_file'):
self._file = self.storage.open(self.name, 'rb')
return self._file
file = property(_get_file)
def _get_path(self):
self._require_file()
return self.storage.path(self.name)
path = property(_get_path)
def _get_url(self):
self._require_file()
return self.storage.url(self.name)
url = property(_get_url)
def open(self, mode='rb'):
self._require_file()
return super(ImageVariation, self).open(mode)
# open() doesn't alter the file's contents, but it does reset the pointer
open.alters_data = True
from StringIO import StringIO
def get_file(data):
if hasattr(data, 'temporary_file_path'):
file = data.temporary_file_path()
else:
if hasattr(data, 'read'):
file = StringIO(data.read())
else:
file = StringIO(data['content'])
return file
WIDTH, HEIGHT = 0, 1
def resize_image(content, size):
from PIL import Image
img = Image.open(get_file(content))
if img.size[0] > size['width'] or img.size[1] > size['height']:
if size['force']:
target_height = float(size['height'] * img.size[WIDTH]) / size['width']
if target_height < img.size[HEIGHT]: # Crop height
crop_side_size = int((img.size[HEIGHT] - target_height) / 2)
img = img.crop((0, crop_side_size, img.size[WIDTH], img.size[HEIGHT] - crop_side_size))
elif target_height > img.size[HEIGHT]: # Crop width
target_width = float(size['width'] * img.size[HEIGHT]) / size['height']
crop_side_size = int((img.size[WIDTH] - target_width) / 2)
img = img.crop((crop_side_size, 0, img.size[WIDTH] - crop_side_size, img.size[HEIGHT]))
img.thumbnail((size['width'], size['height']), Image.ANTIALIAS)
out = StringIO()
try:
img.save(out, optimize=1)
except IOError:
img.save(out)
return out
else:
return content
class Thumbnail(ImageVariation):
variation_suffix = 'thumbnail'
def save(self, name, content):
self.storage.save(self.name, resize_image(content, {'height': 200, 'width': 200, 'force': True} ) )
class ImageVariationsDescriptor(object):
def __get__(self, instance=None, owner=None):
self.variations = [ (v(instance))
for v in instance.field.variations ]
for v in self.variations:
setattr(self, v.__class__.__name__.lower(), v)
return self
def save(self, name, content):
for v in self.variations:
content.seek(0)
v.save(name, content)
def delete(self):
for v in self.variations:
v.delete()
class ImageVariationsFieldFile(ImageFieldFile):
variations = ImageVariationsDescriptor()
def save(self, name, content, save=True):
super(ImageVariationsFieldFile, self).save(name, content, save=save)
self.variations.save(name, content)
def delete(self, save=True):
self.variations.delete()
super(ImageVariationsFieldFile, self).delete(save)
class ImageVariationsField(ImageField):
attr_class = ImageVariationsFieldFile
def __init__(self, variations=[], *args, **kwargs):
self.variations = variations
super(ImageVariationsField, self).__init__(*args, **kwargs)
|
Comments