Play With Pillow

Who hasn't heard PIL? It's an image processing library made by python (Python Image Library). Pillow is an extension of it.

So installing pillow is really easy:

pip install pillow

Now we are going to do some image processing cool stuff:

First Load Image:

from PIL import Image, ImageOps

img = Image.open('image.png')  

Resize Image

Suppose We want to resize an image and maintain its aspect ratio. Here we need to get the aspect ratio after resizing. Here is a snippet for it:

   def get_resize_image_size(image, baseheight=None):
        """
        Get resize image size
        """
        size = 1200, 1200
        print("Getting resize image size")
        if not baseheight:
            baseheight = size[1]
        hpercent = (baseheight / float(image.size[1]))
        wsize = int((float(image.size[0]) * float(hpercent)))
        return wsize, baseheight

Or we may want to our desired image size.

After we get the desired aspect ratio, now we resize it with the following code:

def resize_image(img, size=None):  
    """
    Resize Image
    img: Image file opened by PIL
    size: if Size not given, it will be 
    calculated 
    """
    print("Resizing image")
    if not size:
       size = get_resize_image_size(img)
    img = img.resize(size, Image.ANTIALIAS)
    return img

Crop Image in Box Shape

When we try to crop, we can either give it positions for cropping or we can calculate the points, which will be used in cropping. Suppose we have a random image, but we want to crop it in middle position and we want to crop in such way that, we will only take out 1200x1200 size out of the sample image, the following is the code:

    def crop_position(image):
        """
        Get Crop Image Positions
        """
        print("Getting Crop Image Positions")
        width, height = image.size
        new_width, new_height = 1200, 1200
        left = (width - new_width) / 2
        top = (height - new_height) / 2
        right = (width + new_width) / 2
        bottom = (height + new_height) / 2
        return left, top, right, bottom

Now we got the position, lets do cropping:

def crop_image(img, positions=None):  
   """
   Crop Image in Box Shape
   """
   if not positions:
       positions = crop_position(img)
   return img.crop(box=positions)

Resize Image and Crop in Center to Convert it to a Fixed Size

Let's take an image in size and convert it to 1200x1200 image:

   def convert_image(pil_image):
        """
        Resize Image and Crop in Center to Convert it to a Fixed Size
        """
        try:
            if pil_image.size == self.size:
                print("Nothing to change, returning image")
                return image
            # Resize to size given in settings
            pil_image = resize_image(pil_image)
            # Cropping to adjust size given in settings
            pil_image = crop_image(pil_image)
            pil_image.save(path)
        except (KeyError, Exception) as exp:
            print(str(exp))
            raise exp

Paste Image over Background Image

The following code will do the trick:

    def add_overlay_over_background(background_image, overlay_image, offset=(0, 0)):
        """
        Add overlay image over background image
        """
        background_image.paste(overlay_image, offset, mask=overlay_image)
        return background_image

Draw Text over Image

For that, we first we need fonts:

    path = 'path/to/font'
    def get_font(size):
        """
        Get Font Object
        """
        return ImageFont.truetype(path, size=size)

Then we need to co-ordinates where the texts will be written:

Here are two scenarios:

  1. You provide the exact positions.
  2. You can provide the height of the text position, we will calculate where the texts will be printed in the image. Here we are assuming that texts will be aligned in middle horizontally. It will be symmetric in perspective middle vertical line.
    def process_text_coordination(position, font=None, vertical_only=False, text=None):
        """
        Process Co-Ordination of the position
        """
        if vertical_only:
            # Case Two
            size = font.getsize(text)
            width = (self.size[0] - size[0]) / 2
            return width, position
       # Case One
       return position

Now we got everything, so let's do writing text on image:

    def write_text_on_image(image, font, text,position, color, size, vertical_only=False):
        """
        Write Text over Image
        """
        draw = ImageDraw.Draw(image)
        font = get_font(size)
        position = process_text_coordination(
            position, font, vertical_only, text
        )
        draw.text(position, text, font=font, fill=color)
        return image

BTW, here color can be hexa value of the color you want to use. For white, you need use: #fffff

Adjast brightness of Images

Let's lighten or darken image based on amount:

    def darken_or_lighten_pixels(image, amount=0.5):
        """
        Enhance Image
        """
        converter = ImageEnhance.Brightness(image)
        return converter.enhance(amount)

Adjast color of images

Let's adjust color of image based on amount

    def add_color_saturation(image, amount=0.5):
        """
        Color saturation
        """
        converter = ImageEnhance.Color(image)
        return converter.enhance(amount)

Save PIL Image in Django Models or Serve as Django File

This code will convert PIL Images to Content file:

    def process_django_file(pil_image, name, format='png'):
        """
        Process the PIL file to Django File
        """
        file_object = BytesIO()
        pil_image.save(file_object, format=format)
        content = file_object.getvalue()
        return ContentFile(content, name=name)

And saving image will be damn easy:

pil_image = Image.open('image.png')

content_file = process_django_file(pil_image, name="some name", format='png')

my_model.image = content_file  
my_model.save()  

And many more methods are given in the following Repo:

https://github.com/ruddra/play-with-pillow

Hope it was helpful. Cheers!!!

comments powered by Disqus