Created
April 20, 2012 14:55
-
-
Save valberg/2429288 to your computer and use it in GitHub Desktop.
Django create thumbnail form ImageField and save in a different ImageField - now with updating!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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) |
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)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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...