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')
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 hpercent = (baseheight / float(image.size)) wsize = int((float(image.size) * 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
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)
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
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
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:
- You provide the exact positions.
- 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 - size) / 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:
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)
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)
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()
Put watermark on your image by
img= Image.open('foobar.jpg') pil_service = PILService() pil_service.water_mark_on_image( img, "Text", "20", # percent of height "font/path", opacity=50, margin=10 )
For this feature you need to install.jpg driver in your machine. For mac use you need to run the following(using homebrew):
brew install webp
Or you can install
libwebp in Unix/Linux.
Then you need to re-install pillow. Now, run this command to convert all the files to
*.webp format in a certain directory.
DIR = "Path/To/Images" for root, dirs, files in os.walk(DIR): for file in files: infile = os.path.join(root, file) name, ext = os.path.splitext(file) try: im = Image.open(infile) im.save(os.path.join(root, name) + ".webp", "WEBP") os.remove(infile) # comment out this line if you want to keep original images except Exception as e: print(e)
Before converting to JPG/JPEG, you need to know that JPG is a lossy compression, and it can’t convert RGBA(Red, Green, Blue, Alpha). Meaning it can’t convert Alpha. So you can try like this:
im = Image.open(infile) im = im.convert('RGB') # convert RGB im.save(os.path.join(root, name) + ".jpg", "JPEG")
But above code will convert any transparent background to black. So instead you can use a white background to replace transparent part and then convert to RGB:
im = Image.open(infile) new_image = Image.new("RGBA", im.size, "WHITE") # White Image new_image.paste(im, (0, 0), im) # Setting as background im = new_image.convert('RGB') im.save(os.path.join(root, name) + ".jpg", "JPEG")
Many more methods are given in this Repo: https://github.com/ruddra/play-with-pillow
Hope it was helpful. Cheers!!!
If you like this article, you can buy me a coffee. Thanks!
Last updated: Nov 20, 2023