##// END OF EJS Templates
Added tag 4.6.0 for changeset 0b571b3a99ef
Added tag 4.6.0 for changeset 0b571b3a99ef

File last commit:

r1819:1bcad2dd default
r1956:84d0ebaa default
Show More
thumbs.py
217 lines | 7.4 KiB | text/x-python | PythonLexer
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 # -*- encoding: utf-8 -*-
"""
django-thumbs by Antonio Melé
http://django.es
"""
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452 from django.core.files.images import ImageFile
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 from django.db.models import ImageField
from django.db.models.fields.files import ImageFieldFile
from PIL import Image
from django.core.files.base import ContentFile
neko259
Moving neboard to python3 support (no python2 for now until we figure out how...
r765 import io
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22
neko259
Added user to the posts. This refs #12
r113
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 def generate_thumb(img, thumb_size, format):
"""
Generates a thumbnail image and returns a ContentFile object with the thumbnail
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 Parameters:
===========
img File object
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 thumb_size desired thumbnail size, ie: (200,120)
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 format format of the original image ('jpeg','gif','png',...)
(this format will be used for the generated thumbnail, too)
"""
neko259
Added user to the posts. This refs #12
r113
neko259
Raise an error whena decompression bomb is launched to the thumbs generator
r1819 Image.warnings.simplefilter('error', Image.DecompressionBombWarning)
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 img.seek(0) # see http://code.djangoproject.com/ticket/8222 for details
image = Image.open(img)
neko259
Added user to the posts. This refs #12
r113
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 # get size
thumb_w, thumb_h = thumb_size
# If you want to generate a square thumbnail
if thumb_w == thumb_h:
# quad
xsize, ysize = image.size
# get minimum size
neko259
Added user to the posts. This refs #12
r113 minsize = min(xsize, ysize)
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 # largest square possible in the image
neko259
Added user to the posts. This refs #12
r113 xnewsize = (xsize - minsize) / 2
ynewsize = (ysize - minsize) / 2
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 # crop it
neko259
Added user to the posts. This refs #12
r113 image2 = image.crop(
(xnewsize, ynewsize, xsize - xnewsize, ysize - ynewsize))
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452 # load is necessary after crop
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 image2.load()
# thumbnail of the cropped image (with ANTIALIAS to make it look better)
image2.thumbnail(thumb_size, Image.ANTIALIAS)
else:
# not quad
image2 = image
image2.thumbnail(thumb_size, Image.ANTIALIAS)
neko259
Added user to the posts. This refs #12
r113
neko259
Fixed image decoding with the new python3 IO module
r767 output = io.BytesIO()
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 # PNG and GIF are the same, JPG is JPEG
neko259
Added user to the posts. This refs #12
r113 if format.upper() == 'JPG':
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 format = 'JPEG'
neko259
Added user to the posts. This refs #12
r113
neko259
Fixed image decoding with the new python3 IO module
r767 image2.save(output, format)
return ContentFile(output.getvalue())
neko259
Added user to the posts. This refs #12
r113
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22
class ImageWithThumbsFieldFile(ImageFieldFile):
"""
See ImageWithThumbsField for usage example
"""
neko259
Added user to the posts. This refs #12
r113
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 def __init__(self, *args, **kwargs):
super(ImageWithThumbsFieldFile, self).__init__(*args, **kwargs)
self.sizes = self.field.sizes
neko259
Added user to the posts. This refs #12
r113
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 if self.sizes:
def get_size(self, size):
if not self:
return ''
else:
neko259
Added user to the posts. This refs #12
r113 split = self.url.rsplit('.', 1)
thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 return thumb_url
neko259
Added user to the posts. This refs #12
r113
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 for size in self.sizes:
neko259
Added user to the posts. This refs #12
r113 (w, h) = size
setattr(self, 'url_%sx%s' % (w, h), get_size(self, size))
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 def save(self, name, content, save=True):
super(ImageWithThumbsFieldFile, self).save(name, content, save)
neko259
Added user to the posts. This refs #12
r113
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 if self.sizes:
for size in self.sizes:
neko259
Added user to the posts. This refs #12
r113 (w, h) = size
split = self.name.rsplit('.', 1)
thumb_name = '%s.%sx%s.%s' % (split[0], w, h, split[1])
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 # you can use another thumbnailing function if you like
thumb_content = generate_thumb(content, size, split[1])
neko259
Added user to the posts. This refs #12
r113
thumb_name_ = self.storage.save(thumb_name, thumb_content)
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 if not thumb_name == thumb_name_:
neko259
Added user to the posts. This refs #12
r113 raise ValueError(
'There is already a file named %s' % thumb_name)
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 def delete(self, save=True):
neko259
Added user to the posts. This refs #12
r113 name = self.name
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 super(ImageWithThumbsFieldFile, self).delete(save)
if self.sizes:
for size in self.sizes:
neko259
Added user to the posts. This refs #12
r113 (w, h) = size
split = name.rsplit('.', 1)
thumb_name = '%s.%sx%s.%s' % (split[0], w, h, split[1])
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 try:
self.storage.delete(thumb_name)
except:
pass
neko259
Added user to the posts. This refs #12
r113
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 class ImageWithThumbsField(ImageField):
attr_class = ImageWithThumbsFieldFile
"""
Usage example:
==============
photo = ImageWithThumbsField(upload_to='images', sizes=((125,125),(300,200),)
To retrieve image URL, exactly the same way as with ImageField:
my_object.photo.url
To retrieve thumbnails URL's just add the size to it:
my_object.photo.url_125x125
my_object.photo.url_300x200
Note: The 'sizes' attribute is not required. If you don't provide it,
ImageWithThumbsField will act as a normal ImageField
How it works:
=============
For each size in the 'sizes' atribute of the field it generates a
thumbnail with that size and stores it following this format:
available_filename.[width]x[height].extension
Where 'available_filename' is the available filename returned by the storage
backend for saving the original file.
Following the usage example above: For storing a file called "photo.jpg" it saves:
photo.jpg (original file)
photo.125x125.jpg (first thumbnail)
photo.300x200.jpg (second thumbnail)
With the default storage backend if photo.jpg already exists it will use these filenames:
photo_.jpg
photo_.125x125.jpg
photo_.300x200.jpg
Note: django-thumbs assumes that if filename "any_filename.jpg" is available
filenames with this format "any_filename.[widht]x[height].jpg" will be available, too.
To do:
======
Add method to regenerate thubmnails
neko259
Added initial database migration. Added south support. This fixes #41
r114
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22
"""
neko259
Added user to the posts. This refs #12
r113
neko259
Added image duplicate check
r527 preview_width_field = None
preview_height_field = None
neko259
Added user to the posts. This refs #12
r113 def __init__(self, verbose_name=None, name=None, width_field=None,
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452 height_field=None, sizes=None,
preview_width_field=None, preview_height_field=None,
**kwargs):
neko259
Added user to the posts. This refs #12
r113 self.verbose_name = verbose_name
self.name = name
self.width_field = width_field
self.height_field = height_field
neko259
Added images upload. Changed the design a bit. Reformatted some code by PEP 8. Changed the urls: not the main site is located at /, not /boards/.
r22 self.sizes = sizes
neko259
Added initial database migration. Added south support. This fixes #41
r114 super(ImageField, self).__init__(**kwargs)
neko259
Saving image thumbnails size to the database and using this size in the HTML
r452 if sizes is not None and len(sizes) == 1:
self.preview_width_field = preview_width_field
self.preview_height_field = preview_height_field
def update_dimension_fields(self, instance, force=False, *args, **kwargs):
"""
Update original image dimension fields and thumb dimension fields
(only if 1 thumb size is defined)
"""
super(ImageWithThumbsField, self).update_dimension_fields(instance,
force, *args,
**kwargs)
thumb_width_field = self.preview_width_field
thumb_height_field = self.preview_height_field
if thumb_width_field is None or thumb_height_field is None \
or len(self.sizes) != 1:
return
original_width = getattr(instance, self.width_field)
original_height = getattr(instance, self.height_field)
if original_width > 0 and original_height > 0:
thumb_width, thumb_height = self.sizes[0]
w_scale = float(thumb_width) / original_width
h_scale = float(thumb_height) / original_height
scale_ratio = min(w_scale, h_scale)
if scale_ratio >= 1:
thumb_width_ratio = original_width
thumb_height_ratio = original_height
else:
thumb_width_ratio = int(original_width * scale_ratio)
thumb_height_ratio = int(original_height * scale_ratio)
setattr(instance, thumb_width_field, thumb_width_ratio)
neko259
Raise an error whena decompression bomb is launched to the thumbs generator
r1819 setattr(instance, thumb_height_field, thumb_height_ratio)