Introduction
Pillow is a free Python image library based in PIL (the official Python Image Library), born as a Git fork.
PIL only supports up to Python 2.7, and as they don’t intend to advance with the development and Pillow is continuously updated, it is always recommended to use Pillow over PIL.
Anyway, implementation for users remains almost the same for both.
But be careful, because according to the official Pillow web, I can’t have both installed in your system at the same time.
This library supports many formats such as BMP, DDS, DIB, EPS, GIF, ICNS, ICO, I.M., JPEG, JPEG 2000, MSP, PCX, PNG, PPM, SGI, SPIDER, TGA, TIFF, and many more.
Pillow works with raster images, which are arrays of pixels with information about the pixel’s location, size, or color.
The first thing we have to do is install the library to use. We have different ways to do it, but the easiest one is to type the following sentence in the command prompt (I use Windows as my O.S.):
We will use the following structure for files and folders, with the main folder containing the .py
file and a subfolder imgs
with the pictures we will use. I do it this way to see how to work with folder paths.
We have these files in our imgs
folder (We have four .png
files):
Creating .jpg Files from .png
We will write the next code in a Python console or into a .py
file:
#Importing the class Path from the module pathlib from pathlib import Path #Importing the module Image from the PIL library from PIL import Image #We create the path to our images folder #And save it in a variable imgs_path #Path.cwd() returns the current working directory #where the program .py file is. imgs_path = Path.cwd()/Path('imgs') #We use here the method glob to search for the .png files for x in imgs_path.glob('*.png'): #This with statement is not necessary but is use to ensure #the Image will be closed with Image.open(x) as im2: #x.stem returns the name of the file and we add the .jpg extension save_file_name = x.stem+'.jpg' #Create the path for the saved file save_path = imgs_path / save_file_name #We need to conver the image opened to RGB rgb_im2 = im2.convert('RGB') #Save the image with the path created before #We have pass the % of quality we want for the .jpg rgb_im2.save(save_path, quality=95)
We can see the new pictures created with our code:
Creating .png Files from .jpg
If we need to do the opposite, the code for this is very similar to the one we use before:
from pathlib import Path from PIL import Image imgs_path = Path.cwd()/Path('imgs') #We use here the method glob to search for the .jpg or jpeg files for x in imgs_path.glob('*.jp*'): with Image.open(x) as im2: #We add the .png extension save_file_name = x.stem+'.png' save_path = imgs_path / save_file_name #We donβt need to convert to RGB to save in .jpg rgb_im2 = im2.convert('RGB') im2.save(save_path, format=βpngβ)
With this code we have created the new .png files.
Working with .png Files
Let’s keep going with this tutorial, and we will see how to do some bits with PNG files.
Transparency and color.
With PNG files we can work with the opacity. Weβll see an example. The original picture:
Letβs type the following code:
from PIL import Image #We use now a picture in the same folder as our .py file img = Image.open("crown-1803689.png") #Convert the img to be sure we are in RBGA mode. #We could work now with red, green, blue and #alpha (opacity) channels img = img.convert("RGBA") new_img = [] #img.getdata() returns a sequence of tuples with RGBA data for item in img.getdata(): #if we find black color (R=0,G=0,B=0), we replace that #for the same black color but with the opacity to 0 (A=0) #in the new image we are creating. Keeping the rest of #the pixels the same. if item[0:3] == (0, 0, 0): new_img.append((0, 0, 0, 0)) else: new_img.append(item) #Put the new data in the img object img.putdata(new_img) #Save with the name we want img.save("Newcrown.png", "PNG")
With this code, we open the image, search for black colour and change that for the same black colour but with the opacity to 0 (completely transparent) and save the data in a new image.
The result is the picture I show you next:
If we want to swap the black colour for red, we only need to change this part of the code:
for item in img.getdata(): #if we find black color (R=0,G=0,B=0), we replace that #for the red color but with the opacity to 255 (A=255). if item[0:3] == (0, 0, 0): new_img.append((255, 0, 0, 255)) else: new_img.append(item)
The result is this:
Text in Images and filters
To finish this tutorial, we will see how to insert text inside a picture and other changes.
I will show you the original picture:
#We need to import ImageDraw and ImageFont and ImageFilter to insert #text in an image and apply filters from PIL import Image, ImageFont, ImageDraw, ImageFilter #Convert the image to RGBA and open it into img with Image.open("car-967387.png").convert("RGBA") as img: #To modify the image we use ImageDraw.Draw draw = ImageDraw.Draw(img) #ImageFont.truetype to define font type and size font = ImageFont.truetype("Bangers-Regular.ttf", 84) #Now add text in the picture, using coordinates, text, #color and font draw.text((20, 20),"CHEVY CAMARO",(255,255,255),font=font) draw.text((30, 30),"CHEVY CAMARO",(57,136,188),font=font) draw.text((40, 40),"CHEVY CAMARO",(0,0,0),font=font) #Apply EMBOSS filter to the car Image #We have plenty of filters to apply such as: BLUR, CONTOUR, #DETAIL, EDGE_ENHANCE, EDGE_ENHANCE_MORE, EMBOSS, FIND_EDGES, #SMOOTH, SMOOTH_MORE, SHARPEN img = img.filter(ImageFilter.EMBOSS) #Create new image with format RGBA, 600x100 size as img and #with color white and opacity 0. txt = Image.new("RGBA", (600,100), (255,255,255,0)) #New ImageDraw to work with this new image draw2 = ImageDraw.Draw(txt) #In this case we use fill to pass the color and opacity. In the first text #we use stroke_width to make that text bigger. draw2.text((0,0),"CHEVY CAMARO", fill=(0,0,0,125),font=font,stroke_width=10) draw2.text((0,0),"CHEVY CAMARO", fill=(57,136,188,125),font=font) #Apply Gaussian Blur. The image is going to be blurry txt = txt.filter(ImageFilter.GaussianBlur(radius=5)) #Turn upside down txt = txt.transpose(Image.FLIP_TOP_BOTTOM) #Paste txt in img in that position img.paste(txt, (40,140)) #save in a new file img.save('car-967387_2.png')
After running this code, the image we got is this:
Resize images (keep aspect ratio)
We can use Python and the Pillow library to reduce the size of a picture, which could be very useful if we need to send the image by email, for example
If we just chose a random new size the resulting image may be distorted.
from PIL import Image import PIL #We open the image and resize to 640x480 im = Image.open("bulb.png") im.resize((640,480),PIL.Image.BICUBIC).save("bulb_new.png")
I show you now the original picture with the new one:
The result is not what we probably expected.
If we want to keep the aspect ration (proportions) of the picture we can use the next code:
from PIL import Image import PIL #We chose the height we want for the picture new_height = 640 im = Image.open("bulb.png") #Now we need to modify the width in the same proportion as the #height. #Calculate the new height in relation to the original height height_percent = (new_height / float(im.size[1])) #Apply that % to calculate the new width new_width = int((float(im.size[0])*float(height_percent))) #Resize with the new values #We use BICUBIC because is a good balance between quality and #performance im.resize((new_width, new_height), PIL.Image.BICUBIC).save("bulb2.png")
Now we have the new image where we have kept the aspect ratio.
Conclusion
With all this we’ve seen, we’re just scratching the surface of the possibilities of the Pillow library. We can modify the size, rotate, transform in different formats, change colours and opacity, apply filters, merge pictures, etc.
I hope this will motivate you to keep investigating.
And remember, Good coding and have fun!!