Skip to content
Remove Image Watermark

Remove Image Watermark

PdfPage.RemoveWatermarkImage deletes a watermark image from a page: it drops the entry from the page’s XObject resources, cuts the operators that drew it out of the content stream, and strips any watermark annotations. There is no document-level call, so you iterate the pages yourself.

Which name to pass

ArgumentWhat gets removed
""Any XObject marked as an Adobe watermark, plus all watermark annotations.
"Img1"The XObject with that exact name, plus all watermark annotations.

The empty-string form works on watermarks applied by Adobe products, which tag the XObject with an ADBE_CompoundType piece-info entry whose Private value is Watermark. Nothing else sets that tag, so a watermark added by UniPDF or by another library will not be found this way.

For everything else you need the XObject’s name. Get it by listing the page’s images; the list images guide covers that, and the name it prints for each XObject image is exactly what goes here.

Doing it

for i := 0; i < numPages; i++ {
    page, err := pdfReader.GetPage(i + 1)
    if err != nil {
        return err
    }

    // "" for Adobe-applied watermarks, otherwise the XObject name.
    if err := page.RemoveWatermarkImage("Img1"); err != nil {
        return err
    }
}

pdfWriter, err := pdfReader.ToWriter(nil)
if err != nil {
    return err
}
return pdfWriter.WriteToFile(outputPath)

Names are scoped to a page’s resource dictionary, so the same watermark can be /Img1 on one page and /Im3 on another. Do not assume one name covers the document; list the images per page if the input is not something you produced yourself.

Annotation removal is unconditional. Every call strips all Watermark subtype annotations from the page regardless of the name argument, so a watermark that exists only as an annotation is removed by any call, including one with a name that matches nothing.

Limitations

The method returns nil whether or not it removed anything. A misspelled name, a name from the wrong page, or a document with no watermark at all all look like success. Verify by listing the page’s images afterwards.

Cutting the drawing operators out is done by string editing, not by parsing: for the content stream containing the name, everything between the nearest preceding q and the following Q is deleted. That is exactly right for a watermark added by AddWatermarkImage, which emits its own q ... Q block. Where the XObject is invoked inside a larger q ... Q group, other operators in that group go with it.

Only the first content stream containing the name is edited per stream object, so an XObject drawn more than once inside a single stream may leave a Do behind that now refers to a removed resource. Viewers generally ignore it, but a strict validator may not.

Removing the resource entry does not shrink the file on its own. The image stream becomes unreferenced; run the optimizer if size matters.

Run the example

The example walks every page of the input, removes the XObject named Img1, and writes the result through a PdfWriter. It is all in main. Change the name argument to match the document you’re working on.

git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/watermarks
go run pdf_remove_watermark_image.go input.pdf output.pdf

If this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.

View the full source
Last updated on