Pillow to Convert Image Formats Between .png and .jpg – and Work With Images

Rate this post
Pillow to Convert Image Formats .png & .jpg - and Work With Images


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))

#Put the new data in the img object 
#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))

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,

    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

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")

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
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.


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!!