PageRenderTime 43ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/thumbs.py

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