BlogScreenshots on your device
How to Save a Croppable PNG Screenshot to the Windows Desktop with Python
Capture part of your Windows screen with Python, crop it with Pillow, and save a PNG to the current user's Desktop.
Short answer: use PyAutoGUI to capture the visible screen as a Pillow image, call crop((left, upper, right, lower)), and save the result to Path.home() / 'Desktop' / 'filename.png'. The crop coordinates are pixel positions: the last two values are the ending coordinates, not width and height.
from pathlib import Path
import pyautogui
# Coordinates are pixels: left, upper, right, lower.
left, upper, right, lower = 100, 100, 700, 500
image = pyautogui.screenshot()
cropped = image.crop((left, upper, right, lower))
desktop = Path.home() / 'Desktop'
desktop.mkdir(parents=True, exist_ok=True)
output = desktop / 'cropped_screenshot.png'
cropped.save(output, format='PNG')
print(f'Saved: {output.resolve()}')
Install the dependencies in the same Python environment that will run the script:
python -m pip install pyautogui pillow
PyAutoGUI’s screenshot function returns an image and can save directly to a filename; its screenshot support requires Pillow. See the PyAutoGUI screenshot documentation.
1. Choose the capture method
| Need | Use | Why |
|---|---|---|
| A simple screenshot and a crop decided in code | PyAutoGUI + Pillow | One call returns a Pillow image, so cropping and saving are straightforward. |
| A known rectangle, a specific monitor, or explicit region capture | MSS | MSS can grab a monitor or region directly and documents PNG output and Pillow conversion. |
| A one-off manual capture | Windows Snipping Tool | Microsoft documents selecting, editing, saving and sharing a snip. It is not a Python automation workflow. |
Use coordinates from the capture library you choose. On a multi-monitor desktop, the coordinate space can include negative values or begin at a monitor origin other than (0, 0).
2. Install Python packages on Windows
- Install Python and make sure
python --versionworks in PowerShell or Command Prompt. - Create a project folder and, optionally, a virtual environment.
- Install PyAutoGUI and Pillow:
python -m venv .venv
.venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install pyautogui pillow
Using python -m pip ties installation to the interpreter that runs the script, which avoids the common case where a package was installed for a different Python installation.
3. Capture the full screen, then crop it
This pattern is useful when you want to inspect the full screenshot first or calculate the crop after another step. Pillow uses a four-value box:
(left, upper, right, lower)
The origin is the upper-left corner. The right and lower values mark the opposite edge. If you have a rectangle expressed as (left, top, width, height), convert it before calling crop:
right = left + width
lower = top + height
cropped = image.crop((left, top, right, lower))
A complete script with validation and useful output:
from pathlib import Path
import pyautogui
# Rectangle in left, top, width, height form.
left, top, width, height = 100, 100, 600, 400
if width <= 0 or height <= 0:
raise ValueError('width and height must be positive')
right = left + width
lower = top + height
image = pyautogui.screenshot()
print(f'Full screenshot dimensions: {image.size[0]}x{image.size[1]}')
# Keep the requested box inside the captured image.
image_width, image_height = image.size
if left < 0 or top < 0 or right > image_width or lower > image_height:
raise ValueError(
f'Crop {(left, top, right, lower)} is outside '
f'the captured image {(image_width, image_height)}'
)
cropped = image.crop((left, top, right, lower))
desktop = Path.home() / 'Desktop'
desktop.mkdir(parents=True, exist_ok=True)
output = desktop / 'cropped_screenshot.png'
cropped.save(output, 'PNG')
print(f'Crop dimensions: {cropped.size[0]}x{cropped.size[1]}')
print(f'Saved: {output.resolve()}')
The parent directory check is harmless when Desktop already exists and helps when a profile has an unusual setup. Windows profiles may redirect Desktop to a cloud-synced or organization-managed location. If the file is not where you expect, use the printed resolved path or set desktop to your actual Desktop folder.
4. Capture only a region with MSS
If the rectangle is known before capture, MSS avoids taking a full-screen image first. Its documentation covers monitor selection, region capture, PNG saving and conversion to Pillow for later image processing. Install it with:
python -m pip install mss pillow
Direct region capture and PNG output:
from pathlib import Path
from mss import mss
left, top, width, height = 100, 100, 600, 400
if width <= 0 or height <= 0:
raise ValueError('width and height must be positive')
region = {'left': left, 'top': top, 'width': width, 'height': height}
desktop = Path.home() / 'Desktop'
desktop.mkdir(parents=True, exist_ok=True)
output = desktop / 'mss_region.png'
with mss() as capture:
capture_img = capture.grab(region)
capture.tools.to_png(capture_img.rgb, capture_img.size, output=str(output))
print(f'Saved: {output.resolve()}')
To process the MSS result with Pillow, convert it first:
from pathlib import Path
from mss import mss
from PIL import Image
region = {'left': 100, 'top': 100, 'width': 600, 'height': 400}
desktop = Path.home() / 'Desktop'
desktop.mkdir(parents=True, exist_ok=True)
output = desktop / 'mss_processed.png'
with mss() as capture:
shot = capture.grab(region)
image = Image.frombytes('RGB', shot.size, shot.rgb)
# Further Pillow operations can go here.
image.save(output, 'PNG')
print(f'Saved: {output.resolve()}')
For another monitor, use its origin when constructing the region. MSS exposes monitor information through its monitor list; anchor the rectangle to the selected monitor rather than assuming the primary display starts at zero. A monitor positioned left of the primary display can have negative screen coordinates.
5. Make the crop interactively selectable
The examples above use known coordinates. If a person should choose the rectangle with the mouse, capture the pointer positions and convert them to a normalized box before cropping. The exact interaction layer depends on the GUI toolkit you choose; the important Pillow rule remains the same:
left = min(start_x, end_x)
right = max(start_x, end_x)
upper = min(start_y, end_y)
lower = max(start_y, end_y)
cropped = image.crop((left, upper, right, lower))
Normalize the two corners so dragging in any direction works. Reject a zero-width or zero-height selection, and ensure the pointer coordinates and screenshot coordinates use the same scaling and monitor space.
6. PNG options and file handling
PNG is lossless, so it preserves sharp text and UI edges. Pillow accepts a path object and lets you specify the format explicitly:
cropped.save(output, format='PNG', optimize=True)
Use a unique filename when a script runs repeatedly:
from datetime import datetime
output = desktop / f'screenshot-{datetime.now():%Y%m%d-%H%M%S}.png'
Check the resulting dimensions before handing the file to another process:
with Image.open(output) as saved:
print(saved.format, saved.size, saved.mode)
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
ModuleNotFoundError: pyautogui or PIL |
The package is missing from the active interpreter. | Activate the correct virtual environment and run python -m pip install pyautogui pillow. |
| The crop is empty or has unexpected dimensions | The tuple was supplied as (left, top, width, height). |
Convert to (left, top, left + width, top + height). |
ValueError for an invalid crop |
Coordinates are reversed, zero-sized, negative, or outside the image. | Normalize both corners and compare the box with image.size. |
| The wrong monitor was captured | Coordinates were assumed to start at zero. | Inspect monitor origins and use the selected monitor’s left and top offsets. |
| The image is saved but cannot be found | Desktop is redirected or a relative path was used. | Print output.resolve() and check the displayed location; set an explicit Desktop path if needed. |
| The screenshot does not show a minimized window | These libraries capture visible screen pixels. | Bring the target content onto the visible desktop before capture. |
| A protected video surface is black | Some applications restrict screen capture. | Do not assume ordinary desktop capture can bypass application-specific protection. |
8. Performance, reliability and repeatability
- Capture less when you can: MSS region capture avoids processing pixels outside the requested rectangle.
- Use full-screen capture when the crop is dynamic: it gives your code a stable image to inspect and crop later.
- Keep coordinate spaces consistent: display scaling, multiple monitors and remote-desktop sessions can change the relationship between logical pointer coordinates and image pixels. Print the captured dimensions and inspect a sample output.
- Create output directories deliberately: use
Path.home()rather than embedding another person’sC:\Users\...path. - Verify the artifact: check that the file exists, can be opened, and has the expected dimensions before reporting success.
- Do not promise invisible or protected captures: the documented workflows capture visible monitors or regions, not every application surface.
9. Or skip the browser setup
If you need screenshots of web pages rather than pixels on your Windows desktop, ScreenshotNeo returns a PNG, JPEG, WebP or PDF from one GET request. Its browser capture can accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups and chat widgets before the shot. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.
Read the ScreenshotNeo API documentation for the complete option list, including full-page and element capture, device presets, custom CSS and JavaScript, waits, blocking rules, authentication headers and cookies, caching, signed links, asynchronous jobs, bulk capture and PDFs.
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}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
The MCP server also provides take_screenshot, get_page_info and capture_pdf tools 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, and every feature is available on every plan.
Create a free ScreenshotNeo account to try the API without a card.
10. FAQ
Should I use PyAutoGUI or MSS?
Use PyAutoGUI for the shortest full-screen-to-Pillow workflow. Use MSS when you know the region in advance, need explicit monitor selection, or want direct region capture.
Are crop coordinates width and height?
No. Pillow expects (left, upper, right, lower). Add width to left and height to top when converting from a size-based rectangle.
Where is the Windows Desktop path?
Path.home() / 'Desktop' is the portable starting point. Print the resolved path because Windows profiles can redirect Desktop.
Can this capture a minimized window?
No. These workflows capture visible screen or monitor pixels. A minimized or protected surface may not appear in the result.
Can I save JPEG instead?
Yes, Pillow can save other formats, but PNG is usually preferable for text and interface screenshots because it is lossless.


