1. Introduction — Why Convert to WebP?
I recently optimized my website’s mobile performance and found that images were the main bottleneck. The PNGs and JPGs are putting great pressure on the mobile processing of mobile users which may cause laggy in your website browsing.
But as there are so many images to process, it’s impossible to convert them one by one.
So I wrote a Python command-line tool to batch convert JPG/PNG images into WebP while keeping the original directory structure.
And don’t worry, it’s just a very simple python script.And of course I’ll try my best to get all the main points across clearly.
2. preparations
To make sure the tool work, you have to get:
- a python editor(VS code, Pycharm, etc)
- python 3.x
- appropriate dependencies for our little project
ATTENTION please! In this little project, only an extra dependency is needed:pillow (helpful in image processing)
And I suggest that you finish your project in an independent environment managed through Anaconda which can make it easier to manage all the de[endencies, no matter download or delete.
To download this dependency, just type in your terminal(cmd):
pip install pillow
#if your choose to manage your items and projects through anaconda and hava an independent environment
#before the line, make sure your environment is activated!
conda install pillow3. How does the script works?
I’ll try my best to explain all the lines of the full script down below.
3.1 imports
- argparse: design client-friendly command lines to execute
- Path from pathlib: read and process the path of images
- Image from Python Image Library: processing the images
3.2 convert_image_to_webp
This function handles the conversion of one image file (JPG/PNG) into a WebP file.
It is the smallest and most essential building block of the entire batch converter.
def convert_image_to_webp(src_path: Path, dst_path: Path, quality: int = 85):
try:
with Image.open(src_path) as img:
img.save(dst_path, format="WEBP", quality=quality)
print(f"[OK] {src_path} -> {dst_path}")
except Exception as e:
print(f"[ERROR] Failed to convert {src_path}: {e}")src_path: the source image file (JPG/PNG)dst_path: where the.webpfile will be savedquality: WebP compression quality (0–100, default85)(just feel free to adjust the quality in your need)with Image.open(src_path) as img:Pillow loads the image and keeps it in memory;withensures the file is safely closed after useimg.save(dst_path, format="WEBP", quality=quality):save the imgs as .webp with quality ofqualityindst_path
And the two print()s can remind you whether or not the function works.
Overall, this function focuses on converting a single image safely and efficiently.And the batch converter later calls this function repeatedly for every JPG/PNG file it finds.
3.3 batch_convert
This function scans a folder (including all subfolders), finds every JPG/PNG image, and converts them into WebP while keeping the original directory structure. It is the “core engine” of the whole script. And let’s cut it into pieces.
def batch_convert(input_dir: Path, output_dir: Path, quality: int):
if not input_dir.exists():
print(f"[ERROR] Input directory does not exist: {input_dir}")#Anything wrong
return
#parents=True allows nested folder creation;
#exist_ok=True prevents errors if the folder already exists
output_dir.mkdir(parents=True, exist_ok=True)
# Traverse all files recursively
for src_path in input_dir.rglob("*"):
if src_path.suffix.lower() in SUPPORTED_EXTS:
# Rebuild directory structure in output folder if necessary
relative = src_path.relative_to(input_dir)
dst_path = (output_dir / relative).with_suffix(".webp")
dst_path.parent.mkdir(parents=True, exist_ok=True)
# Skip existing webp files
if dst_path.exists():
print(f"[SKIP] Already exists: {dst_path}")
continue
#convert one by one in a circle
convert_image_to_webp(src_path, dst_path, quality)for src_path in input_dir.rglob("*")::walk through all the subfolders and finds every file underneath the input directoryif src_path.suffix.lower() in SUPPORTED_EXTS::filter only JPG/PNG images!if dst_path.exists():skip existing .webp filesconvert_image_to_webp(src_path, dst_path, quality):convert all the images of JPG/PNG into webp
Then comes to the most important part of our script:
#Gets the image’s path relative to the input folder
relative = src_path.relative_to(input_dir)
#Creates a matching path inside the output folder and converts the extension to .webp
dst_path = (output_dir / relative).with_suffix(".webp")
#Ensures nested folders are automatically created if necessary(if you have to output into an independent directory)
dst_path.parent.mkdir(parents=True, exist_ok=True)3.4 main()
The main() function turns this Python script into a fully functional command-line tool.
It uses argparse to let the user specify:
- the input folder
- the output folder
- the WebP quality
This makes the tool flexible, user-friendly, and easy to automate.
def main():
parser = argparse.ArgumentParser(
#the description is what you can see when you run the script
description="Batch convert JPG/PNG images to WebP format."
)
#specify where you input, output and the quality of your .webp
parser.add_argument(
"--input", "-i", required=True,
help="Path to the input folder containing images."
)
parser.add_argument(
"--output", "-o", required=True,
help="Path to the output folder to save WebP images."
)
parser.add_argument(
"--quality", "-q", type=int, default=85,
help="WebP quality (0-100, default: 85)."
)
args = parser.parse_args()
#call the function for batch converting
batch_convert(
input_dir=Path(args.input),
output_dir=Path(args.output),
quality=args.quality
)Notice: with this module, then you can run your script as:
python convert_webp.py -i ./images -o ./webp
python convert_webp.py --input "D:/photos" --output "D:/out"ATTENTION: both the relative path and the real path is ok !
4. The full script
4.1 full script to work
The whole script for exchanging images into .webp:
import argparse
from pathlib import Path
from PIL import Image
SUPPORTED_EXTS = {".jpg", ".jpeg", ".png"}
def convert_image_to_webp(src_path: Path, dst_path: Path, quality: int = 85):
"""Convert a single image to WebP format."""
try:
with Image.open(src_path) as img:
img.save(dst_path, format="WEBP", quality=quality)
print(f"[OK] {src_path} -> {dst_path}")
except Exception as e:
print(f"[ERROR] Failed to convert {src_path}: {e}")
def batch_convert(input_dir: Path, output_dir: Path, quality: int):
"""Batch convert all supported images in a folder recursively."""
if not input_dir.exists():
print(f"[ERROR] Input directory does not exist: {input_dir}")
return
#parents=True allows nested folder creation;
#exist_ok=True prevents errors if the folder already exists
output_dir.mkdir(parents=True, exist_ok=True)
# Traverse all files recursively
for src_path in input_dir.rglob("*"):
if src_path.suffix.lower() in SUPPORTED_EXTS:
# Rebuild directory structure in output folder
relative = src_path.relative_to(input_dir)
dst_path = (output_dir / relative).with_suffix(".webp")
dst_path.parent.mkdir(parents=True, exist_ok=True)
# Skip existing webp files
if dst_path.exists():
print(f"[SKIP] Already exists: {dst_path}")
continue
convert_image_to_webp(src_path, dst_path, quality)
def main():
parser = argparse.ArgumentParser(
description="Batch convert JPG/PNG images to WebP format."
)
parser.add_argument(
"--input", "-i", required=True,
help="Path to the input folder containing images."
)
parser.add_argument(
"--output", "-o", required=True,
help="Path to the output folder to save WebP images."
)
parser.add_argument(
"--quality", "-q", type=int, default=85,
help="WebP quality (0-100, default: 85)."
)
args = parser.parse_args()
batch_convert(
input_dir=Path(args.input),
output_dir=Path(args.output),
quality=args.quality
)
#make sure the main() won't run automatically when imported into other procedures!
if __name__ == "__main__":
main()4.2 Running
type the correct command line
Firstly, if you type the real path to run the script, then just make sure you type them correctly, then you can run your script anywhere;
But if you type the relative path , you should firstly confirm your current location which you can find at the beginning of your terminal. Make sure that through the relative path you can find the images you want to process.
For example, I myself use vs code to run the script like this:

And of course, all the two images are correctly converted into .webp, and the original .jpg and .png are still in the same directory.
5. Conclusion
That’s it! With just a bit of Python and Pillow, we now have a simple command-line tool that can batch convert entire folders of JPG/PNG images into WebP. It keeps your original files safe, preserves the folder structure, and lets you tweak the quality however you want.
I made this tool mainly to speed up my own website, but it turned out to be super handy in general — whether you’re organizing photos, optimizing a blog, or just want a cleaner workflow. Feel free to copy it, customize it, or build extra features on top of it.(Although some of you pros probably won’t need this (‾◡◝))
If you enjoyed this little project, check out the other tech posts on my site — I’ll keep sharing more small but useful tools like this.
Happy coding!
You can find the full source code and latest updates on GitHub:
