PageRenderTime 113ms CodeModel.GetById 60ms app.highlight 13ms RepoModel.GetById 38ms app.codeStats 0ms

/thumbs.py

http://django-thumbs.googlecode.com/
Python | 163 lines | 147 code | 2 blank | 14 comment | 1 complexity | 957bc387c5590ddfd63fe7485da86474 MD5 | raw file
  1# -*- encoding: utf-8 -*-
  2"""
  3django-thumbs by Antonio MelĂŠ
  4http://django.es
  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
 11
 12def generate_thumb(img, thumb_size, format):
 13    """
 14    Generates a thumbnail image and returns a ContentFile object with the thumbnail
 15    
 16    Parameters:
 17    ===========
 18    img         File object
 19    
 20    thumb_size  desired thumbnail size, ie: (200,120)
 21    
 22    format      format of the original image ('jpeg','gif','png',...)
 23                (this format will be used for the generated thumbnail, too)
 24    """
 25    
 26    img.seek(0) # see http://code.djangoproject.com/ticket/8222 for details
 27    image = Image.open(img)
 28    
 29    # Convert to RGB if necessary
 30    if image.mode not in ('L', 'RGB', 'RGBA'):
 31        image = image.convert('RGB')
 32        
 33    # get size
 34    thumb_w, thumb_h = thumb_size
 35    # If you want to generate a square thumbnail
 36    if thumb_w == thumb_h:
 37        # quad
 38        xsize, ysize = image.size
 39        # get minimum size
 40        minsize = min(xsize,ysize)
 41        # largest square possible in the image
 42        xnewsize = (xsize-minsize)/2
 43        ynewsize = (ysize-minsize)/2
 44        # crop it
 45        image2 = image.crop((xnewsize, ynewsize, xsize-xnewsize, ysize-ynewsize))
 46        # load is necessary after crop                
 47        image2.load()
 48        # thumbnail of the cropped image (with ANTIALIAS to make it look better)
 49        image2.thumbnail(thumb_size, Image.ANTIALIAS)
 50    else:
 51        # not quad
 52        image2 = image
 53        image2.thumbnail(thumb_size, Image.ANTIALIAS)
 54    
 55    io = cStringIO.StringIO()
 56    # PNG and GIF are the same, JPG is JPEG
 57    if format.upper()=='JPG':
 58        format = 'JPEG'
 59    
 60    image2.save(io, format)
 61    return ContentFile(io.getvalue())    
 62
 63class ImageWithThumbsFieldFile(ImageFieldFile):
 64    """
 65    See ImageWithThumbsField for usage example
 66    """
 67    def __init__(self, *args, **kwargs):
 68        super(ImageWithThumbsFieldFile, self).__init__(*args, **kwargs)
 69        
 70        if self.field.sizes:
 71            def get_size(self, size):
 72                if not self:
 73                    return ''
 74                else:
 75                    split = self.url.rsplit('.',1)
 76                    thumb_url = '%s.%sx%s.%s' % (split[0],w,h,split[1])
 77                    return thumb_url
 78                    
 79            for size in self.field.sizes:
 80                (w,h) = size
 81                setattr(self, 'url_%sx%s' % (w,h), get_size(self, size))
 82                
 83    def save(self, name, content, save=True):
 84        super(ImageWithThumbsFieldFile, self).save(name, content, save)
 85        
 86        if self.field.sizes:
 87            for size in self.field.sizes:
 88                (w,h) = size
 89                split = self.name.rsplit('.',1)
 90                thumb_name = '%s.%sx%s.%s' % (split[0],w,h,split[1])
 91                
 92                # you can use another thumbnailing function if you like
 93                thumb_content = generate_thumb(content, size, split[1])
 94                
 95                thumb_name_ = self.storage.save(thumb_name, thumb_content)        
 96                
 97                if not thumb_name == thumb_name_:
 98                    raise ValueError('There is already a file named %s' % thumb_name)
 99        
100    def delete(self, save=True):
101        name=self.name
102        super(ImageWithThumbsFieldFile, self).delete(save)
103        if self.field.sizes:
104            for size in self.field.sizes:
105                (w,h) = size
106                split = name.rsplit('.',1)
107                thumb_name = '%s.%sx%s.%s' % (split[0],w,h,split[1])
108                try:
109                    self.storage.delete(thumb_name)
110                except:
111                    pass
112                        
113class ImageWithThumbsField(ImageField):
114    attr_class = ImageWithThumbsFieldFile
115    """
116    Usage example:
117    ==============
118    photo = ImageWithThumbsField(upload_to='images', sizes=((125,125),(300,200),)
119    
120    To retrieve image URL, exactly the same way as with ImageField:
121        my_object.photo.url
122    To retrieve thumbnails URL's just add the size to it:
123        my_object.photo.url_125x125
124        my_object.photo.url_300x200
125    
126    Note: The 'sizes' attribute is not required. If you don't provide it, 
127    ImageWithThumbsField will act as a normal ImageField
128        
129    How it works:
130    =============
131    For each size in the 'sizes' atribute of the field it generates a 
132    thumbnail with that size and stores it following this format:
133    
134    available_filename.[width]x[height].extension
135
136    Where 'available_filename' is the available filename returned by the storage
137    backend for saving the original file.
138    
139    Following the usage example above: For storing a file called "photo.jpg" it saves:
140    photo.jpg          (original file)
141    photo.125x125.jpg  (first thumbnail)
142    photo.300x200.jpg  (second thumbnail)
143    
144    With the default storage backend if photo.jpg already exists it will use these filenames:
145    photo_.jpg
146    photo_.125x125.jpg
147    photo_.300x200.jpg
148    
149    Note: django-thumbs assumes that if filename "any_filename.jpg" is available 
150    filenames with this format "any_filename.[widht]x[height].jpg" will be available, too.
151    
152    To do:
153    ======
154    Add method to regenerate thubmnails
155    
156    """
157    def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, sizes=None, **kwargs):
158        self.verbose_name=verbose_name
159        self.name=name
160        self.width_field=width_field
161        self.height_field=height_field
162        self.sizes = sizes
163        super(ImageField, self).__init__(**kwargs)