Recommended Free Tools
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 direct method: cropping means selecting a rectangle in source-image coordinates and saving the pixels inside it. In Python Pillow, call Image.crop((left, upper, right, lower)); in ImageMagick, use -crop widthxheight+x+y. Both methods keep the original pixels inside the selected region and do not distort them. The important decisions are coordinate order, boundary handling, output aspect ratio, and whether transparency and metadata must survive.
What a programmatic crop actually does
A crop extracts a rectangular region. Coordinates refer to the source image, not the desired output size. The usual convention is an origin at the upper-left: x increases to the right and y increases downward.
- Left/top: the first pixel coordinate in the rectangle.
- Right/bottom: the rectangle’s ending coordinates. In Pillow these form a four-item box,
(left, upper, right, lower). - Width and height: for a conventional half-open rectangle, width is
right - leftand height islower - upper.
Always define whether your application rejects a box outside the image, clips it to the image, or pads the missing area. That policy matters when crop coordinates come from users or an external API.
Crop an image in Python with Pillow
Install Pillow
Install the current Pillow package in the environment that runs your script:
#1 Best Overall
python -m pip install Pillow
Crop a rectangle
This complete example keeps the 80-by-80 region whose upper-left corner is at (20, 20):
from PIL import Image
with Image.open("input.jpg") as im:
cropped = im.crop((20, 20, 100, 100))
cropped.save("crop.jpg", quality=92)
The returned image is a new image object. The source file is not changed. Pillow’s box order is exactly (left, upper, right, lower); swapping x and y or treating the last two values as width and height produces a different region.
Crop by x, y, width, and height
Many user interfaces provide an origin plus dimensions. Convert that representation explicitly:
Free tools Windows power users keep installed
One-click scans. No signup required.
from PIL import Image
def crop_xywh(input_path, output_path, x, y, width, height):
if width <= 0 or height <= 0:
raise ValueError("width and height must be positive")
right = x + width
bottom = y + height
with Image.open(input_path) as im:
if x < 0 or y < 0 or right > im.width or bottom > im.height:
raise ValueError("crop rectangle is outside the image")
im.crop((x, y, right, bottom)).save(output_path)
crop_xywh("input.jpg", "crop.jpg", 20, 20, 800, 600)
Rejecting an invalid rectangle is safest for an editing API. A thumbnail service may instead clip coordinates or pad with a chosen background; make that behavior explicit and test it.
Remove a border with ImageOps.crop
When the task is “remove N pixels from each edge,” use ImageOps.crop instead of calculating four coordinates:
from PIL import Image, ImageOps
with Image.open("input.png") as im:
result = ImageOps.crop(im, border=(20, 10, 20, 10))
result.save("without-border.png")
A single integer removes that many pixels from all four sides. A two-item tuple specifies horizontal and vertical borders. A four-item tuple is (left, top, right, bottom).
Rank #2
Make a crop fit an exact aspect ratio
A rectangle crop alone does not guarantee a target ratio. For a fixed output box, choose whether the complete image must remain visible or whether excess edges may be removed.
Cover the target box (crop excess)
ImageOps.fit resizes and crops to an exact size. Centering at (0.5, 0.5) keeps the crop centered; values near (0, 0) bias toward the top-left, while (1, 0) biases toward the bottom-left.
from PIL import Image, ImageOps
with Image.open("portrait.jpg") as im:
square = ImageOps.fit(im, (800, 800), centering=(0.5, 0.5))
square.save("portrait-square.jpg", quality=92)
Use a different centering point when the subject is not in the middle. For example, a face near the top generally needs a vertical bias above 0.5.
Contain the complete image
ImageOps.contain resizes the whole image so it fits inside the target box while preserving aspect ratio. It may leave unused space around the image:
from PIL import Image, ImageOps
with Image.open("photo.jpg") as im:
thumbnail = ImageOps.contain(im, (800, 800))
thumbnail.save("thumbnail.png")
Choose between contain and cover
| Requirement | Use | Result |
|---|---|---|
| Show every source pixel | ImageOps.contain |
Entire image fits; target box may not be filled. |
| Fill every target pixel | ImageOps.fit or ImageOps.cover |
Aspect ratio is preserved; some source pixels are cropped. |
| Keep a manually selected region | Image.crop |
Exact source rectangle; output size follows the box. |
Center-crop math without a helper
For code that must work without a high-level helper, calculate the largest centered rectangle matching the target ratio.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsfrom PIL import Image
def center_crop(im, target_width, target_height):
if target_width <= 0 or target_height <= 0:
raise ValueError("target dimensions must be positive")
target_ratio = target_width / target_height
source_ratio = im.width / im.height
if source_ratio > target_ratio:
# Source is too wide: remove left and right edges.
crop_height = im.height
crop_width = round(crop_height * target_ratio)
left = (im.width - crop_width) // 2
box = (left, 0, left + crop_width, im.height)
else:
# Source is too tall: remove top and bottom edges.
crop_width = im.width
crop_height = round(crop_width / target_ratio)
top = (im.height - crop_height) // 2
box = (0, top, im.width, top + crop_height)
return im.crop(box)
with Image.open("input.jpg") as im:
result = center_crop(im, 1200, 630)
result = result.resize((1200, 630))
result.save("social-card.jpg", quality=92)
The crop happens before the final resize, so resizing does not stretch the image. For important subjects, use a stored focal point rather than assuming the center is correct.
Crop images with ImageMagick
ImageMagick expresses a crop as widthxheight+x+y: retained width and height, followed by the upper-left x and y offsets.
magick input.jpg -crop 800x600+100+50 +repage output.jpg
+repage removes virtual-canvas/page metadata so the output’s canvas starts at its cropped upper-left corner. This is especially important when later operations, animations, or compositing interpret page offsets.
Use ImageMagick from a script
Validate dimensions before constructing the command, and pass paths as separate arguments rather than interpolating untrusted shell text. A crop that misses the actual image can produce a transparent missed image and a warning. Treat warnings as failures when the output is required to contain pixels.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Tile an image
If offsets are omitted, ImageMagick can generate a set of tiles across the input:
magick input.jpg -crop 256x256 +repage tiles-%02d.jpg
Tile naming and the number of generated files depend on the source dimensions and geometry. For images with a virtual canvas, use viewport behavior or +repage deliberately rather than assuming page coordinates are physical pixels.
Transparency, color, and output formats
- Alpha: preserve an RGBA image when saving PNG or WebP. JPEG has no alpha channel; choose a background color before converting.
- Color mode: inspect whether the source is RGB, RGBA, grayscale, palette-based, or CMYK. Convert deliberately when a downstream consumer expects RGB.
- JPEG quality: cropping itself is lossless in pixel selection, but saving a JPEG recompresses the selected pixels. Avoid repeated JPEG save cycles.
- Metadata: libraries and format conversions may not preserve every EXIF, ICC, or orientation field. Normalize orientation before calculating coordinates if camera images may contain an EXIF orientation tag.
Do not use a browser-rendered CSS crop when you need the original pixel dimensions: CSS coordinates are in display pixels and may be affected by device scale, transforms, and responsive layout.
Validation and security for production services
- Require finite numeric coordinates and positive width and height.
- Set maximum source pixels, output dimensions, and file size to limit memory and denial-of-service risk.
- Choose reject, clip, or pad behavior for out-of-bounds rectangles and document it in the API response.
- Decode only formats your service needs, and enforce a timeout for remote inputs.
- Write to a new output path or stream; never overwrite the input before a successful encode.
- Use deterministic filenames and avoid trusting user-supplied paths.
Large images can consume far more memory after decompression than their file size suggests. Process them in a worker with resource limits when accepting uploads at scale.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePerformance and reliability choices
When Pillow is the better fit
Pillow runs in-process with Python, so it is convenient for web handlers, notebooks, and applications that already use Python image objects. Keep the image open only as long as needed, crop before expensive transformations, and avoid creating multiple full-size intermediate copies.
When ImageMagick is the better fit
ImageMagick is practical for shell pipelines, batch jobs, and command-line automation. It provides geometry expressions, tiling, viewport handling, and scripting interfaces. Isolate the process, capture stderr, check exit status, and apply explicit resource policies.
Test the edges
- Crop at (0, 0), at the bottom-right boundary, and at a one-pixel rectangle.
- Test odd dimensions where centering leaves one extra pixel on one side.
- Test RGB, RGBA, grayscale, and rotated-camera images.
- Verify the encoded output dimensions, alpha behavior, and file readability.
Troubleshooting common crop failures
“The crop is shifted”
Check x/y ordering and remember that Pillow takes right/bottom coordinates, not width/height. Log the source dimensions and the final four-value box.
“The output is stretched”
The crop and resize ratios differ. Use ImageOps.fit, ImageOps.contain, or the center-crop calculation, then resize only to a matching ratio.
“A transparent border appeared in ImageMagick”
The crop may have missed the actual image or retained a virtual-canvas offset. Confirm geometry against the image dimensions and apply +repage when you need a new canvas origin.
Best Value
“The subject is cut off”
A centered crop is mathematically correct but semantically unaware. Store a focal point, adjust centering, or provide an editor-defined box.
“The file opens with the wrong rotation”
Normalize EXIF orientation before selecting coordinates, then verify the saved file in a decoder that honors the resulting metadata.
Or skip the browser setup
If what you need is a clean screenshot of a web page rather than cropping a local image, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; the response identifies the page verdict and billing status in X-Page-Verdict and X-Billed headers.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo API documentation for capture options such as full-page lazy-image loading, CSS-selector element capture, dark mode, device presets, retina scale, custom CSS and JavaScript, click actions, wait conditions, blocked requests, cookies, headers, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous webhooks, bulk capture, and PDF settings.
The same request from 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)
Or 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(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots. Sign up free.
Frequently Asked Questions
Should crop coordinates be integers?
For pixel-accurate raster cropping, use integer coordinates. If your UI produces fractional values, define a rounding rule before converting them and test the resulting edge pixels.
Can a crop increase image quality?
No. Cropping selects existing pixels. You can resize the result, but enlargement cannot restore detail that was not present in the source.
How do I crop a non-rectangular shape?
The documented Pillow and ImageMagick operations here are rectangular. Crop a bounding rectangle first, then apply a mask or alpha operation for circles, polygons, or other shapes.
Quick Recap
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.

