Creating image thumbnails in Django + Jinja2 for files uploaded to S3

FurnitureNear.Me was having some page load issues, mostly due to incredibly large images being used on our search results page, even thought we only needed thumbnail-sized pics on those pages. Yes, we could have used cloudinary, but with 150,000+ images the cost seemed excessive, and existing libraries like sorl-thumbnail aren’t written for Jinja2 and I didn’t feel like doing the port. 

I found a great solution for creating thumbnails for ImageFields, and a nice little update that works with existing ImageFields (which we had thousands of), BUT both of these solutions assumed local copies in the filesystem. Um—hello? I have a Macbook Air and barely enough HD space as is—so obviously all assets are on S3. 

What’s a girl to do, other that write a modification that pulls the image file via PIL & S3, modifies it, and uploads that magical baby-image to the cloud? 

This code also includes improvements to allow for GIFs (original only took JPEG and PNGs.)

Django create thumbnail for existing image stored on S3 (not locally) with support for JPEG, PNG, and GIF

    
class Image(models.Model):
    product = models.ForeignKey(Product, related_name='images', null=True, blank=True)
    image = models.ImageField(upload_to='product-images', max_length=256, null=True, blank=True)
    image_thumbnail = models.ImageField(upload_to='product-images', max_length=256, null=True, blank=True)
    img_type = models.CharField(max_length=256)

    def create_thumbnail(self):
        # original code for this method came from
        # http://snipt.net/danfreak/generate-thumbnails-in-django-with-pil/
        # and https://gist.github.com/valberg/2429288
        # 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
        import urllib
 
        # Set our max thumbnail size in a tuple (max width, max height)
        THUMBNAIL_SIZE = (225, 150)
 
        # Open original photo which we want to thumbnail using PIL's Image
        url = self.image.url
        try:
            file=urllib.urlopen(url) # Open the S3 image URL
            im = StringIO(file.read()) # constructs a StringIO holding the image
            image = Image.open(im) # Creates PIL Image from URL
        except:
            print 'failed on %s' %url #Sometimes it just doesn't work. Deal with it. 
            return


        PIL_TYPE = image.format
        print PIL_TYPE
 
        # Check PIL Image type to set Django Type and File Extension
        # Modified from original code to also manage GIFs
        if PIL_TYPE == 'JPEG':
            DJANGO_TYPE = 'image/jpeg'
            FILE_EXTENSION = 'jpg'
        elif PIL_TYPE == 'PNG':
            DJANGO_TYPE = 'image/png'
            FILE_EXTENSION = 'png'
        elif PIL_TYPE == 'GIF':
            DJANGO_TYPE = 'image/gif'
            FILE_EXTENSION = 'gif'
 
        # 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.image_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)
    

The Official Language of the United States

usagov:

In the last few days, we’ve gotten several searches for the “official language” of the United States.

Did you know, the United States doesn’t actually have an official language? Some states, however, do list English as their official language. 

In fact, the federal government is required to provide access and information about federal programs and federally assisted programs to people with limited English proficiency. 

Learn more

Reblogged from usagov