Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

The right Python call depends on the object you are saving: use Image.save() for a Pillow image, fig.savefig() for a Matplotlib figure, and cv2.imwrite() for an OpenCV array. The examples below write PNG files, choose other formats explicitly, and show how to keep the result in memory instead of creating a disk file.

Choose the save function that matches your image object

Python image data is not one universal type. A Pillow Image, a Matplotlib figure, and an OpenCV array each have a different writer. Select the API before choosing a filename or format.

Object you have Function Destination Format selection
Pillow image image.save() Path or binary file-like object Usually inferred from the extension; pass format= when it cannot be inferred
Matplotlib chart or figure fig.savefig() or plt.savefig() Path or file-like object Selected by the output name or an explicit save option
OpenCV image array cv2.imwrite() Path Selected from the filename extension; optional format parameters can be supplied

Save an existing or processed image with Pillow

Pillow’s Image.save() is the general-purpose choice for an image you opened, resized, cropped, or otherwise processed with Pillow. Give it a filename whose extension matches the format you want.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Save as PNG

from PIL import Image

with Image.open('input.jpg') as image:
    image.save('output.png')

Here Pillow opens input.jpg and writes a PNG to output.png. The extension normally tells Pillow which writer to use. The with block closes the input image when the operation finishes.

#1 Best Overall
Sale
Kodak PIXPRO FZ45 Digital Camera, 16MP Point & Shoot (Black)
  • 16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting
  • Optical Zoom: 4x optical zoom with a 27mm wide angle lens for flexible framing indoors or outdoors
  • Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
  • Memory Support: Works with Class 10 SD, SDHC, or SDXC cards up to 512GB
  • LCD Screen and Battery: 2.7in LCD screen with 2 AA alkaline batteries for convenient on-the-go use

Choose a format explicitly

If the filename has a nonstandard extension, specify the writer with format=. This prevents the extension from being mistaken for a format name.

from PIL import Image

with Image.open('input.jpg') as image:
    image.save('output.data', format='PNG')

You can use the same pattern with another supported Pillow format by changing both the intended format and, when appropriate, the extension. Keep the extension and the actual format aligned so other programs can identify the file reliably.

Save an image already held in a variable

If earlier processing produced a Pillow image object, save it directly; there is no need to reopen it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from PIL import Image, ImageFilter

with Image.open('input.jpg') as source:
    softened = source.filter(ImageFilter.BLUR)
    softened.save('softened.png')

Pass format-specific options only when they apply to the writer you selected. For example, keep quality or compression arguments with the format that defines them rather than passing them indiscriminately.

Save an image to memory instead of a named file

Pillow can write to a file-like object. Use a binary object that supports seek, tell, and write, and state the format explicitly because a stream has no filename extension for Pillow to inspect.

from io import BytesIO
from PIL import Image

with Image.open('input.jpg') as image:
    buffer = BytesIO()
    image.save(buffer, format='PNG')
    png_bytes = buffer.getvalue()

# png_bytes now contains the complete PNG file in memory.

This approach is useful when the next step accepts bytes rather than a path. Keep the stream in binary mode; a text stream will not provide the interfaces required by the image writer.

Save a Matplotlib chart or figure

For a chart, save the figure object with fig.savefig(). The function accepts either a path or a file-like object and exposes options such as output format, resolution, and bounding-box handling.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Kodak PIXPRO FZ55-BK 16MP CMOS Sensor Camera 5X Optical Zoom 28mm Wide
  • 16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting
  • Optical Zoom: 5x optical zoom with a 28mm wide angle lens for flexible framing indoors or outdoors
  • Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
  • Memory Support: Works with Class 10 SD, SDHC, or SDXC cards up to 512GB
  • LCD Screen and Battery: 2.7in LCD screen and a rechargeable lithium-ion battery for on-the-go use
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])
fig.savefig('plot.png', dpi=300, bbox_inches='tight')

Using the figure object is explicit and works well when a script creates more than one chart. If you are using pyplot’s stateful interface, the equivalent call is plt.savefig('plot.png') after the desired figure has been drawn.

Write a figure to an in-memory stream

Because Matplotlib accepts file-like objects, you can avoid a named output file in the same way as Pillow.

from io import BytesIO
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])

buffer = BytesIO()
fig.savefig(buffer, format='PNG', dpi=150)
chart_bytes = buffer.getvalue()

Specify format='PNG' (or another format supported by your Matplotlib installation) when writing to a stream. A stream has no extension to guide format selection.

Save an OpenCV image array

OpenCV stores an image as an array. Use cv2.imwrite(filename, image); the filename extension selects the output format, and format-specific parameters can be supplied as an optional third argument.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import cv2

image = cv2.imread('input.jpg')
ok = cv2.imwrite('output.png', image)
if not ok:
    raise OSError('Image could not be written')

Check the Boolean return value. A false result means the write did not succeed, so your program can stop or report the failure instead of silently continuing.

Pass encoder parameters when needed

OpenCV accepts a params sequence for format-specific encoder settings. Keep those parameters tied to the extension and encoder you selected.

import cv2

image = cv2.imread('input.jpg')
params = []  # Add encoder-specific key/value parameters when required.
ok = cv2.imwrite('output.jpg', image, params)
if not ok:
    raise OSError('Image could not be written')

Match the extension, format, and destination

  • Use a matching extension. Pillow normally infers its writer from the filename; OpenCV selects its encoder from the filename extension.
  • Use an explicit format for streams. A BytesIO object has no extension, so pass format='PNG' (or the format you intend).
  • Keep options with the correct API. Pillow writer options, Matplotlib save options, and OpenCV encoder parameters are not interchangeable.
  • Choose a path your process can write. A valid image and a correct API call still fail if the destination directory is unavailable or unwritable.

Build a small, checkable save function

Wrapping the operation in a function makes the destination and failure behavior explicit. The Pillow version below accepts a format override, which is useful for generated filenames that do not end in a conventional extension.

Rank #3
Sale
Digital Camera, Latest FHD 1080P Digital Camera for Teens with SD Card Anti Shake Point and Shoot Cameras Portable 16X Zoom Compact Small Cameras for Kids Boys Girls Seniors with Wrist Strap
  • Latest Digital Camera Built-in Fill Light : This compact digital camera is paired with a powerful CMOS processor and image stabilization to help you take & record the most exciting moments in 44 MP quality images & FHD 1080P quality videos anywhere, anytime. Plus, there is also a built-in fill light to help you take high quality pictures even in low light&dark settings, making this the perfect camera for all indoors/outdoors situations.
  • Long-Lasting Battery Life & 16X Digital Zoom :This point and shoot camera will retain its battery charge even after long use. The controls and functions are easy to operate making this the perfect choice for children, teens and younger. This kids camera supports 16x digital zoom, you can zoom in or out the subject by pressing the W/T button for taking still photos to zoom in or out on distant objects and capture all the details you need.
  • Multifunctional & Portable Digital Camera: This cheap digital camera is slim enough to fit in your pocket. You'll easily be able to take it with you on all your indoor/outdoor activities and adventures and ideal for beginners, children and teenagers. This kids digital camera is equipped with 20 filters, anti-shaking, self-timer, continuous shooting, date stamp, time-lapse recording, smile capture, internal MIC and speaker (recording sound videos), great for your daily photography needs.
  • WEBCAM & PAUSE FUNCTION : More than just a FHD 1080p digital camera, it also works as a webcam for video calls and vlogging. Connect the camera to the computer, press shutter and power button at the same time and the camera will automatically turn on webcam mode for all your video calling and live streaming needs. The pause function allows you to pause when seeing playback videos.
  • A Must Have Photography Device : This digital camera with SD card made from high-quality materials, this retro camera is safe and durable. Perfect for all ages to develop & improve their photographic abilities and observation skills. Our dedicated and experienced 24/7 support team is available for all after purchase troubleshooting, questions and technical help.
from pathlib import Path
from PIL import Image

def save_pillow_image(source_path: str, destination: str, output_format: str | None = None) -> Path:
    destination_path = Path(destination)
    with Image.open(source_path) as image:
        if output_format is None:
            image.save(destination_path)
        else:
            image.save(destination_path, format=output_format)
    if not destination_path.exists():
        raise OSError(f'Expected output was not created: {destination_path}')
    return destination_path

save_pillow_image('input.jpg', 'exports/output.png')
save_pillow_image('input.jpg', 'exports/output.data', 'PNG')

Create the exports directory before calling this function if it does not already exist. The function checks that a path now exists, while the OpenCV workflow separately checks its Boolean write result.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common save failures

“Cannot identify image file” from Pillow

The input is not a readable image for Pillow, the path is wrong, or the file is incomplete. Verify the input path and open the file with Image.open() before attempting to save.

“unknown file extension” or a format error

The destination extension does not identify a Pillow writer. Supply an explicit format, for example image.save('output.data', format='PNG'), and ensure that the selected format is available in your Pillow installation.

The output is written in an unexpected format

Check that the extension matches your intention. With Pillow, an extension normally controls inference; with OpenCV, the extension selects the encoder. For a stream, always set the format explicitly.

OpenCV returns False

cv2.imwrite() reports failure through its return value. Check that the source array is valid, the destination directory exists, and the process can write there. Do not treat the call as successful until ok is true.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The figure is clipped or has unwanted margins

Matplotlib exposes save options for layout and resolution. Adjust arguments such as bbox_inches='tight' and dpi on fig.savefig() for the output you need.

A stream write fails

Use a binary file-like object that supports seek, tell, and write. Pass an explicit format because the stream cannot provide an extension.

Rank #4
Kodak PIXPRO FZ55-RD 16MP Camera 5X Optical Zoom 28mm Wide Angle 1080p
  • 16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting
  • Optical Zoom: 5x optical zoom with a 28mm wide angle lens for flexible framing indoors or outdoors
  • Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
  • Memory Support: Works with Class 10 SD, SDHC, or SDXC cards up to 512GB
  • LCD Screen and Battery: 2.7in LCD screen and a rechargeable lithium-ion battery for on-the-go use

Performance and reliability considerations

For a single local image, the direct save calls are usually the simplest and clearest solution. When producing many files, keep the writer matched to the object type and choose destinations deliberately. In-memory streams avoid temporary files but retain the complete encoded image in memory, so release or reuse buffers after the next step has consumed the bytes.

Matplotlib’s resolution and bounding-box settings affect the resulting file and the time required to encode it. Pillow and OpenCV expose format-specific controls; apply them only when the selected writer supports them. Regardless of library, make failure visible: check OpenCV’s Boolean result, verify expected paths for file saves, and handle exceptions around input and output operations.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If the image you need is a webpage screenshot, you can avoid installing and driving a browser yourself with ScreenshotNeo. Its API accepts one GET request and returns a PNG, JPEG, WebP, or PDF. The following call saves the response directly to a file; see the ScreenshotNeo API documentation for the available parameters.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests

r = requests.get(
    'https://api.screenshotneo.com/v1/shot',
    params={'access_key': 'YOUR_API_KEY', 'url': 'https://stripe.com'},
    timeout=90,
)
r.raise_for_status()
open('shot.webp', 'wb').write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is available on every plan, and yearly billing gives two months free. Create a free ScreenshotNeo account to get started.

FAQ

Frequently Asked Questions

How do I save image bytes returned by another Python library?

Open the destination in binary mode and write the bytes: with open('output.png', 'wb') as file: file.write(data). Use this when you already have encoded PNG, JPEG, or WebP bytes rather than a Pillow image, figure, or OpenCV array.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can I choose a destination at runtime?

Yes. Build the destination from a string or pathlib.Path value, then pass it to the matching save function. Ensure the parent directory exists before writing.

Quick Recap

SaleBestseller No. 1
Kodak PIXPRO FZ45 Digital Camera, 16MP Point & Shoot (Black)
Kodak PIXPRO FZ45 Digital Camera, 16MP Point & Shoot (Black)
16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting; Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
$99.99
SaleBestseller No. 2
Kodak PIXPRO FZ55-BK 16MP CMOS Sensor Camera 5X Optical Zoom 28mm Wide
Kodak PIXPRO FZ55-BK 16MP CMOS Sensor Camera 5X Optical Zoom 28mm Wide
16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting; Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
$139.99
Bestseller No. 4
Kodak PIXPRO FZ55-RD 16MP Camera 5X Optical Zoom 28mm Wide Angle 1080p
Kodak PIXPRO FZ55-RD 16MP Camera 5X Optical Zoom 28mm Wide Angle 1080p
16MP Sensor: Captures detailed photos with a CMOS sensor for everyday shooting; Full HD Video: Records 1080p video for travel clips, family moments, or simple vlogging
$139.99

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.