VMware ESXi and vSphere Cluster Management
Save Images with Pillow
Learn how to save transformed and newly created images with Pillow using Image.save(), output paths, formats, transparency handling, and JPEG quality.
Why save an image?
Pillow is a Python Imaging Library fork used to open, edit, and save image files. When you open or create an image, Pillow represents it as an in-memory Image object. Operations such as flipping, rotating, resizing, or drawing modify or produce Image objects in memory.
Saving writes an Image object to a file on disk. The output path identifies the filename and location for that file.
Saving normally creates a new output file or overwrites the specified output file. It does not automatically change the source image file. For example, saving a flipped image as flipped.jpg leaves the original input file unchanged.
The Image.save() method
Image.save() writes a Pillow Image object to an image file. The simplest form supplies the destination filename:
image.save('output.jpg')
image.save('output.png')The object before .save() is the image that will be written. The filename is the output path, not necessarily the name of the file that was opened.
Save a transformed image
A common workflow is to open or create an image, apply an operation, assign the result to a variable, and save that result under a new name.
from PIL import Image
image = Image.open('input.jpg')
flipped_image = image.transpose(Image.FLIP_LEFT_RIGHT)
flipped_image.save('flipped_img.jpg')Image.transpose(Image.FLIP_LEFT_RIGHT) produces a horizontally flipped Image object. Calling save() on flipped_image writes the flipped result. The original input.jpg is not replaced because the output name is different.
This same pattern works with images created in Python:
from PIL import Image
image = Image.new('RGB', (400, 200), 'white')
image.save('new-image.png')Choosing the output location
A bare filename is resolved relative to the process's working directory. This is the directory Python uses when resolving relative paths, commonly the directory from which the script or command was launched. It is not always the directory containing the script.
flipped_image.save('flipped_img.jpg')To place the file in a subdirectory, provide a relative path:
flipped_image.save('output/flipped.png')To specify an exact destination, provide an absolute path:
flipped_image.save('/home/alex/photos/flipped.png')On Windows, an absolute path can be written as a raw string to avoid treating backslashes as escape sequences:
flipped_image.save(r'C:\Users\Alex\Pictures\flipped.png')The parent directory must already exist. save() writes the file, but it does not generally create missing destination directories for you.
Checking the working directory
If a filename-only output seems to disappear, inspect the directory from which Python is resolving the path:
from pathlib import Path
print(Path.cwd())During development, printing the complete output path can also make the destination clear:
from pathlib import Path
output_path = Path('output') / 'flipped.png'
print(output_path.resolve())
flipped_image.save(output_path)Selecting an output format
Pillow generally infers the output image format from the filename extension. A file extension is the suffix such as .jpg or .png. Changing the output extension, or supplying an explicit format, controls how Pillow encodes the saved file.
image.save('photo.jpg') # JPEG output
image.save('photo.png') # PNG output
image.save('photo.webp') # WebP outputThis is more than renaming a file. Saving with a different extension causes the image data to be encoded in the selected format, subject to that format's capabilities.
If the filename does not identify a format, provide one explicitly:
image.save('output_file', format='PNG')Format compatibility and image modes
An image mode describes how pixel data is stored. RGB has red, green, and blue channels. RGBA has those three color channels plus an alpha channel containing per-pixel opacity information.
Not every image mode is supported by every output format. The most common compatibility issue occurs when saving an RGBA image as JPEG. JPEG has no alpha channel, so it cannot preserve transparency directly.
Save an RGBA image as PNG when transparency must be retained:
from PIL import Image
image = Image.open('logo.png')
image.save('logo-with-transparency.png')If JPEG is required, convert the image to RGB first. The alpha information will not be preserved:
from PIL import Image
image = Image.open('logo.png')
rgb_image = image.convert('RGB')
rgb_image.save('logo.jpg')The shorter equivalent is:
image.convert('RGB').save('logo.jpg')Save options
save() accepts optional keyword arguments that control format-specific encoding behavior. The available options depend on the selected format.
JPEG quality
The quality option controls the balance between JPEG visual quality and file size:
image.save('photo.jpg', quality=90)A higher quality value usually preserves more visual detail but creates a larger file. A lower value usually creates a smaller file but can introduce visible compression artifacts. JPEG is a lossy compression format: it can discard image information to reduce file size.
PNG optimization and compression
PNG is lossless, so its compression does not intentionally discard pixel information. Pillow provides options such as optimize=True and a format-dependent compress_level for controlling encoding behavior:
image.save('optimized.png', optimize=True)
image.save('compressed.png', compress_level=9)PNG compression settings mainly affect encoding time and file size, not the displayed pixel values. Use options appropriate for the chosen format rather than assuming that every keyword works for JPEG, PNG, and WebP.
Practical saving patterns
Save beside the working directory
from PIL import Image
image = Image.open('input.jpg')
image.save('copy.jpg')copy.jpg is written to the current working directory. The input and output names are different, so the source remains available.
Save to an existing relative output folder
from PIL import Image
image = Image.open('input.jpg')
flipped_image = image.transpose(Image.FLIP_LEFT_RIGHT)
flipped_image.save('output/flipped.png')Before running this code, make sure the output directory exists.
Save as PNG while preserving transparency
from PIL import Image
image = Image.open('transparent-source.png')
image.save('transparent-result.png')When the source has an alpha channel, PNG is usually an appropriate target for keeping that transparency.
Save an RGBA image safely as JPEG
from PIL import Image
image = Image.open('source.png')
image.convert('RGB').save('result.jpg')Control JPEG quality
from PIL import Image
image = Image.open('input.jpg')
image.save('web-photo.jpg', quality=90)Compare the resulting file's appearance and size with the requirements of your application. If exact image data or transparency is more important, choose a suitable lossless or transparency-capable format instead.
Troubleshooting
The saved image cannot be found
- A filename without a directory is relative to the working directory, which may differ from the directory you expected.
- Print
Path.cwd()or use a known relative or absolute output path.
Saving raises a file or directory error
- The parent output directory may not exist. Create it before calling
save(). - The process may not have permission to write to the destination. Choose a writable directory or correct the permissions.
Saving as JPEG fails for an image with transparency
- The image may use RGBA or another mode that JPEG does not support directly.
- Save as PNG to retain transparency, or convert to RGB before saving as JPEG.
The output format is not recognized
- The filename may have no recognized extension or may contain a misspelled or unsupported extension.
- Use a supported extension such as
.jpg,.png, or.webp, or provideformat='PNG'when the filename does not identify the format.
The JPEG is unexpectedly large or has visible artifacts
- The selected
qualityvalue may not suit the image or use case. - Adjust the quality and compare both file size and appearance. Use PNG when lossless output or transparency is more important than compact size.
Quick reference
from PIL import Image
image = Image.open('input.jpg')
flipped_image = image.transpose(Image.FLIP_LEFT_RIGHT)
# Infer format from the extension.
flipped_image.save('output/flipped.png')
# Specify a format explicitly.
flipped_image.save('output_file', format='PNG')
# Convert before JPEG output when the source may have alpha.
flipped_image.convert('RGB').save('flipped.jpg', quality=90)For more practice, continue with saving images with Pillow as part of your image-processing workflow.