Add ::1 and localhost in settings.dev.ALLOWED_HOSTS
[xnet] / xnet / utils / images / fields.py
1 # -*- encoding: utf-8 -*-
2 """
3 django-thumbs by Antonio Melé
4 Modified by Arthur Darcet to support on demand resizing
5 """
6 from django.db.models import ImageField
7 from django.db.models.fields.files import ImageFieldFile
8 from PIL import Image
9 from django.core.files.base import ContentFile
10 import cStringIO, re
11
12
13 def 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
37 class 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
67 class 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)