There's more

As a bonus, we will see an example of how to generate a thumbnail out of the uploaded image. In many cases, it is sufficient to use a third-party solution such as sorl-thumbnail to generate thumbnails from the template layer, based on the original image. Using this technique, however, you could generate and store specific versions of the image for later use, such as the list version, mobile version, and desktop computer version.

We will add three main methods to the InspirationalQuote model (quotes/models.py). They are save(), create_thumbnail(), and get_thumbnail_picture_url(). Some helper functions are used by these to get_picture_paths(), get_square_crop_points() and get_centering_points() when creating the thumbnail.

When the model is being saved, we will trigger the thumbnail creation. When we need to show the thumbnail in a template, we can get its URL using {{ quote.get_thumbnail_picture_url }}. The method definitions are as follows:

# quotes/models.py
import os
from PIL import Image

from django.conf import settings
from django.core.files.storage import default_storage as storage
from django.db import models
from django.utils.timezone import now as timezone_now
from django.utils.translation import ugettext_lazy as _


THUMBNAIL_SIZE = getattr(settings, "QUOTES_THUMBNAIL_SIZE", 50)
THUMBNAIL_EXT = getattr(settings, "QUOTES_THUMBNAIL_EXT", None)


def get_square_crop_points(image):
width, height = image.size
target = width if width > height else height
upper, lower = get_centering_points(height, target)
left, right = get_centering_points(width, target)
return left, upper, right, lower


def get_centering_points(size, target):
delta = size - target
start = int(delta) / 2
end = start + target
return start, end

# ...

class InspirationalQuote(models.Model):
# ...

def save(self, *args, **kwargs):
super().save(*args, **kwargs)
self.create_thumbnail()

def create_thumbnail(self):
if not self.picture:
return False
picture_path, thumbnail_path = self.get_picture_paths()
if thumbnail_path and not storage.exists(thumbnail_path):
try:
picture_file = storage.open(picture_path, "r")
image = Image.open(picture_file)
image = image.crop(get_square_crop_points(image))
image = image.resize((THUMBNAIL_SIZE,
THUMBNAIL_SIZE),
Image.ANTIALIAS)

image.save(thumbnail_path)
except (IOError, KeyError, UnicodeDecodeError):
return False

return True

def get_thumbnail_picture_url(self):
url = ""
picture_path, thumbnail_path = self.get_picture_paths()

if thumbnail_path:
url = (storage.url(thumbnail_path)
if storage.exists(thumbnail_path)
else self.picture.url)

return url


def get_picture_paths(self):
picture_path = None
thumb_path = None

if self.picture:
picture_path = self.picture.name
filename_base, filename_ext = os.path.splitext(
picture_path)

if THUMBNAIL_EXT:
filename_ext = THUMBNAIL_EXT
thumb_path = f"{filename_base}_thumbnail{filename_ext}"

return picture_path, thumb_path

def __str__(self):
return self.quote

In the preceding methods, we are using the file storage API instead of directly juggling the filesystem, as we could then exchange the default storage with Amazon S3 buckets or other storage services and the methods will still work.

How does the creation of the thumbnail work? If we had the original file saved as quotes/2014/04/20140424140000.png, we are making sure that the quotes/2014/04/20140424140000_thumbnail.png file doesn't exist and, in that case, we are opening the original image, cropping it to a square from the center, resizing it to 50 x 50 pixels, and saving it to the storage. We can supply a QUOTES_THUMBNAIL_SIZE setting to change the resizing behavior, and we can set QUOTES_THUMBNAIL_EXT to a specific image file extension (such as ".jpg") to change the format used when saving the thumbnail.

The get_thumbnail_picture_url() method checks whether the thumbnail version exists in the storage and returns its URL. If the thumbnail version does not exist, the URL of the original image is returned as a fallback.

In this example, we only dealt with changing image size, but a more sophisticated solution might take in additional input to make changes to the center point, alter colors, or apply other effects, and much more.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.69.143