"Just remove the watermark" is one of those tasks that sounds trivial until you open the file. I've lost count of how many times someone has told me a tool "doesn't work", when the real issue was that they were dealing with a different kind of watermark than the tool was built for.
There are three, and they live in completely different places in the file.
Type 1: an annotation
This is the easy one. The watermark is an object in the page's /Annots array — the same mechanism as a sticky note or a highlight. It's drawn on top of the page, but it isn't part of the page content.
Anything that can edit annotations can delete it. On the command line:
# see what annotations exist
pdfinfo -meta file.pdf
qpdf --show-object=trailer file.pdf | head
Most "PDF watermark remover" tools stop here. Which is fine, as long as that's what you actually have.
Type 2: a Form XObject
This is where it gets interesting. The watermark is a reusable content object referenced from the page's resource dictionary and painted via a Do operator in the content stream. It is page content now — there's no annotation to select and delete.
Removing it means:
- finding the XObject in
/Resources /XObject - following the mapping through
/Formand theMatrix×DoCTM combination (a naive search misses nested forms) - deleting the object and its reference
- writing the stream back and clearing the stale filter keys (
Filter,DecodeParms,F,FFilter,FDecodeParms,DL)
Step 2 is why simple text-matching approaches fail. The content stream is compressed, the object may be nested several levels deep, and the positioning math is composed at draw time rather than stored as coordinates.
Type 3: baked into a scan
If the PDF is a scanned image, the watermark is pixels. No PDF-level tool will remove it — that's image editing, and results are usually ugly.
Worth checking before you try anything else:
pdftotext file.pdf - | wc -c
If that returns almost nothing, you're looking at a scan. Stop trying PDF tools.
How to tell which one you have
Quick heuristic:
pdfinfo file.pdf | grep -i pages
pdftotext file.pdf - | head -20 # text present?
qpdf --qdf --object-streams=disable file.pdf out.pdf
grep -a -n "/Annots\|/XObject\|/Watermark" out.pdf | head
If /Annots shows up with a /Subtype /Watermark entry, it's type 1. If you find /XObject forms that don't correspond to visible images, it's probably type 2.
The part that actually matters
Whatever you remove, verify afterwards. A lot of tools — including some well-known paid ones — "remove" content by drawing an opaque rectangle over it. The underlying text is untouched and trivially recoverable:
pdftotext cleaned.pdf - | grep -in "confidential\|salary\|身份证"
If that prints anything, the file is not clean. I've seen contracts go out to counterparties with the "redacted" salary figure still in the text layer, because whoever prepared it trusted the visual preview.
For type 1 and 2, a proper removal should survive this check. For type 3, it won't — and that's the honest signal that you need a different approach.
Disclosure: I work on PDFnoted, which does object-level watermark removal and re-scans the file after cleaning. The three-type distinction here is tool-independent though — knowing which one you have will save you most of the time regardless of what you use.
Top comments (0)