Add bottom-only footers to PDFs in bulk. Works well on scanned PDFs and mixed rotations.
Left footer shows the relative file path. Right footer shows Page i/N.
Pages that appear internally flipped are skipped to avoid stamping at the visual top.
- Recursively finds PDFs starting from the current working directory
- Places a bottom-only footer inside each page’s visible area (CropBox)
- Handles
/Rotate0, 90, 180, 270 - Skips pages that look internally flipped in their content stream
- Keeps originals unchanged, writes results to
PDF_with_Footer/with_footer.pdfsuffix - Ignores
PDF_with_Footer/when scanning so it never reprocesses its own output
You can run this in any folder that contains PDFs, including nested subfolders. Example:
your-docs-root/
contracts/
2023/
NDA.pdf
SOW.pdf
receipts/
jan/
store-a.pdf
store-b.pdf
notes.pdf
main.py
requirements.txt
.gitignore
README.md
- The script scans everything under the folder where you run it.
- Processed files are written to:
your-docs-root/PDF_with_Footer/<original-name>_footer.pdf - The input layout can be any set of folders. You do not need special names like
Lesson 011.
If you want to process a different tree, either:
- Copy
main.pyinto that folder and run it there, or - Open a terminal in that folder and run
python3 main.pyfrom there.
- Python 3.9 or newer
pipavailable in your path
# 1) Clone your repo
git clone https://github.com/<your-username>/pdf-bottom-footer-stamper.git
cd pdf-bottom-footer-stamper
# 2) Create and activate a virtual environment
python3 -m venv .venv
source .venv/bin/activate
# 3) Install dependencies
pip install -r requirements.txt# 1) Clone your repo
git clone https://github.com/<your-username>/pdf-bottom-footer-stamper.git
cd pdf-bottom-footer-stamper
# 2) Create and activate a virtual environment
py -3 -m venv .venv
.venv\Scripts\Activate.ps1
# 3) Install dependencies
pip install -r requirements.txtgit clone https://github.com/<your-username>/pdf-bottom-footer-stamper.git
cd pdf-bottom-footer-stamper
py -3 -m venv .venv
call .venv\Scripts\activate.bat
pip install -r requirements.txtUse the same steps as macOS and Linux. Replace python3 with the correct Python command if needed.
- Place
main.pyin the root folder that contains the PDFs you want to stamp. - Open a terminal in that folder and run:
python3 main.pyOn Windows you can also use:
py -3 main.pyOutput will appear in a new folder:
./PDF_with_Footer/<original-name>_footer.pdf
If you change footer settings in main.py or want to regenerate everything:
- Delete the
PDF_with_Footer/folder - Run
python3 main.pyagain
The script never modifies originals.
Processing: contracts/2023/NDA.pdf
Processing: receipts/jan/store-a.pdf
↪︎ skipped page 2 (reflected/flip matrix in content)
Processing: notes.pdf
...
Best-effort stamping complete (bottom-only).
Check the folder: /full/path/to/PDF_with_Footer
receipts/jan/store-a.pdf Page 2/5
- The left side shows the PDF’s relative path from the root where you ran the script.
- The right side shows Page i/N.
Open main.py if you want to adjust:
margin_x,margin_yfor spacing from edges- Trimming length of the left text (the relative path)
- Font family and size used by ReportLab
Re-run after changes. If you want to remove previous results, delete PDF_with_Footer/ and run again.
-
Some scanned pages are stored upside down without a
/Rotateflag. The script uses a best effort check on the content stream. If it detects a likely flipped page, it skips stamping that page to avoid a top footer. -
If you must stamp every page, normalize scans first, then run the stamper:
macOS and Linux
brew install ocrmypdf # macOS with Homebrew ocrmypdf --rotate-pages --rotate-pages-threshold 12 input.pdf fixed.pdfWindows
- Install OCRmyPDF from the official docs
- Then run the same
ocrmypdfcommand in PowerShell or CMD
-
Very old PyPDF2 versions behave differently. The repo pins versions in
requirements.txtthat work well.
- No output files: ensure you are running from the correct folder and that there are PDFs beneath it.
- Footer at the top: those pages are likely internally flipped without rotation metadata. The script will try to detect this and skip. Pre-normalize with OCRmyPDF if you want to stamp them.
- Text too long: paths are trimmed. You can shorten deep folder names or adjust the trim logic in code.
- Permission errors on Windows: if PowerShell blocks scripts, run
Set-ExecutionPolicy -Scope CurrentUser RemoteSignedin an elevated PowerShell window.
See requirements.txt:
PyPDF2>=3.0.0
reportlab>=4.0.0
Wineel Wilson Dasari
- Email: wineel10wilson@gmail.com
- GitHub: @wineel