Django / PIL - save thumbnail version right when image is uploaded

前端 未结 6 806
挽巷
挽巷 2021-01-30 09:39

This is my forms.py:

class UploadImageForm(forms.ModelForm):
    class Meta:
        model = UserImages
        fields = [\'photo\']

and this i

相关标签:
6条回答
  • 2021-01-30 10:00

    If you don't want to implement a solution from scratch I suggest you to use a django app called sorl-thumbnail

    0 讨论(0)
  • 2021-01-30 10:01

    there is super easier way,

    in model:

    def upload_thumb_dir(self, filename):
            path = f'path_to_thumb.jpg'
            return path
    
    thumb = ProcessedImageField(upload_to=upload_thumb_dir,
        processors=[ResizeToFill(192, 108)],
        max_length= 255,
        format='JPEG',
        default='preview.jpg',
        options={'quality': 80},
        null=True, blank=True
    )
    # ...
    def save(self, *args, **kwargs):
        self.thumb = self.rawfile.file
        super(VersionPreviews, self).save(*args, **kwargs)
    
    0 讨论(0)
  • 2021-01-30 10:04

    I wrote it based by ziiiro's answer. It works fine with Django2.2.1. Need process for save for path of image field.

    models.py

    from django.db import models
    from my.images import make_thumbnail
    
    
    class Image(models.Model):
        image = models.ImageField(upload_to='')
        thumbnail = models.ImageField(upload_to='', editable=False)
        icon = models.ImageField(upload_to='', editable=False)
    
        def save(self, *args, **kwargs):
            # save for image
            super(Image, self).save(*args, **kwargs)
    
            make_thumbnail(self.thumbnail, self.image, (200, 200), 'thumb')
            make_thumbnail(self.icon, self.image, (100, 100), 'icon')
    
            # save for thumbnail and icon
            super(Image, self).save(*args, **kwargs)
    

    my.images.py

    from django.core.files.base import ContentFile
    import os.path
    from PIL import Image
    from io import BytesIO
    
    
    def make_thumbnail(dst_image_field, src_image_field, size, name_suffix, sep='_'):
        """
        make thumbnail image and field from source image field
    
        @example
            thumbnail(self.thumbnail, self.image, (200, 200), 'thumb')
        """
        # create thumbnail image
        image = Image.open(src_image_field)
        image.thumbnail(size, Image.ANTIALIAS)
    
        # build file name for dst
        dst_path, dst_ext = os.path.splitext(src_image_field.name)
        dst_ext = dst_ext.lower()
        dst_fname = dst_path + sep + name_suffix + dst_ext
    
        # check extension
        if dst_ext in ['.jpg', '.jpeg']:
            filetype = 'JPEG'
        elif dst_ext == '.gif':
            filetype = 'GIF'
        elif dst_ext == '.png':
            filetype = 'PNG'
        else:
            raise RuntimeError('unrecognized file type of "%s"' % dst_ext)
    
        # Save thumbnail to in-memory file as StringIO
        dst_bytes = BytesIO()
        image.save(dst_bytes, filetype)
        dst_bytes.seek(0)
    
        # set save=False, otherwise it will run in an infinite loop
        dst_image_field.save(dst_fname, ContentFile(dst_bytes.read()), save=False)
        dst_bytes.close()
    
    0 讨论(0)
  • 2021-01-30 10:10

    To do this, you should add a new ImageField to your current UserImages model to hold the thumbnail, then override your the save method to create and save the thumbnail after the full image is saved.

    I've adapted the following snippet of code from one of my projects that did exactly this, I'm pretty sure this will do exactly what you need it to do:

    from cStringIO import StringIO
    import os
    
    from django.db import models
    from django.core.files.base import ContentFile
    from django.core.files.storage import default_storage as storage
    
    from PIL import Image
    
    # Thumbnail size tuple defined in an app-specific settings module - e.g. (400, 400)
    from app.settings import THUMB_SIZE
    
    class Photo(models.Model):
        """
        Photo model with automatically generated thumbnail.
        """
        photo = models.ImageField(upload_to='photos')
        thumbnail = models.ImageField(upload_to='thumbs', editable=False)
    
        def save(self, *args, **kwargs):
            """
            Make and save the thumbnail for the photo here.
            """
            super(Photo, self).save(*args, **kwargs)
            if not self.make_thumbnail():
                raise Exception('Could not create thumbnail - is the file type valid?')
    
        def make_thumbnail(self):
            """
            Create and save the thumbnail for the photo (simple resize with PIL).
            """
            fh = storage.open(self.photo.name, 'r')
            try:
                image = Image.open(fh)
            except:
                return False
    
            image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
            fh.close()
    
            # Path to save to, name, and extension
            thumb_name, thumb_extension = os.path.splitext(self.photo.name)
            thumb_extension = thumb_extension.lower()
    
            thumb_filename = thumb_name + '_thumb' + thumb_extension
    
            if thumb_extension in ['.jpg', '.jpeg']:
                FTYPE = 'JPEG'
            elif thumb_extension == '.gif':
                FTYPE = 'GIF'
            elif thumb_extension == '.png':
                FTYPE = 'PNG'
            else:
                return False    # Unrecognized file type
    
            # Save thumbnail to in-memory file as StringIO
            temp_thumb = StringIO()
            image.save(temp_thumb, FTYPE)
            temp_thumb.seek(0)
    
            # Load a ContentFile into the thumbnail field so it gets saved
            self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=True)
            temp_thumb.close()
    
            return True
    
    0 讨论(0)
  • 2021-01-30 10:14

    Probably you have forgotten save a file:

    im.save(file + ".thumbnail", "JPEG")
    

    See http://effbot.org/imagingbook/image.htm#examples

    0 讨论(0)
  • 2021-01-30 10:20

    Based on xjtian's answer. This works for Python 3:

    import os.path
    from PIL import Image
    from io import BytesIO
    from django.core.files.base import ContentFile
    from .my_app_settings import THUMB_SIZE    
    
    class Photo(models.Model):
        photo = models.ImageField(upload_to='photos')
        thumbnail = models.ImageField(upload_to='thumbs', editable=False)
    
        def save(self, *args, **kwargs):
    
            if not self.make_thumbnail():
                # set to a default thumbnail
                raise Exception('Could not create thumbnail - is the file type valid?')
    
            super(Photo, self).save(*args, **kwargs)
    
        def make_thumbnail(self):
    
            image = Image.open(self.photo)
            image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
    
            thumb_name, thumb_extension = os.path.splitext(self.photo.name)
            thumb_extension = thumb_extension.lower()
    
            thumb_filename = thumb_name + '_thumb' + thumb_extension
    
            if thumb_extension in ['.jpg', '.jpeg']:
                FTYPE = 'JPEG'
            elif thumb_extension == '.gif':
                FTYPE = 'GIF'
            elif thumb_extension == '.png':
                FTYPE = 'PNG'
            else:
                return False    # Unrecognized file type
    
            # Save thumbnail to in-memory file as StringIO
            temp_thumb = BytesIO()
            image.save(temp_thumb, FTYPE)
            temp_thumb.seek(0)
    
            # set save=False, otherwise it will run in an infinite loop
            self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=False)
            temp_thumb.close()
    
            return True
    
    0 讨论(0)
提交回复
热议问题