Learning Outcomes

  • To learn how to convert a single image into different image formats such as .png, .jpg and .Webp
  • To learn how to convert multiple .png & .jpg images within the current working directory into .Webp images.
  • To Learn how to combine image resizing & converting images into the .Webp format.

With the rise of recommended speed changes from Google including Web Vitals, its crucial that your website or web application is able to serve better image formats.

In this tutorial, you’ll learn how to convert image formats into next-generation formats using Python.


What Are Next Generation Image Formats And Why Are They Important?

Next generation image formats include:

  • JPEG 2000
  • JPEG XR
  • WebP

All of the above formats have better compression and are higher in quality when compared to their previous PNG and JPEG counterparts.

Encoding your images into one of the above formats ensures that your images will use less data, cost you less money and ensures your applications load faster for your users.


Check Browser Compatibility

Currently there isn’t true browser support for all of the next-generation image formats, therefore it’s recommended that you provide either a fallback JPEG or PNG image for older browsers.


Module Imports

from PIL import Image
import PIL
import os
import glob
Image
# <module 'PIL.Image' from '/opt/anaconda3/lib/python3.7/site-packages/PIL/Image.py'>

You can easily load an image from a file, using the open() found within the Image module:


image = image.open('image-filepath.png')
image.show()

Image Conversions In Python

You can convert an image into a different format by:

  • Opening the image.
  • Converting the image to RGB colour.
  • Saving the image as a different file.

# 1. Open The Image:
image = Image.open('example.jpg')

# 2. Convert the image to RGB Colour:
image = image.convert('RGB')

# 3. Save The Image:
image.save('example-test.png', 'png')

Extra Information About The Functions:

Image.convert() returns a converted image copy. For the “P” mode, the method translates pixels through the palette. However, if mode is omitted, a mode is chosen so that all information in the image and the palette is represented without a palette.

The Image.save() requires two arguments, the first one is the file path (or file name) and the second one is the file format that you would like to save the image as.


Common Image Conversions In Python

Let’s practice some common image conversions using the Pillow Library!

!ls
changing-image-types-and-next-generation-formats.ipynb
example-1.png
example-2.jpg

PNG to JPG

image = Image.open('example-1.png')
image = image.convert('RGB')
image.save('new-image.jpg', 'jpeg')

JPG to PNG

image = Image.open('example-2.jpg')
image = image.convert('RGB')
image.save('new-image.png', 'png')

If you check your current working directory, you’ll now see two extra images:

converting images in python

PNG to WebP

image = Image.open('example-1.png')
image = image.convert('RGB')
image.save('new-format-image-from-png.webp', 'webp')

JPG to WebP

image = Image.open('example-2.jpg')
image = image.convert('RGB')
image.save('new-format-image-from-jpeg.webp', 'webp')

WebP to PNG

image = Image.open('new-format-image-from-png.webp')
image = image.convert('RGB')
image.save('converting-from-webp-to-png-format.png', 'png')

WebP to JPG

image = Image.open('new-format-image-from-png.webp')
image = image.convert('RGB')
image.save('converting-from-webp-to-jpg-format.jpg', 'jpeg')

converting from Webp formats to older formats

Converting All The Images In Your Current Working Directory Into .WebP Format

Let’s create a python function which will convert any .png or .jpeg files from the current working directory into .webp images!

files = os.listdir() # We list all of the files and folders using os.listdir()
print(f"These are all of the files in our current working directory: {files}")

These are all of the files in our current working directory: ['.DS_Store', 'converting-from-webp-to-png-format.png', 'new-format-image-from-png.webp', 'converting-from-webp-to-jpg-format.jpg', 'new-format-image-from-jpeg.webp', '.ipynb_checkpoints', 'example-1.png', 'new-image.jpg', 'example-2.jpg', 'new-image.png', 'changing-image-types-and-next-generation-formats.ipynb']

We will also filter to only retrieve files ending in jpg or png:

images = [file for file in files if file.endswith(('jpg', 'png'))]
print(f"These are all of the images in our current working directory {images}")

These are all of the images in our current working directory ['converting-from-webp-to-png-format.png', 'converting-from-webp-to-jpg-format.jpg', 'example-1.png', 'new-image.jpg', 'example-2.jpg', 'new-image.png']

# Defining a Python user-defined exception
class Error(Exception):
    """Base class for other exceptions"""
    pass
def convert_image(image_path, image_type):

    # 1. Opening the image:
    im = Image.open(image_path)
    # 2. Converting the image to RGB colour:
    im = im.convert('RGB')
    # 3. Spliting the image path (to avoid the .jpg or .png being part of the image name):
    image_name = image_path.split('.')[0]
    print(f"This is the image name: {image_name}")

    # Saving the images based upon their specific type:
    if image_type == 'jpg' or image_type == 'png':
        im.save(f"Converted-to-next-gen-format-{image_name}.webp", 'webp')
    else:
        # Raising an error if we didn't get a jpeg or png file type!
        raise Error
for image in images:
    if image.endswith('jpg'):
        convert_image(image, image_type='jpg')
    elif image.endswith('png'):
        convert_image(image, image_type='png')
    else:
        raise Error
This is the image name: converting-from-webp-to-png-format
This is the image name: converting-from-webp-to-jpg-format
This is the image name: example-1
This is the image name: new-image
This is the image name: example-2
This is the image name: new-image

# Deleting any files that contain the sring Converted
[os.remove(file) for file in os.listdir() if 'Converted' in file]
[None, None, None, None, None]

After learning how to convert multiple .jpg or .png files into .webp files, with a list comprehension expression we can also execute the convert_image functions one by one:

[convert_image(image, image_type='jpg') if image.endswith('jpg') else
 convert_image(image, image_type='png') for image in images]

This is the image name: converting-from-webp-to-png-format
This is the image name: converting-from-webp-to-jpg-format
This is the image name: example-1
This is the image name: new-image
This is the image name: example-2
This is the image name: new-image
[None, None, None, None, None, None] # Notice how the function doesn't return anything, therefore we get a list of None objects back, however the function has still executed!!!

Deleting All Of The Files Created:

string_matches = ['Converted', 'converting', 'new']
for file in os.listdir():
    if any(x in file for x in string_matches):
        os.remove(file)
!ls
changing-image-types-and-next-generation-formats.ipynb
example-1.png
example-2.jpg

Combining Image Resizing With Converting Images To .Webp

As a final task, let’s slightly change the convert_image function so that it automatically detects the image size.

  • If the image is above 600px in width, we’ll set the a custom width and will dynamically re-size it before converting it into a .Webp image.
def convert_image(image_path, image_type, custom_size=300):
    # 1. Opening the image:
    im = Image.open(image_path)
    # 2. Converting the image to RGB colour:
    im = im.convert('RGB')
    # 3. Spliting the image path (to avoid the .jpg or .png being part of the image name):
    image_name = image_path.split('.')[0]
    print(f"This is the image name: {image_name}")

    # Saving the images based upon their specific type:
    if image_type == 'jpg' or image_type == 'png':
        if im.size[0] > 600:
            im.thumbnail(size=((custom_size, custom_size)))
            im.save(f"Converted-to-next-gen-format-{image_name}.webp", 'webp')
        else:
            im.save(f"Converted-to-next-gen-format-{image_name}.webp", 'webp')
    else:
        # Raising an error if we didn't get a jpeg or png file type!
        raise Error
images = [file for file in os.listdir() if file.endswith(('jpg', 'png'))]
[convert_image(image, image_type='jpg', custom_size=200) if image.endswith('jpg') else
convert_image(image, image_type='png', custom_size=200) for image in images]

This is the image name: example-1
This is the image name: example-2
[None, None]

Deleting All Of The Files Created:

string_matches = ['Converted', 'converting', 'new']
for file in os.listdir():
    if any(x in file for x in string_matches):
        os.remove(file)

Pillow is a great image processing library and by combining image compression with resizing and next-generation image formats, you’ll be able to create high quality imagery without sacrificing on user experience.