Product Page | Docs | Demos | API Reference | Blog | Free Support | Temporary License
GroupDocs.Watermark for Python via .NET is a document-watermarking API for adding, searching, and removing text and image watermarks. Stamp configurable text or image watermarks — with control over position, size, opacity, rotation, alignment, and tiling — then save the result back to the original format; search for and remove existing watermarks (including ones added by other tools) across PDF, Word, Excel, PowerPoint, Visio, email, and image formats through one unified API, with no MS Office or other external software required.
Get Started
pip install groupdocs-watermark-net
from groupdocs.watermark import Watermarker
from groupdocs.watermark.watermarks import TextWatermark, Font
with Watermarker("document.pdf") as watermarker:
watermark = TextWatermark("CONFIDENTIAL", Font("Arial", 36.0))
watermark.opacity = 0.5
watermarker.add(watermark)
watermarker.save("watermarked.pdf")
How It Works
The package is a self-contained Python wheel that bundles the embedded .NET runtime and the native libraries it ships (SkiaSharp, Aspose.Drawing) to load, watermark, render, and save documents. On Windows nothing else is needed; on Linux and macOS a few system packages are - see System Requirements. The wheel works across Python 3.5 - 3.14 on 64-bit Windows, Linux, and macOS (Intel + Apple Silicon).
Features
- Text watermarks — configurable font, foreground/background color, opacity, rotation, and alignment.
- Image watermarks — from a file or an in-memory stream, with scaling, opacity, and positioning.
- Positioning & sizing — absolute coordinates, horizontal/vertical alignment, margins, scale-to-parent sizing, and rotation.
- Tiling — repeat a watermark across the page with configurable tile lines and spacing.
- Search — find existing watermarks by text, image, color, size, or rotation, combined with AND/OR/NOT criteria.
- Remove — delete found watermarks individually or in batches and save the cleaned document.
- Document introspection — read format, page count, and per-page dimensions before processing.
- Previews — render pages to PNG/JPEG/BMP images via a page-stream callback.
- Cross-Platform - Windows x64, Linux x64, macOS x64/ARM64.
Common Tasks
- Stamp a "CONFIDENTIAL" text watermark across every page of a PDF and save it back
- Add a semi-transparent logo image watermark to a Word or PowerPoint document
- Tile a watermark diagonally across a page
- Search a document for an existing watermark by its text and remove it
- Read a document's format and page count before processing
- Render watermarked pages to images for a preview UI
Supported File Formats
For a complete list, see supported formats.
| Category | Formats |
|---|---|
| Word Processing | DOC, DOCX, DOCM, DOT, DOTX, RTF, ODT |
| Spreadsheets | XLS, XLSX, XLSM, XLSB |
| Presentations | PPT, PPTX, PPTM, PPS, PPSX |
| Fixed-Layout | |
| Diagrams | VSD, VSDX, VSS, VDX |
| MSG, EML, EMLX | |
| Images | BMP, JPG, JPEG, PNG, GIF, TIFF, WEBP |
Examples
Add a text watermark
from groupdocs.watermark import Watermarker
from groupdocs.watermark.watermarks import TextWatermark, Font, Color
with Watermarker("document.pdf") as watermarker:
watermark = TextWatermark("CONFIDENTIAL", Font("Arial", 48))
watermark.foreground_color = Color.red
watermark.opacity = 0.5
watermark.rotate_angle = -45
watermarker.add(watermark)
watermarker.save("watermarked.pdf")
Add an image watermark
from groupdocs.watermark import Watermarker
from groupdocs.watermark.watermarks import ImageWatermark, SizingType
with Watermarker("document.docx") as watermarker:
watermark = ImageWatermark("logo.png")
watermark.sizing_type = SizingType.SCALE_TO_PARENT_DIMENSIONS
watermark.scale_factor = 0.5
watermark.opacity = 0.7
watermarker.add(watermark)
watermarker.save("watermarked.docx")
Tile a watermark across the page
from groupdocs.watermark import Watermarker
from groupdocs.watermark.watermarks import TextWatermark, Font, TileOptions, TileType
with Watermarker("document.pdf") as watermarker:
watermark = TextWatermark("DRAFT", Font("Arial", 19))
tile = TileOptions()
tile.tile_type = TileType.STRAIGHT # repeat across the page
watermark.tile_options = tile
watermark.opacity = 0.3
watermarker.add(watermark)
watermarker.save("tiled.pdf")
Search for and remove a watermark
from groupdocs.watermark import Watermarker
from groupdocs.watermark.search.search_criteria import TextSearchCriteria
with Watermarker("watermarked.pdf") as watermarker:
criteria = TextSearchCriteria("CONFIDENTIAL") # also: ImageSearchCriteria(...)
possible = watermarker.search(criteria)
print("found:", len(possible))
for wm in possible:
print(wm.text, wm.x, wm.y)
watermarker.remove(possible) # remove the whole collection
watermarker.save("clean.pdf")
Read document info
from groupdocs.watermark import Watermarker
with Watermarker("document.pdf") as watermarker:
info = watermarker.get_document_info()
print("format:", info.file_type)
print("pages:", info.page_count)
Render page previews
from groupdocs.watermark import Watermarker
from groupdocs.watermark.options import PreviewOptions, PreviewFormats
def create_page_stream(page_number):
return open("page-%d.png" % page_number, "wb")
def release_page_stream(page_number, stream):
stream.close() # the object create_page_stream returned
with Watermarker("document.pdf") as watermarker:
options = PreviewOptions(create_page_stream, release_page_stream)
options.preview_format = PreviewFormats.PNG
options.page_numbers = [1, 2]
watermarker.generate_preview(options)
create_page_stream may also return an io.BytesIO; it is filled by the time release_page_stream gets it.
Watermark from / to a binary stream
import io
from groupdocs.watermark import Watermarker
from groupdocs.watermark.watermarks import TextWatermark, Font
with open("document.pdf", "rb") as src:
with Watermarker(src) as watermarker:
watermarker.add(TextWatermark("CONFIDENTIAL", Font("Arial", 36)))
buffer = io.BytesIO()
watermarker.save(buffer) # BytesIO is updated after save
data = buffer.getvalue()
AI Agent & LLM Friendly
This package is designed for seamless integration with AI agents, LLMs, and automated code generation tools.
AGENTS.mdin the package — AI coding assistants (Claude Code, Cursor, GitHub Copilot) auto-discover the API surface, usage patterns, and troubleshooting tips from the installed package- MCP server — connect your AI tool to GroupDocs documentation for on-demand API lookups:
{ "mcpServers": { "groupdocs-docs": { "url": "https://docs.groupdocs.com/mcp" } } }
- Machine-readable docs — full documentation available as plain text for RAG and LLM context:
- Single file:
https://docs.groupdocs.com/watermark/python-net/llms-full.txt - Per page: append
.mdto any docs URL
- Single file:
Evaluation Mode
The API works without a license in evaluation mode. Every feature runs - adding several watermarks, search, and removal included - and there is no cap on the number of documents, but each saved document carries an evaluation mark:
- PDF and image files: the line "Evaluation only. Created with GroupDocs.Watermark."
- Word, PowerPoint, and Visio files: the line "Created with evaluation version of GroupDocs.Watermark".
- Excel files: an extra "Evaluation Warning" worksheet.
To remove the mark, apply a license or request a temporary license:
from groupdocs.watermark import License
License().set_license("path/to/license.lic")
Or set the environment variable (auto-applied at import):
export GROUPDOCS_LIC_PATH="path/to/license.lic"
Troubleshooting
| Issue | Platform | Fix |
|---|---|---|
| "Evaluation only" / "Created with evaluation version" line, or an "Evaluation Warning" sheet, in the output | All | No license is applied: set GROUPDOCS_LIC_PATH or call License().set_license(path) |
The type initializer for 'Gdip' threw an exception / DllNotFoundException: libgdiplus when adding a watermark |
Linux/macOS | Install libgdiplus: apt-get install libgdiplus / brew install mono-libgdiplus. Only text watermarks on Word, Excel, PowerPoint, Visio, and image files, text watermarks on PDF that set sizing_type, and image watermarks, removal, and previews on PowerPoint need it; the rest of PDF works without it |
FontNotFoundException when adding a text watermark to a PDF |
Linux | Install the font the watermark names - for Arial and the other Microsoft fonts: apt-get install ttf-mscorefonts-installer (Debian: enable contrib), then fc-cache -f. Liberation fonts are not substituted |
Not implemented. from generate_preview on a PowerPoint file |
Linux/macOS | PowerPoint previews need a GDI+ feature libgdiplus lacks; generate them on Windows. Previews of the other formats work |
The process aborts on first use with Couldn't find a valid ICU package |
Linux | Install ICU: apt-get install libicu-dev; do NOT set DOTNET_SYSTEM_GLOBALIZATION_INVARIANT |
is not a supported wheel on this platform, or No matching distribution found |
Linux/macOS | The OS is older than the wheel needs (glibc 2.27, macOS 12), or pip is older than 20.3: python -m pip install --upgrade pip. On an Intel Mac, a Python built against an old SDK reports macOS 10.16 - use pip 24.1+ or SYSTEM_VERSION_COMPAT=0 pip install groupdocs-watermark-net |
System Requirements
- Python 3.5 - 3.14, pip 20.3 or newer
- Windows x64, Linux x64, macOS x64/ARM64 - 64-bit Python only; there is no 32-bit Windows wheel
- Linux: glibc 2.27 or newer (e.g. Ubuntu 18.04+, Debian 10+, RHEL 8+), plus ICU, fontconfig, libgdiplus and the Microsoft core fonts:
apt-get install libicu-dev libfontconfig1 libgdiplus ttf-mscorefonts-installer(on Debian, enable thecontribcomponent first). libgdiplus is needed for text watermarks on Word, Excel, PowerPoint, Visio, and image files, for text watermarks on PDF files that setsizing_type, and for image watermarks, removal, and previews on PowerPoint files; the core fonts for text watermarks on PDF files, which look their font up by name. - macOS 12 or newer, Intel or Apple Silicon:
brew install mono-libgdiplusfor the same features.
Upgrading from 26.6
release_page_stream(page_number, stream)now gets the streamcreate_page_streamreturned; 26.6 passedNone. A one-argumentrelease_page_stream(page_number)still works.- Previews written through a release callback are complete (26.6 could leave a spreadsheet page truncated), and
io.BytesIOpages are filled (26.6 left them empty). WatermarkerSettings.loggertakes a Python object withtrace,warning, anderrormethods, or a functionfn(level, message, exception).- Assigning an attribute a class does not have raises
AttributeErrorwith a suggestion (watermark.opactiy = 0.5-> "Did you mean: 'opacity'?"); 26.6 stored it on the Python object and changed nothing. - Python 3.5, 3.6, and 3.7 work; 26.6 could not be imported on 3.5 and 3.6 and failed on first use on 3.7.
- Evaluation mode allows several watermarks per document, search, and removal (engine 26.9).
- The wheels state the OS they need (
manylinux_2_27,macosx_12_0), so installing needs pip 20.3 or newer.
The release notes have the full list.
More Resources
Also available for other platforms: .NET | Java | Node.js
Product Page | Docs | Demos | API Reference | Blog | Free Support | Temporary License
Metadata
Release files for groupdocs-watermark-net 26.10.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| groupdocs_watermark_net-26.10.0-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| groupdocs_watermark_net-26.10.0-py3-none-manylinux_2_27_x86_64.whl | Python 3 | none | Linux glibc 2.27+ x86-64 | Details |
| groupdocs_watermark_net-26.10.0-py3-none-macosx_12_0_x86_64.whl | Python 3 | none | macOS 12.0+ x86-64 | Details |
| groupdocs_watermark_net-26.10.0-py3-none-macosx_12_0_arm64.whl | Python 3 | none | macOS 12.0+ ARM64 | Details |
Total release size: 550.0 MB
Release files / groupdocs_watermark_net-26.10.0-py3-none-win_amd64.whl
| Download URL | groupdocs_watermark_net-26.10.0-py3-none-win_amd64.whl |
|---|---|
| Size | 137.5 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
831b596d14b0feda5a9f7d28b2f4db78d3beb259243afb385285393f049fdb20
|
|
BLAKE2b-256 checksum How to use checksums |
1769f6c117684b35e4186f7f5ab63b1e7a711f3846aafce92f9560bc68e420f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / groupdocs_watermark_net-26.10.0-py3-none-manylinux_2_27_x86_64.whl
| Download URL | groupdocs_watermark_net-26.10.0-py3-none-manylinux_2_27_x86_64.whl |
|---|---|
| Size | 136.9 MB |
| Tags | Linux glibc 2.27+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
a7c4cb25ac7d92ef4bbc1e43b165d663f31817a7c3c64dee6fb306ad7ab4bf8f
|
|
BLAKE2b-256 checksum How to use checksums |
14052d1577b56393ac631d8f489adfb739a63a695c6ca120d56929c39512d744
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / groupdocs_watermark_net-26.10.0-py3-none-macosx_12_0_x86_64.whl
| Download URL | groupdocs_watermark_net-26.10.0-py3-none-macosx_12_0_x86_64.whl |
|---|---|
| Size | 138.9 MB |
| Tags | Python 3 macOS 12.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
0298efae35dafafaf02a76a0d3de262ade04db4ebcca36eeaebed19014519ac7
|
|
BLAKE2b-256 checksum How to use checksums |
bc8e0865d99807595dfc496598aef81d982d9c7f8ef8801f74a2e48ed8559c90
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|
Release files / groupdocs_watermark_net-26.10.0-py3-none-macosx_12_0_arm64.whl
| Download URL | groupdocs_watermark_net-26.10.0-py3-none-macosx_12_0_arm64.whl |
|---|---|
| Size | 136.7 MB |
| Tags | Python 3 macOS 12.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
23eb3139ec065a7be73a14a3da988b81d44a00c40cac83c958ebac59631a06e2
|
|
BLAKE2b-256 checksum How to use checksums |
a330550cb01e11286000e4fd8fe7ed526d1926cda0aad363125e5e46bc491410
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.16
|