Use PyMuPDF when you want the shortest reliable way to put an image behind the existing content on every PDF page. Open the source file, insert the image across each page with overlay=False, and save to a different output file. The complete script is:
import pymupdf
doc = pymupdf.open("document.pdf")
for page in doc:
page.insert_image(page.bound(), filename="watermark.png", overlay=False)
doc.save("watermarked-document.pdf")
This places the image at the base of each page, so the PDF text remains in front. The rest of this guide explains sizing, opacity, page rotation, selective stamping, a pypdf alternative, troubleshooting, and ways to verify a published PDF.
| # | Preview | Product | Price | |
|---|---|---|---|---|
| 1 |
|
Digital Watermarking for PDF and PostScript Documents | $95.00 | Buy on Amazon |
| 2 |
|
Bodies of Water (Book 2) | $19.99 | Buy on Amazon |
What “watermark” means in a PDF
PDF libraries commonly distinguish a watermark from a stamp by its layer. A watermark is an underlay: it is merged beneath existing page content. A stamp is an overlay: it is placed on top. For an image that should appear faintly behind text, use an underlay.
- Underlay: the original text and graphics remain above the image.
- Overlay: the image can cover or obscure content unless you make it transparent and position it carefully.
- Page coordinates: the image must be inserted into a rectangle on each page; the page’s bounding rectangle is the simplest full-page target.
Keep the watermark’s aspect ratio intentional. A logo stretched to fill a portrait page will look distorted; a transparent PNG with whitespace around the mark may also appear smaller than expected.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall#1 Best Overall
Prerequisites and installation
Use a current Python 3 installation and work in a virtual environment so the PDF libraries do not conflict with other projects.
- Create and activate an environment:
python -m venv .venv, then use.venvScriptsactivateon Windows orsource .venv/bin/activateon macOS and Linux. - Install PyMuPDF:
python -m pip install PyMuPDF. - Put
document.pdfandwatermark.pngin the working directory, or provide absolute paths.
PyMuPDF is imported as pymupdf. The watermark can be PNG, JPEG, or another image format accepted by the library. Transparency and opacity are properties of the image you supply; the insertion call does not automatically make an opaque image faint.
Watermark every page with PyMuPDF
Minimal underlay script
import pymupdf
input_path = "document.pdf"
watermark_path = "watermark.png"
output_path = "watermarked-document.pdf"
doc = pymupdf.open(input_path)
for page in doc:
page.insert_image(
page.bound(),
filename=watermark_path,
overlay=False,
)
doc.save(output_path)
doc.close()
print(f"Saved {output_path}")
page.bound() returns the page rectangle, so the image is placed over the entire page area. With overlay=False, it is inserted at the base of the page. Use a separate output filename; saving over the input while it is open can fail or destroy your original if a later operation goes wrong.
Reuse image data on large documents
When the same image is inserted repeatedly, reuse its image data rather than repeatedly loading and embedding it. This can reduce memory use and repeated image data in the output. A practical pattern is:
import pymupdf
src = pymupdf.open("document.pdf")
img = open("watermark.png", "rb").read()
for page in src:
page.insert_image(page.bound(), stream=img, overlay=False)
src.save("watermarked-document.pdf")
src.close()
The exact output size depends on the source image, PDF contents, and compression. Treat reuse as an efficiency technique, not a guaranteed file-size reduction for every document.
Use a deliberate rectangle instead of the whole page
To place a logo in a corner or center it without distortion, create a rectangle with the desired dimensions. For example:
import pymupdf
doc = pymupdf.open("document.pdf")
for page in doc:
r = page.rect
width = 180
height = 60
margin = 24
box = pymupdf.Rect(
r.x1 - width - margin,
r.y1 - height - margin,
r.x1 - margin,
r.y1 - margin,
)
page.insert_image(box, filename="watermark.png", overlay=False)
doc.save("corner-watermark.pdf")
This example places the image near the lower-right corner. Set the rectangle’s width and height to match the image’s intended aspect ratio. If the source image has a different ratio, calculate one dimension from the other rather than stretching it.
Opacity, aspect ratio, and page appearance
Opacity belongs in the image
Prepare a transparent PNG with the desired alpha level before insertion. An image with fully opaque pixels will remain visually strong even when used as an underlay; underlying text may become difficult to read if the image has a solid background.
Full-page versus logo watermarks
- Full-page background: use a faint, transparent image and
page.bound(). This is useful for patterns or ownership notices. - Centered logo: use a smaller rectangle, preserving the logo’s ratio.
- Corner mark: reserve a margin so the image does not collide with page numbers or bleed areas.
Do not assume every page has the same size
page.bound() adapts to each page’s dimensions. A fixed rectangle does not, so calculate its position from page.rect when the document mixes letter, A4, landscape, or custom pages.
Selective pages and conditional placement
The basic loop processes every page. To watermark only selected pages, use the zero-based page index:
import pymupdf
doc = pymupdf.open("document.pdf")
for index, page in enumerate(doc):
if index in {0, 4, 9}: # pages 1, 5, and 10
page.insert_image(page.bound(), filename="watermark.png", overlay=False)
doc.save("selected-pages.pdf")
For a range, test start <= index < end. Keep the original file until you have opened and checked the result.
pypdf alternative: convert the image to a PDF page
pypdf treats a watermark as an underlay and a stamp as an overlay. Its documented image workflow converts the image into a one-page PDF with Pillow, then merges that page into each source page. over=False places it beneath existing content; over=True places it on top.
from io import BytesIO
from PIL import Image
from pypdf import PdfReader, PdfWriter, Transformation
def image_to_pdf(path):
image = Image.open(path)
buffer = BytesIO()
image.save(buffer, "PDF")
buffer.seek(0)
return PdfReader(buffer)
source = PdfReader("document.pdf")
watermark = image_to_pdf("watermark.png").pages[0]
writer = PdfWriter()
for page in source.pages:
page.merge_transformed_page(
watermark,
Transformation(),
over=False,
)
writer.add_page(page)
with open("watermarked-document.pdf", "wb") as output:
writer.write(output)
Choose pypdf when the watermark is naturally a reusable PDF page and you need merge transformations, translation, rotation, or more explicit per-page composition. Use over=True for a foreground stamp. The transformation object can be expanded to scale, rotate, or translate the watermark.
Handle rotated pages before merging
A PDF page can carry a rotation value instead of having rotated coordinates baked into its content. If a pypdf watermark appears rotated or misplaced, transfer the page rotation to its content before merging, as recommended in pypdf’s documentation. Then apply the transformation and add the page to the writer.
Rank #2
PyMuPDF or pypdf?
| Need | Better fit | Reason |
|---|---|---|
| Insert one image behind every page quickly | PyMuPDF | Direct image insertion with insert_image and a page rectangle. |
| Put an image beneath or above existing content | Either | PyMuPDF uses overlay=False; pypdf uses over=False or over=True. |
| Scale, rotate, or translate a reusable watermark page | pypdf | Merge-based composition with Transformation. |
| Adapt automatically to each page’s full bounds | PyMuPDF | page.bound() supplies the target rectangle. |
| Reuse one image across many pages | Either | Reuse image/page data and avoid reopening the source for every page. |
These are workflow distinctions documented by the projects, not benchmark claims. Neither library guarantees a particular runtime or output-size percentage for every PDF.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Verification and troubleshooting
The watermark covers the text
Cause: it was inserted as an overlay, or the image itself is opaque. Fix: use overlay=False in PyMuPDF or over=False in pypdf, and prepare a transparent image with suitable opacity.
The logo is stretched
Cause: the target rectangle has a different aspect ratio. Fix: calculate the rectangle from the image ratio and leave transparent padding outside the visible logo if needed.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Only the first page is watermarked
Cause: the insertion call is outside the page loop. Fix: indent it inside for page in doc: or the equivalent pypdf loop.
The watermark is missing on rotated pages
Cause: page rotation metadata changes the coordinate interpretation. Fix: with pypdf, call transfer_rotation_to_content before merging; with either library, inspect a rotated page and calculate its rectangle from the page object rather than assuming portrait dimensions.
The output cannot be opened or the input was lost
Cause: writing to the same file that is still open, an interrupted write, or a permissions problem. Fix: save to a new filename, ensure the destination directory is writable, and retain the original until validation succeeds.
The file is unexpectedly large
Cause: repeated image embedding or a very large, uncompressed source image. Fix: reuse image data, resize the watermark to its intended display resolution, and use an appropriately compressed PNG or JPEG. Check readability after any conversion.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsText extraction or signatures changed
Any rewrite can affect PDF internals. If the source is digitally signed, adding a watermark generally invalidates that signature. Preserve the original and apply the watermark before signing, or obtain a new signature afterward.
Or skip the browser setup
If your next step is checking how a published, watermarked PDF renders in a browser, ScreenshotNeo can capture the URL without you configuring a headless browser. It is not a replacement for modifying a local PDF; use the Python workflow above to create the file, publish it at an accessible URL, then capture that page.
One GET request returns an image or PDF. See the ScreenshotNeo documentation for all parameters.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/watermarked-document.pdf -o shot.webp
Before capture, ScreenshotNeo accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status with X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Free tools Windows power users keep installed
One-click scans. No signup required.
Python, cURL, and Node.js capture examples
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com/watermarked-document.pdf"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/watermarked-document.pdf' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);
Frequently Asked Questions
Can I watermark a password-protected PDF?
Open it with the library’s supported password workflow first; if the file cannot be decrypted, neither insertion method can modify it. Keep the password handling separate from the watermark loop.
Will a watermark become permanent and impossible to remove?
The image is written into the page content, but PDF editing tools may still be able to remove or alter it. A watermark is not encryption or digital-rights management.
Should I use PNG or JPEG?
PNG is usually preferable for logos and transparency; JPEG can be smaller for photographic watermarks but has lossy compression and no alpha channel.
Quick Recap
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.




