Files
2026-07-25 21:31:59 +02:00

5.8 KiB
Raw Permalink Blame History

PDF Toolkit

A small command-line toolkit for common PDF operations, built with Python and PyMuPDF (fitz).

The scripts can:

  • extract a page range from a PDF;
  • join two PDF files;
  • place consecutive pages side by side while preserving links; and
  • remove repeated text such as a text-based watermark.

Project structure

PDF-Toolkit/
├── requirements.txt
└── scripts/
    ├── extract_pages.py
    ├── join_files.py
    ├── side_by_side.py
    └── watermark_remover.py

Requirements

  • Python 3.10 or later is recommended.
  • Dependencies listed in requirements.txt.
  • PyMuPDF, imported by the scripts as fitz.

Installation

Clone or download the project, then create and activate a virtual environment.

macOS and Linux

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt

Windows PowerShell

python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt

Run the examples below from the project root. Quote paths that contain spaces.

Tools

Extract pages

extract_pages.py copies an inclusive range of pages from a source PDF into a new PDF. Page numbers are one-based, so the first page is page 1.

python scripts/extract_pages.py INPUT_PDF OUTPUT_PDF START END

Arguments:

Argument Description
INPUT_PDF Path to the source PDF.
OUTPUT_PDF Path for the extracted PDF.
START First page to extract, inclusive.
END Last page to extract, inclusive.

Example—extract pages 3 through 8:

python scripts/extract_pages.py documents/report.pdf output/report-pages-3-8.pdf 3 8

The output is saved with garbage collection, compression, and font/image deflation enabled.

Join two PDFs

join_files.py appends the complete second PDF to the complete first PDF and saves the result as a third file.

python scripts/join_files.py FIRST_PDF SECOND_PDF OUTPUT_PDF

Arguments:

Argument Description
FIRST_PDF PDF whose pages appear first.
SECOND_PDF PDF appended after the first file.
OUTPUT_PDF Path for the combined PDF.

Example:

python scripts/join_files.py documents/part-1.pdf documents/part-2.pdf output/combined.pdf

This tool accepts exactly two input PDFs per invocation. To combine more files, run it repeatedly using the previous output as the next first input.

Place pages side by side

side_by_side.py creates a two-page-wide, or “2-up,” PDF. It places consecutive source pages next to each other:

  • the first page in each pair is placed on the left;
  • the second page is placed on the right; and
  • an unpaired final page is placed by itself.

The script also remaps link annotations so that external URLs and internal page links continue to work in the new layout. Other link types are copied on a best-effort basis.

python scripts/side_by_side.py INPUT_PDF OUTPUT_PDF START_PAGE

Arguments:

Argument Description
INPUT_PDF Path to the source PDF.
OUTPUT_PDF Path for the side-by-side PDF.
START_PAGE One-based source page at which processing begins. Earlier pages are omitted.

Example—start at page 1:

python scripts/side_by_side.py documents/manual.pdf output/manual-2up.pdf 1

Example—skip the cover and start at page 2:

python scripts/side_by_side.py documents/manual.pdf output/manual-2up.pdf 2

Because the output contains only pages from START_PAGE onward, internal links that point to an omitted earlier page are not expected to have a valid destination. The current implementation is best suited to files whose relevant link targets are included in the processed range.

Remove a text watermark

watermark_remover.py searches every page for an exact text string, adds redaction annotations over every match, applies the redactions, and saves a cleaned copy.

python scripts/watermark_remover.py INPUT_PDF OUTPUT_PDF WATERMARK_TEXT

Arguments:

Argument Description
INPUT_PDF Path to the source PDF.
OUTPUT_PDF Path for the processed PDF.
WATERMARK_TEXT Exact text to find and redact. Quote text containing spaces.

Example:

python scripts/watermark_remover.py documents/sample.pdf output/sample-clean.pdf "CONFIDENTIAL"

The script prints the rectangle of each match and reports the output path when processing is complete. Images intersecting a redaction are preserved because redactions are applied with PDF_REDACT_IMAGE_NONE.

Important: This tool works on searchable PDF text. It will not detect a watermark that is embedded only as an image, converted to outlines, or otherwise absent from the PDF text layer. Redaction permanently removes matched content from the generated output, so keep the original file as a backup.

Getting command help

Each script uses argparse. Run a script with --help to see its command syntax:

python scripts/extract_pages.py --help
python scripts/join_files.py --help
python scripts/side_by_side.py --help
python scripts/watermark_remover.py --help

Notes

  • Input files must exist and be readable.
  • The destination directory must already exist.
  • Existing output files may be overwritten or may cause an error depending on the platform and PyMuPDF behavior, so use a new output path when possible.
  • These scripts do not currently perform explicit validation for page ranges, encrypted PDFs, damaged files, or an output path that matches an input path.
  • Always verify the generated PDF before deleting or replacing the original.

Dependency

The scripts use PyMuPDF:

PyMuPDF

Keep the projects requirements.txt as the authoritative dependency list and install it with:

python -m pip install -r requirements.txt