GroupDocs.Watermark for Python via .NET 26.10 Release Notes
This release upgrades the GroupDocs.Watermark engine from 26.6 to 26.9. The embedded .NET runtime moves from 10.0.0 to 10.0.12 and the wheel tags now target manylinux_2_27_x86_64, macosx_12_0_x86_64 and macosx_12_0_arm64. New features let WatermarkerSettings.logger accept a Python object or function and raise an AttributeError when assigning a non‑existent attribute. Preview callbacks now receive the actual page stream, fixing empty or truncated io.BytesIO previews. Support for Python 3.5 – 3.7 and guardrails against installing on unsupported Linux/macOS versions are also added.
Breaking change: assigning an attribute that a class does not have now raises AttributeError (e.g., watermark.opactiy = 0.5 used to be stored on the Python object and change nothing; now it raises). No classes or members were renamed or moved, but the wheel platform tags changed, so pip ≥ 20.3 is required to select the correct binary – see Requirements for details.
Full List of Changes in This Release
| Key | Category | Summary |
|---|---|---|
| WATERMARKPYTHON‑65 | Feature | Accept a Python object or function as WatermarkerSettings.logger |
| WATERMARKPYTHON‑66 | Enhancement | Update GroupDocs.Watermark engine from 26.6 to 26.9 |
| WATERMARKPYTHON‑67 | Enhancement | Update the embedded .NET runtime from 10.0.0 to 10.0.12 |
| WATERMARKPYTHON‑68 | Enhancement | Raise AttributeError when code assigns an attribute a class does not have |
| WATERMARKPYTHON‑69 | Fix | Cannot use the package on Python 3.5 – 3.7 |
| WATERMARKPYTHON‑70 | Fix | pip installs the package on Linux and macOS versions that cannot run it |
| WATERMARKPYTHON‑71 | Fix | Preview release callbacks receive None instead of the page stream |
| WATERMARKPYTHON‑72 | Fix | Page previews written to io.BytesIO are empty |
| WATERMARKPYTHON‑73 | Fix | Spreadsheet page previews written through a release callback are truncated |
Major Features
Custom logger for WatermarkerSettings
WatermarkerSettings.logger now accepts a Python object or a plain function. In 26.6 assigning any value raised
TypeError: _marshal_callback_or_handle: cannot wrap ... as GroupDocs.Watermark.Options.ILogger
The logger can be an object that implements trace(message), warning(message) and error(message, exception), or a callable fn(level, message, exception). The engine logs a trace when it opens a file and an error (with the .NET exception text) when it cannot load one; failures inside the logger are ignored.
from groupdocs.watermark import Watermarker, WatermarkerSettings
class PrintLogger:
def trace(self, message):
print("trace:", message)
def warning(self, message):
print("warning:", message)
def error(self, message, exception):
print("error:", message, exception)
settings = WatermarkerSettings()
settings.logger = PrintLogger() # object with the required methods
# or: settings.logger = lambda level, msg, exc: print(level, msg, exc)
with Watermarker("document.pdf", settings) as watermarker:
print(watermarker.get_document_info().page_count)
Strict attribute assignment
Assigning a misspelled or .NET‑style property on a watermark wrapper now raises an AttributeError instead of silently creating a Python‑only attribute. This prevents code from thinking it has changed the document when it has not.
from groupdocs.watermark.watermarks import TextWatermark, Font
watermark = TextWatermark("CONFIDENTIAL", Font("Arial", 36))
try:
watermark.opacity_level = 0.5 # misspelled: the property is `opacity`
except AttributeError as error:
print(error)
The raised error is:
AttributeError: 'TextWatermark' object has no attribute 'opacity_level'; assigning it would not reach the .NET object. Did you mean: 'opacity'?
Existing correct property assignments continue to work unchanged.
API Changes
Upgrading requires using the new wheel (pip ≥ 20.3) and handling the new AttributeError for misspelled attributes; other API signatures remain unchanged.
New classes and members
Color: a constructor; it had none.get()on 4 indexed classes —ReadOnlyListBase,SpreadsheetHeaderFooterCollection,SpreadsheetHeaderFooterSectionCollection,WordProcessingHeaderFooterCollection— as an alternative tox[key]; theiritemproperty is removed.
Fixed
- Cannot use the package on Python 3.5 – 3.7 (WATERMARKPYTHON‑69). Importing
groupdocs.watermarkon Python 3.5 or 3.6 raised aSyntaxError, and on Python 3.7 the first API call raisedAttributeError: module 'typing' has no attribute 'get_origin'because the wheel used newer language features. The 26.10 wheel removes those features, so the package imports and runs on Python 3.5 – 3.14. - pip installs the package on Linux and macOS versions that cannot run it (WATERMARKPYTHON‑70). On Linux systems with glibc older than 2.27 or macOS versions earlier than 12 the installed wheel could not start the embedded .NET runtime, causing runtime startup failures. The 26.10 wheels are tagged
manylinux_2_27_x86_64,macosx_12_0_x86_64andmacosx_12_0_arm64, so pip now blocks installation on those unsupported platforms. - Preview release callbacks receive
Noneinstead of the page stream (WATERMARKPYTHON‑71). When usingPreviewOptions(create_page_stream, release_page_stream), the release callback was invoked withNoneinstead of the page stream, so cleanup actions never saw the data. In 26.10 the release callback receives the stream returned by the create callback (or can accept only the page number). - Page previews written to
io.BytesIOare empty (WATERMARKPYTHON‑72). A create callback that returned anio.BytesIOyielded empty pages (all lengths 0) because the engine wrote to a .NET copy of the stream. The 26.10 wheel writes the page bytes back into the originalBytesIO, so the stream contains the expected data. - Spreadsheet page previews written through a release callback are truncated (WATERMARKPYTHON‑73). Providing a release callback for spreadsheet previews left the stream open and never passed it to Python, resulting in truncated PNG files. The wrapper now closes the engine’s stream before calling the release callback, so the file holds the full image.
Known Issues
- On Linux or macOS, adding a watermark may raise
The type initializer for 'Gdip' threw an exceptionorDllNotFoundException: libgdiplus; install libgdiplus (sudo apt install libgdiplusorbrew install mono-libgdiplus). - On Linux, adding a text watermark to a PDF may raise
FontNotFoundException; install Microsoft core fonts (sudo apt install ttf-mscorefonts-installer fontconfig && sudo fc-cache -f). - Generating a preview for a PowerPoint file on Linux/macOS raises
Not implemented.; generate PowerPoint previews only on Windows. - If a
DllNotFoundException: libSkiaSharpoccurs, rename or remove the conflicting system library (sudo mv /usr/local/lib/libSkiaSharp.dylib /usr/local/lib/libSkiaSharp.dylib.bak). - The process may abort on first use with
Couldn't find a valid ICU package; installlibicu-devand ensureDOTNET_SYSTEM_GLOBALIZATION_INVARIANTis not set. - A
TypeLoadExceptioncan be resolved by reinstalling the package (pip install --force-reinstall groupdocs-watermark-net).
Requirements
- Python 3.5 – 3.14 (
python_requires = ">=3.5,<3.15") and pip 20.3 or newer - Linux x64 with glibc 2.27 or newer; macOS 12 or newer, Intel or Apple Silicon. On an Intel Mac, a Python built against a pre-11 macOS SDK reports the system as macOS 10.16 — use pip 24.1 or newer there, or
SYSTEM_VERSION_COMPAT=0 pip install groupdocs-watermark-net - Windows: no additional packages
- Linux: ICU, fontconfig, libgdiplus and fonts —
apt-get install libicu-dev libfontconfig1 libgdiplus ttf-mscorefonts-installer(on Debian, enable thecontribcomponent first). libgdiplus: text watermarks on Word, Excel, PowerPoint, Visio and image files, text watermarks on PDF files that set sizing_type, and image watermarks, removal and previews on PowerPoint files (the rest of PDF needs none of it). The Microsoft core fonts: text watermarks on PDF files, which look their font up by name (Liberation substitutes are not picked up). PowerPoint previews fail on Linux even with libgdiplus (it does not implement Image.SaveAdd). - The .NET 10.0.12 runtime is embedded in the wheel; no separate install is needed
Wheel Distribution
| Platform | Wheel |
|---|---|
| Windows x64 | groupdocs_watermark_net-26.10.0-py3-none-win_amd64.whl |
| Linux x64 | groupdocs_watermark_net-26.10.0-py3-none-manylinux_2_27_x86_64.whl |
| macOS Intel | groupdocs_watermark_net-26.10.0-py3-none-macosx_12_0_x86_64.whl |
| macOS Apple Silicon | groupdocs_watermark_net-26.10.0-py3-none-macosx_12_0_arm64.whl |
pip install groupdocs-watermark-net==26.10.0
Additional Resources
Feedback
Questions and issues are welcome on the GroupDocs.Watermark forum.