Convert JPG, PNG, and WebP with Python Pillow
python pillow convert jpg png webp image formats: Learn how to convert JPG, PNG, and WebP images with Python Pillow, including format-specific options, transparency ha...
python pillow convert jpg png webp image formats requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
When you need to convert JPG, PNG, or WebP images in Python, Pillow is the standard library for the job. The core workflow is simple: open an image with Image.open() and save it with a new format. But the details matter when you care about quality, transparency, metadata, or processing many files. This article walks through the conversion process and the decisions that come with each format.
The Basic Conversion Workflow
The simplest conversion looks like this:
from PIL import Image im = Image.open("input.jpg") im.save("output.png")
Pillow infers the output format from the file extension. The same pattern works for any combination of JPG, PNG, and WebP. If you need to specify the format explicitly, pass it as the second argument to save():
im.save("output", format="WEBP")
The format parameter is useful when the filename does not carry a clear extension or when you are writing to a file-like object.
Format-Specific Save Options
Each format accepts parameters that control compression and output quality. These are passed directly to save().
For JPEG:
im.save("output.jpg", quality=85, optimize=True, progressive=True)
qualitycontrols the compression level, typically 1–95.optimizespends extra time to produce a smaller file.progressivewrites a progressive JPEG, which loads in stages.
For PNG:
im.save("output.png", optimize=True, compress_level=9)
PNG uses lossless compression, so compress_level trades encoding time for file size. optimize also improves compression at the cost of speed.
For WebP:
im.save("output.webp", quality=80, lossless=False, method=4)
qualityworks like JPEG whenlosslessisFalse.lossless=Trueproduces a lossless WebP, which is useful for images with sharp edges or text.methodcontrols the compression effort, from 0 (fast) to 6 (slow, smaller output).
These options are not interchangeable. Passing a JPEG-only parameter to a PNG save is silently ignored, so keep them format-specific.
Handling Transparency and Color Modes
PNG and WebP support an alpha channel; JPEG does not. If you convert a transparent PNG to JPEG, Pillow will not fail, but the transparency is lost and the image may look wrong. You need to composite the image onto a solid background first:
from PIL import Image im = Image.open("transparent.png").convert("RGBA") background = Image.new("RGB", im.size, (255, 255, 255)) background.paste(im, mask=im.split()[3]) background.save("output.jpg")
The mask uses the alpha channel so only transparent areas show the white background. Without this step, the JPEG will contain black or undefined pixels in transparent regions.
When converting between formats that both support alpha, such as PNG to WebP, the alpha channel is preserved automatically. But be aware that some WebP encoders handle alpha differently, so verify the result if you rely on exact transparency.
Converting Multiple Images in a Batch
For a directory of images, loop over the files and convert each one. Use pathlib for clean path handling:
from pathlib import Path from PIL import Image input_dir = Path("images") output_dir = Path("converted") output_dir.mkdir(exist_ok=True) for src in input_dir.glob("*.png"): im = Image.open(src) dest = output_dir / (src.stem + ".webp") im.save(dest, "WEBP", quality=80)
This pattern keeps memory usage low because each image is opened, converted, and closed before the next one is processed. If you need to convert a large number of files, process them sequentially rather than loading all images into memory at once.
Preserving Metadata and Color Profiles
By default, Pillow does not carry over EXIF, ICC profiles, or other metadata when you save a converted image. To preserve them, copy the relevant entries from the source image's info dictionary:
im = Image.open("input.jpg") exif = im.info.get("exif") icc = im.info.get("icc_profile") im.save("output.webp", exif=exif, icc_profile=icc)
Not every format supports every metadata type. JPEG and WebP can store EXIF and ICC profiles, while PNG has its own metadata conventions. If the target format does not support a particular field, Pillow will ignore it or raise an error depending on the version. Test the output to confirm that the metadata you care about survived the conversion.
Choosing the Right Output Format
The decision between JPG, PNG, and WebP depends on the image content and the use case.
| Format | Compression | Transparency | Typical Use |
|---|---|---|---|
| JPG | Lossy | No | Photographs, web images without alpha |
| PNG | Lossless | Yes | Screenshots, diagrams, images with text |
| WebP | Both | Yes | Web delivery, smaller files than PNG or JPG |
WebP often produces smaller files than JPEG at the same quality, but encoding is slower. PNG is the right choice when lossless output matters more than file size. JPEG remains a safe default for photographic content that does not need transparency.
Performance Considerations for Large Batches
Pillow loads the entire image into memory, so a batch conversion of large files can consume a lot of RAM. Process one image at a time and let the image object go out of scope before moving to the next. If you are converting to JPEG or WebP, the optimize and method options increase encoding time but reduce file size. There is no free lunch: smaller files cost CPU time.
For very large images, consider resizing before conversion if the final dimensions are known. That reduces memory usage and encoding time. If you need to convert thousands of files, parallelize with a process pool, but be aware that Pillow releases the GIL during some operations, so the speedup may not be linear.