Play With Pillow
May 28, 2017 · 5 Min Read · 2 Likes · 1 CommentWho hasn’t heard PIL? It’s an image processing library made by python (Python Image Library). Pillow is an extension of it.
Installation
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 a 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 an 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[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 an image
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 an image
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 the 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()
Put watermark on your image by PILService
object’s water_mark_on_image
method:
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
)
Convert to webp
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)
Convert to JPG/JPEG
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")
And Many more
Many more methods are given in this Repo: https://github.com/ruddra/play-with-pillow
Hope it was helpful. Cheers!!!
Last updated: Nov 08, 2024
I won't spam you. Unsubscribe at any time.