Cropping a PDF means reducing the visible area of each page, typically to remove unwanted margins, cut out a region of interest, or trim a scanned document to its content boundary. This guide covers the free online method and four programmatic approaches: pdf-lib (Node.js), PyMuPDF (Python), Ghostscript, and qpdf.
How PDF cropping works: CropBox vs MediaBox
A PDF page has several bounding boxes. The two you need to know when cropping are:
| Box | Purpose | Default |
|---|---|---|
| MediaBox | Full physical page size (always present) | Set at creation |
| CropBox | Region shown by viewers and printers | Falls back to MediaBox |
Most cropping tools adjust only the CropBox. The content outside the CropBox stays in the file but is not displayed. This means a simple crop is reversible: reset the CropBox to the MediaBox and the full content reappears. To permanently discard the hidden area (and shrink the file), you must re-render the page through a PDF printer like Ghostscript.
How to crop a PDF online (free, no upload)
The PDF4.dev crop PDF tool runs entirely in your browser using pdf-lib. Files are never sent to a server.
- Open pdf4.dev/tools/crop-pdf and drop your PDF onto the upload area.
- A thumbnail of the first page appears. Enter margin values (in mm) for top, bottom, left, and right.
- Choose whether to apply the crop to all pages or a custom page range.
- Click Crop PDF and download the result.
The tool applies the crop by adjusting the CropBox on each selected page. For per-page cropping with different values, process the file in multiple passes.
Crop a PDF online, freeTry it freeHow to crop a PDF with pdf-lib (Node.js)
pdf-lib is a pure-JavaScript library that runs in Node.js and the browser. It adjusts the CropBox directly.
npm install pdf-libimport { PDFDocument } from "pdf-lib";
import { readFileSync, writeFileSync } from "fs";
async function cropPdf(
inputPath: string,
outputPath: string,
margins: { top: number; bottom: number; left: number; right: number }
) {
const bytes = readFileSync(inputPath);
const doc = await PDFDocument.load(bytes);
for (const page of doc.getPages()) {
const { width, height } = page.getSize();
// PDF coordinates: origin is bottom-left
const x = margins.left;
const y = margins.bottom;
const w = width - margins.left - margins.right;
const h = height - margins.top - margins.bottom;
page.setCropBox(x, y, w, h);
}
const output = await doc.save();
writeFileSync(outputPath, output);
console.log(`Cropped PDF saved to ${outputPath}`);
}
// Crop 10pt from each side (1 point ≈ 0.353 mm)
cropPdf("input.pdf", "output.pdf", {
top: 10,
bottom: 10,
left: 10,
right: 10,
});Convert mm to points
PDF dimensions use points (1 inch = 72 points). To convert millimetres:
const mmToPoints = (mm: number) => (mm / 25.4) * 72;
// Crop 5mm from each side
const margin = mmToPoints(5); // ≈ 14.17pt
page.setCropBox(margin, margin, width - margin * 2, height - margin * 2);Crop to a specific page only
const pages = doc.getPages();
const pageIndex = 0; // first page
const page = pages[pageIndex];
const { width, height } = page.getSize();
page.setCropBox(20, 20, width - 40, height - 40);How to crop a PDF with PyMuPDF (Python)
PyMuPDF (pymupdf) provides page.set_cropbox() which accepts a Rect in points.
pip install pymupdfimport pymupdf # pip install pymupdf
def crop_pdf(input_path: str, output_path: str, margin_pt: float = 14.17):
"""Crop all pages by removing a uniform margin (in points)."""
doc = pymupdf.open(input_path)
for page in doc:
rect = page.rect # MediaBox as a Rect
cropped = pymupdf.Rect(
rect.x0 + margin_pt,
rect.y0 + margin_pt,
rect.x1 - margin_pt,
rect.y1 - margin_pt,
)
page.set_cropbox(cropped)
doc.save(output_path, garbage=4, deflate=True)
print(f"Saved: {output_path}")
# Crop 5mm (≈ 14.17pt) from all sides
crop_pdf("input.pdf", "output.pdf", margin_pt=14.17)Crop to content bounding box (auto-trim whitespace)
PyMuPDF can detect where the actual content sits and crop to that boundary automatically:
import pymupdf
doc = pymupdf.open("input.pdf")
for page in doc:
# get_text("blocks") returns (x0, y0, x1, y1, text, block_no, block_type) tuples
blocks = page.get_text("blocks")
if not blocks:
continue
# Compute bounding box of all text blocks
xs = [b[0] for b in blocks] + [b[2] for b in blocks]
ys = [b[1] for b in blocks] + [b[3] for b in blocks]
padding = 14 # add 5mm padding
bbox = pymupdf.Rect(min(xs) - padding, min(ys) - padding,
max(xs) + padding, max(ys) + padding)
page.set_cropbox(bbox)
doc.save("output.pdf", garbage=4, deflate=True)Auto-trim works well for text-heavy documents. For scanned PDFs or image-only pages, use the image bounding box from
page.get_image_info()instead.
How to crop a PDF with Ghostscript (command line)
Ghostscript re-renders the visible area into a new page, permanently removing content outside the crop region and reducing file size.
# Install on macOS
brew install ghostscript
# Install on Ubuntu/Debian
sudo apt install ghostscriptSet a new page size and translate the coordinate system
gs \
-sDEVICE=pdfwrite \
-dNOPAUSE \
-dBATCH \
-dFIXEDMEDIA \
-dPDFFitPage \
-g5954x8419 \
-c "-14 -14 translate" \
-f input.pdf \
-sOutputFile=output.pdfWhat each flag does:
| Flag | Effect |
|---|---|
-dFIXEDMEDIA | Lock the output page size instead of inheriting from input |
-dPDFFitPage | Scale content to fit the new page size |
-g<width>x<height> | Output dimensions in pixels at 72dpi (so 1 unit = 1pt): 5954x8419 ≈ A4 minus 5mm on each side |
-c "<x> <y> translate" | Shift coordinate origin to skip the left/bottom margin |
Calculate the output dimensions
For an A4 page (595 x 842 pt) cropped 5mm (≈ 14pt) on each side:
- Width: 595 - 14 - 14 = 567 pt →
-g5670x8140 - Height: 842 - 14 - 14 = 814 pt
- Translate:
-c "-14 -14 translate"(shift origin past the left/bottom margin)
gs -sDEVICE=pdfwrite -dNOPAUSE -dBATCH \
-dFIXEDMEDIA -dPDFFitPage \
-g5670x8140 \
-c "-14 -14 translate" \
-f input.pdf \
-sOutputFile=output_cropped.pdfGhostscript processes all pages with the same settings. For per-page crops, split the PDF first, crop each page, then merge with
pdfuniteor the merge PDF tool.
How to crop a PDF with qpdf (command line)
qpdf 11+ supports --crop which adjusts the CropBox without re-rendering, so it is fast and lossless.
# Install on macOS
brew install qpdf
# Install on Ubuntu/Debian
sudo apt install qpdf# Syntax: --crop=left,top,right,bottom (in points from the page edges)
qpdf --crop=14,14,14,14 input.pdf output.pdfThis removes 14 points (≈ 5mm) from each side by setting the CropBox. The original content is preserved in the MediaBox. To apply to specific pages only:
# Crop pages 1-3 only
qpdf --crop=14,14,14,14:1-3 input.pdf output.pdfComparison: which method to use?
| Method | Removes hidden content | Speed | Per-page control | Use case |
|---|---|---|---|---|
| PDF4.dev tool | No | Instant | All or range | Quick one-off, no code |
| pdf-lib | No | Fast | Full (loop) | Node.js automation, client-side |
| PyMuPDF | No | Fast | Full (loop) | Python scripts, data pipelines |
| Ghostscript | Yes | Slower | One crop for all | Print-ready, file size reduction |
| qpdf | No | Fastest | Page ranges | Batch scripts, lossless crop |
Results marked "No" for hidden content removal mean the content outside the CropBox stays embedded in the file. Use Ghostscript or the compress PDF tool after cropping to strip it out.
Common use cases
Remove scanned borders. Flatbed scanners often capture a grey border outside the document area. Set a uniform margin of 8-15pt to trim it cleanly.
Crop a two-column PDF to one column. Set the right margin to 50% of the page width to show only the left column, then repeat with the left margin at 50% to extract the right column. Merge both outputs for a single-column reading layout.
Trim slide decks. PowerPoint-exported PDFs often include thick white borders. Crop 20-30pt from each side to make the content fill more screen space.
Prepare files for print. Professional printers request documents with 3mm bleed (content extending past the trim line). Use the crop tool to verify the visible area matches the intended trim size before sending to press.
Extract a region of a page. Combine cropping with page extraction: extract the target page with the extract pages tool, then crop it to the exact bounding box of the element you want.
Summary
- Cropping a PDF adjusts the CropBox, not the MediaBox. Hidden content stays in the file unless you re-render with Ghostscript.
- For quick crops with no code, use the PDF4.dev crop PDF tool — browser-only, instant, free.
- For Node.js automation,
pdf-libwithsetCropBoxis the simplest path. - For Python,
PyMuPDFwithset_cropboxhandles single pages and whole documents equally well. - For permanent content removal and file size reduction, Ghostscript re-renders the visible area into a clean new page.
- For fast lossless batch scripts,
qpdf --cropis the most straightforward command-line option.
Start generating PDFs
Build PDF templates with a visual editor. Render them via API from any language in ~300ms.


