Skip to content

Repository files navigation

📄 pdf-helper

A set of helpful PDF utilities — compress, split/merge, convert to Word or JPG, extract images and decrypt — available as command-line scripts and a small Flask API.

License: GPL v3

The heavy lifting is done by PyMuPDF, PyPDF2, pdf2docx and the Ghostscript command-line tool. Most functionality is bundled into a single multi-action CLI (pdf_util.py); single-purpose scripts and an HTTP API (app.py) expose the same operations.

✨ Features

  • Compress PDFs via Ghostscript with five quality presets (default, prepress, printer, ebook, screen)
  • Split PDFs: one file per page, custom page ranges (e.g. 1-3,7), fixed-size chunks, or merge selected ranges into a single PDF; multi-file output is delivered as a ZIP
  • Convert PDF → Word (.docx) with pdf2docx
  • Render PDF pages → JPG at a chosen DPI, zipped
  • Extract embedded images from a PDF (CMYK images converted to RGB), zipped
  • Decrypt password-protected PDFs
  • Flask API exposing POST /compress_pdf and POST /split_pdf, plus a sample requests client

📋 Requirements

  • Python 3
  • Ghostscript installed and on PATH (gs, gswin32 or gswin64) — required for all compression features; the scripts invoke the executable directly (the ghostscript pip package in requirements.txt is not what does the work)
  • Python packages:
pip install -r requirements.txt
pip install pdf2docx   # imported by pdf_to_word.py / pdf_util.py but not listed in requirements.txt

🛠 Installation

git clone https://github.com/mkamranr/pdf-helper.git
cd pdf-helper
pip install -r requirements.txt
pip install pdf2docx
mkdir PDFFiles   # working directory expected by the Flask app and sample client

🚀 Usage

All-in-one CLI (pdf_util.py)

# PDF -> Word
python pdf_util.py -a pdf_to_word -i input.pdf -o output.docx

# Split: one PDF per page, zipped
python pdf_util.py -a split_pdf -i input.pdf -o pages.zip

# Split: specific pages/ranges, zipped
python pdf_util.py -a split_pdf -i input.pdf -p "1-3,7" -o parts.zip

# Merge the selected ranges into ONE output PDF instead of a ZIP
python pdf_util.py -a split_pdf -i input.pdf -p "1-3,7" -m 1 -o merged.pdf

# Split into fixed 10-page chunks, zipped
python pdf_util.py -a split_pdf -i input.pdf -f 10 -o chunks.zip

# Render every page to JPG at 150 DPI, zipped
python pdf_util.py -a convert_pdf_to_jpg -i input.pdf -o images.zip -q 150

# Extract embedded images, zipped
python pdf_util.py -a extract_images_from_pdf -i input.pdf -o extracted_images.zip

# Decrypt an encrypted PDF
python pdf_util.py -a decrypt_pdf -i locked.pdf -s mypassword -o decrypted_file.pdf
Flag Meaning
-a, --action pdf_to_word, split_pdf, convert_pdf_to_jpg, extract_images_from_pdf, decrypt_pdf
-i, --input input PDF path
-o, --out output path (defaults: converted.docx, splitted.zip, images.zip, extracted_images.zip, decrypted_file.pdf)
-p, --pages page ranges, e.g. "1-3,7"; empty = every page separately
-m, --merge 1 = merge selected ranges into a single PDF (only when -f is not used)
-f, --fixedrange split into chunks of N pages
-s, --password password for decrypt_pdf
-q, --quality DPI for convert_pdf_to_jpg (default 150)

Single-purpose scripts

# Ghostscript compression: -c 0=default 1=prepress 2=printer 3=ebook 4=screen
# (defaults: level 2 "printer", output temp.pdf)
python pdf_compressor.py -i input.pdf -o compressed.pdf -c 3

# Same split engine as pdf_util.py (-p / -m / -f as above)
python pdf_split.py -i input.pdf -p "1-3,7" -o parts.zip

# PDF -> DOCX (default output converted.docx)
python pdf_to_word.py -i input.pdf -o output.docx

# Older positional-argument script
python split_pdf.py split input.pdf pages.zip
python split_pdf.py compress input.pdf compressed.pdf 50

Flask API

python app.py    # serves on http://localhost:5000 in debug mode
  • POST /compress_pdf — multipart field file plus form field compression_level (0=default, 1=prepress, 2=printer, 3=ebook, 4=screen); returns the compressed PDF
  • POST /split_pdf — multipart field file; returns a ZIP containing one PDF per page
curl -F "file=@input.pdf" -F "compression_level=4" http://localhost:5000/compress_pdf -o compressed.pdf
curl -F "file=@input.pdf" http://localhost:5000/split_pdf -o pages.zip

main.py is a sample client: edit api_url and file_path at the bottom (as shipped it posts PDFFiles/Configuration.pdf to /split_pdf and saves the returned ZIP under PDFFiles/), then run python main.py.

⚙️ How it works

Splitting uses PyMuPDF (fitz): pages are copied with insert_pdf into per-range documents written to a temp folder, then zipped — or appended into one merged document when -m 1 is set. Compression shells out to Ghostscript's pdfwrite device with -dPDFSETTINGS presets and reports the size reduction. Word conversion delegates to pdf2docx's Converter. JPG rendering rasterises each page with page.get_pixmap using a DPI-derived zoom matrix; image extraction walks each page's image XObjects and saves them as PNG (CMYK converted to RGB first). Decryption uses PyPDF2's PdfReader.decrypt and rewrites all pages. The Flask app wraps Ghostscript compression and a PyPDF2 per-page split behind HTTP endpoints, storing intermediate files in PDFFiles/.

📁 Project structure

File Purpose
pdf_util.py All-in-one CLI: to-Word, split/merge, to-JPG, image extraction, decryption
pdf_compressor.py Ghostscript compression CLI (levels 0–4)
pdf_split.py Split/merge CLI (same engine as pdf_util.py)
pdf_to_word.py PDF → DOCX CLI
split_pdf.py Older positional-args split/compress script
app.py Flask API: /compress_pdf, /split_pdf (port 5000)
main.py Sample requests client for the API
requirements.txt Pinned dependencies
LICENSE GPL-3.0

⚠️ Notes / Limitations

  • app.py and pdf_compressor.py use subprocess.STARTUPINFO, which only exists on Windows — as written, those two compression paths fail on macOS/Linux (split_pdf.py's Ghostscript call is plain and cross-platform; pdf_util.py has no compress action).
  • The Flask app expects a PDFFiles/ directory to exist next to app.py, runs with debug=True, and does not clean up saved uploads.
  • pdf_util.py accepts -c/--compress but implements no compression action.
  • split_pdf.py's compress action reads an image-quality argument but always calls Ghostscript with the fixed ebook preset.
  • requirements.txt omits pdf2docx and includes packaging extras (pyinstaller, pywin32-ctypes) not used by the scripts at runtime.

📄 License

This project is licensed under the GNU General Public License v3.0 — see LICENSE.

About

Set of helpful PDF utilities

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages