-
-
Save valberg/2429288 to your computer and use it in GitHub Desktop.
# Extension of http://www.yilmazhuseyin.com/blog/dev/create-thumbnails-imagefield-django/ | |
# Note: image_folder and thumbnail_folder are both a callable (ie. a lambda that does a '/'.join()) | |
class Image(Media): | |
image = models.ImageField( | |
upload_to=image_folder | |
) | |
thumbnail = models.ImageField( | |
upload_to=thumbnail_folder, | |
max_length=500, | |
null=True, | |
blank=True | |
) | |
def create_thumbnail(self): | |
# original code for this method came from | |
# http://snipt.net/danfreak/generate-thumbnails-in-django-with-pil/ | |
# If there is no image associated with this. | |
# do not create thumbnail | |
if not self.image: | |
return | |
from PIL import Image | |
from cStringIO import StringIO | |
from django.core.files.uploadedfile import SimpleUploadedFile | |
import os | |
# Set our max thumbnail size in a tuple (max width, max height) | |
THUMBNAIL_SIZE = (99, 66) | |
DJANGO_TYPE = self.image.file.content_type | |
if DJANGO_TYPE == 'image/jpeg': | |
PIL_TYPE = 'jpeg' | |
FILE_EXTENSION = 'jpg' | |
elif DJANGO_TYPE == 'image/png': | |
PIL_TYPE = 'png' | |
FILE_EXTENSION = 'png' | |
# Open original photo which we want to thumbnail using PIL's Image | |
image = Image.open(StringIO(self.image.read())) | |
# We use our PIL Image object to create the thumbnail, which already | |
# has a thumbnail() convenience method that contrains proportions. | |
# Additionally, we use Image.ANTIALIAS to make the image look better. | |
# Without antialiasing the image pattern artifacts may result. | |
image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS) | |
# Save the thumbnail | |
temp_handle = StringIO() | |
image.save(temp_handle, PIL_TYPE) | |
temp_handle.seek(0) | |
# Save image to a SimpleUploadedFile which can be saved into | |
# ImageField | |
suf = SimpleUploadedFile(os.path.split(self.image.name)[-1], | |
temp_handle.read(), content_type=DJANGO_TYPE) | |
# Save SimpleUploadedFile into image field | |
self.thumbnail.save( | |
'%s_thumbnail.%s' % (os.path.splitext(suf.name)[0], FILE_EXTENSION), | |
suf, | |
save=False | |
) | |
def save(self, *args, **kwargs): | |
self.create_thumbnail() | |
force_update = False | |
# If the instance already has been saved, it has an id and we set | |
# force_update to True | |
if self.id: | |
force_update = True | |
# Force an UPDATE SQL query if we're editing the image to avoid integrity exception | |
super(Image, self).save(force_update=force_update) |
Here is a ready-to-use django library that works the way your snippet does:
https://github.com/skitoo/django-thumbs
Not sure about updates though
For python 3 support replace StringIO with BytesIO
from io import BytesIO
self.image.read()
in line 44, sets the pointer to the last byte and causes a problem with Google storage multipart upload, so you can set seek(0).
google storage error: ValueError: Size 266518 was specified but the file-like object only had 0 bytes remaining.
add this at line 45
self.image_file.seek(0)
If anyone has a better solution really like to hear...
You can use this method for creating thumbnail image:
from PIL import Image
from django.db.models.fields.files import ImageFieldFile
from django.core.files.uploadedfile import InMemoryUploadedFile
def _create_thumbnail(image_field: ImageFieldFile, thumbnail_image_field: ImageFieldFile, size: tuple):
image = Image.open(image_field.file.file)
image.thumbnail(size=size)
image_file = BytesIO()
image.save(image_file, image.format)
thumbnail_image_field.save(
image_field.name,
InMemoryUploadedFile(
image_file,
None, '',
image_field.file.content_type,
image.size,
image_field.file.charset,
),
save=False
)
Django extracts the content-type from the extension of the given filename, not the content_type
parameter of SimpleUploadedFile
. So, you might as well use the normal ContentFile
.
I ended up using the following:
def resize(self, geom):
from PIL import Image
img = Image.open(self.image.path)
img.thumbnail(geom)
def image_to_byte_array(img):
byte_arr = io.BytesIO()
img.save(byte_arr, format=img.format)
byte_arr = byte_arr.getvalue()
return byte_arr
img_byte = image_to_byte_array(img)
img_file = ContentFile(img_byte)
new_res = Resource()
old_filename = os.path.split(self.image.name)[-1]
new_res.image.save(old_filename,img_file,save=False)
return new_res
In 2024 this seems to work fine:
def create_thumbnail(self):
if not self.image:
return
image = Image.open(self.image)
image.thumbnail((800, 800))
image_file = BytesIO()
image.save(image_file, image.format)
self.thumb.save(
self.image.name,
InMemoryUploadedFile(
image_file,
None,
None,
self.image.file.content_type,
image_file.tell(),
self.image.file.charset,
),
save=False,
)
def save(self, *args, **kwargs):
self.create_thumbnail()
return super().save(*args, **kwargs)
Reached this snippet from google, what if I upload a .gif image here ? :B