1 # -*- encoding: utf-8 -*-
3 django-thumbs by Antonio Melé
4 Modified by Arthur Darcet to support on demand resizing
6 from django
.db
.models
import ImageField
7 from django
.db
.models
.fields
.files
import ImageFieldFile
9 from django
.core
.files
.base
import ContentFile
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
))
26 image2
.thumbnail(thumb_size
, Image
.ANTIALIAS
)
29 image2
.thumbnail(thumb_size
, Image
.ANTIALIAS
)
30 io
= cStringIO
.StringIO()
31 if format
.upper()=='JPG':
33 image2
.save(io
, format
)
34 return ContentFile(io
.getvalue())
37 class ImageWithThumbsFieldFile(ImageFieldFile
):
39 def _get_for_size(s
, (w
,h
)):
40 split
= s
.rsplit('.',1)
41 return u
'{}.{}x{}.{}'.format(split
[0],w
,h
,split
[1])
43 def __getattr__(self
, attr
):
44 s
= attr
.split('url_')
45 if len(s
) != 2 or 'x' not in s
[1]:
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
)
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)))
63 self
.storage
.delete(u
'{}/{}'.format(directory
, f
))
64 super(ImageWithThumbsFieldFile
, self
).delete(save
)
67 class ImageWithThumbsField(ImageField
):
68 attr_class
= ImageWithThumbsFieldFile
72 photo = ImageWithThumbsField(upload_to='images', sizes=((125,125),(300,200),)
74 To retrieve image URL, exactly the same way as with ImageField:
76 To retrieve thumbnails URL's just add the size to it:
77 my_object.photo.url_125x125
78 my_object.photo.url_300x200
80 Note: The 'sizes' attribute is not required. If you don't provide it,
81 ImageWithThumbsField will act as a normal ImageField
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:
88 available_filename.[width]x[height].extension
90 Where 'available_filename' is the available filename returned by the storage
91 backend for saving the original file.
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)
98 With the default storage backend if photo.jpg already exists it will use these filenames:
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.
108 Add method to regenerate thubmnails
111 def __init__(self
, verbose_name
=None, name
=None, width_field
=None, height_field
=None, **kwargs
):
112 self
.verbose_name
=verbose_name
114 self
.width_field
=width_field
115 self
.height_field
=height_field
116 super(ImageField
, self
).__init__(**kwargs
)