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 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 - left and height is lower - 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.

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

Crop an image in Python with Pillow

Install Pillow

Install the current Pillow package in the environment that runs your script:

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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).

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.

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

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from 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.

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

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.

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

Performance 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.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

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.

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

“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.

“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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

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

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.

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.