Fix Membership.__unicode__.
[xnet] / xnet / utils / images / fields.py
CommitLineData
626048e1
AD
1# -*- encoding: utf-8 -*-
2"""
3django-thumbs by Antonio Melé
4Modified by Arthur Darcet to support on demand resizing
5"""
6from django.db.models import ImageField
7from django.db.models.fields.files import ImageFieldFile
8from PIL import Image
9from django.core.files.base import ContentFile
10import cStringIO, re
11
12
13def generate_thumb(img, thumb_size, format):
14 img.seek(0) # see http://code.djangoproject.com/ticket/8222 for details
15 image = Image.open(img)
16 if image.mode not in ('L', 'RGB'):
17 image = image.convert('RGB')
18 thumb_w, thumb_h = thumb_size
19 if thumb_w == thumb_h and False:
20 xsize, ysize = image.size
21 minsize = min(xsize,ysize)
22 xnewsize = (xsize-minsize)/2
23 ynewsize = (ysize-minsize)/2
24 image2 = image.crop((xnewsize, ynewsize, xsize-xnewsize, ysize-ynewsize))
25 image2.load()
26 image2.thumbnail(thumb_size, Image.ANTIALIAS)
27 else:
28 image2 = image
29 image2.thumbnail(thumb_size, Image.ANTIALIAS)
30 io = cStringIO.StringIO()
31 if format.upper()=='JPG':
32 format = 'JPEG'
33 image2.save(io, format)
34 return ContentFile(io.getvalue())
35
36
37class ImageWithThumbsFieldFile(ImageFieldFile):
38 @staticmethod
39 def _get_for_size(s, (w,h)):
40 split = s.rsplit('.',1)
41 return u'{}.{}x{}.{}'.format(split[0],w,h,split[1])
42
43 def __getattr__(self, attr):
44 s = attr.split('url_')
45 if len(s) != 2 or 'x' not in s[1]:
46 raise AttributeError
47 if not self.name:
48 raise AttributeError('The picture has no file associated with it.')
49 size = map(int, s[1].split('x',1))
50 name = ImageWithThumbsFieldFile._get_for_size(self.name, size)
51 url = ImageWithThumbsFieldFile._get_for_size(self.url, size)
52 if not self.storage.exists(name):
53 thumb_content = generate_thumb(self, size, name.rsplit('.',1)[1])
54 self.storage.save(name, thumb_content)
55 return url
56
57 def delete(self, save=True):
58 directory, name = self.name.rsplit('/', 1)
59 _, files = self.storage.listdir(directory)
60 reg = re.compile(r'{}.[0-9]+x[0-9]+.{}'.format(*name.rsplit('.',1)))
61 for f in files:
62 if reg.match(f):
63 self.storage.delete(u'{}/{}'.format(directory, f))
64 super(ImageWithThumbsFieldFile, self).delete(save)
65
66
67class ImageWithThumbsField(ImageField):
68 attr_class = ImageWithThumbsFieldFile
69 """
70 Usage example:
71 ==============
72 photo = ImageWithThumbsField(upload_to='images', sizes=((125,125),(300,200),)
73
74 To retrieve image URL, exactly the same way as with ImageField:
75 my_object.photo.url
76 To retrieve thumbnails URL's just add the size to it:
77 my_object.photo.url_125x125
78 my_object.photo.url_300x200
79
80 Note: The 'sizes' attribute is not required. If you don't provide it,
81 ImageWithThumbsField will act as a normal ImageField
82
83 How it works:
84 =============
85 For each size in the 'sizes' atribute of the field it generates a
86 thumbnail with that size and stores it following this format:
87
88 available_filename.[width]x[height].extension
89
90 Where 'available_filename' is the available filename returned by the storage
91 backend for saving the original file.
92
93 Following the usage example above: For storing a file called "photo.jpg" it saves:
94 photo.jpg (original file)
95 photo.125x125.jpg (first thumbnail)
96 photo.300x200.jpg (second thumbnail)
97
98 With the default storage backend if photo.jpg already exists it will use these filenames:
99 photo_.jpg
100 photo_.125x125.jpg
101 photo_.300x200.jpg
102
103 Note: django-thumbs assumes that if filename "any_filename.jpg" is available
104 filenames with this format "any_filename.[widht]x[height].jpg" will be available, too.
105
106 To do:
107 ======
108 Add method to regenerate thubmnails
109
110 """
111 def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
112 self.verbose_name=verbose_name
113 self.name=name
114 self.width_field=width_field
115 self.height_field=height_field
116 super(ImageField, self).__init__(**kwargs)