Skip to main content

Python CLI for batch image watermarking with logo or text

Project description

wmk: Python CLI to watermark images (batch watermark, logo watermark, text watermark)

CI PyPI version Python versions License

Python CLI for batch image watermarking with logo or text.

wmk is built for people searching "how to add watermark to image", "add watermark to photo", "put watermark on picture", "add logo to image", "add text watermark to photo", "batch watermark images", "watermark multiple photos at once", and "protect photos with watermark".

20-Second Quickstart: watermark images with a Python CLI

pipx install add-watermark
wmk add
# Expert one-liner: add text watermark to photo
wmk add --input ".\photo.jpg" --text "(c) ACME" --pos br --opacity 40

Install add-watermark for batch watermark, logo watermark, and text watermark

PyPI package name: add-watermark; CLI commands: wmk (primary) and add-watermark (alias).

A) Install (Recommended): pipx

pipx install add-watermark

If pipx is not on PATH yet:

pipx ensurepath

B) Install (Alternative): pip

python -m pip install add-watermark

C) Install from source (repo clone)

git clone https://github.com/ibrahimm7004/add-watermark.git
cd add-watermark

Install from this repo with pipx:

pipx install .

Install from this repo with pip:

python -m pip install .

D) Uninstall (pipx and pip)

pipx uninstall add-watermark
python -m pip uninstall add-watermark

You can also run the beginner-friendly alias:

add-watermark add

Versioning

This project follows Semantic Versioning (MAJOR.MINOR.PATCH):

  • MAJOR: breaking CLI/API changes
  • MINOR: backward-compatible features
  • PATCH: backward-compatible fixes

Check the installed CLI version:

wmk --version

Before and after: put watermark on picture

Before After
Before watermark example After watermark example

Regenerate both demo images:

python examples/generate_examples.py

Add watermark to photo: wizard and expert one-liners

Beginner wizard:

wmk add

Single image with text watermark:

wmk add --input ".\photo.jpg" --text "(c) ACME Studio" --pos br --opacity 40

Single image with logo watermark:

wmk add --input ".\photo.jpg" --watermark ".\logo.png" --pos tr --opacity 35

Batch watermark folder:

wmk add --input ".\photos" --watermark ".\logo.png" --pos br --opacity 35

Batch watermark folder recursively:

wmk add --input ".\photos" --recursive --text "(c) ACME" --pos br --opacity 35

Glob input:

wmk add --input ".\photos\**\*.png" --watermark ".\logo.png" --opacity 35

Dry run (plan only):

wmk add --input ".\photos" --watermark ".\logo.png" --dry-run

Defaults

wmk add defaults (from current implementation):

  • Default position: br
  • Default opacity: 35 (0 is invisible, 100 is fully visible)
  • Default corner margin: 24px
  • Image watermark default scale: target width is about 20% of base image width, clamped to at least 48px and at most 80% of base width
  • Text watermark default scale: font size is about 5% of image width, clamped to 16..256
  • Text watermark style: white text with black stroke and subtle shadow for readability
  • Single-image default output: <input_stem>_watermarked.<ext> next to input
  • Batch default output (folder input): watermarked/ next to the input folder
  • Batch default output (glob input): ./watermarked/ in current working directory
  • Batch mode preserves relative folder structure for folder input
  • For glob input, paths are preserved only when files are under the current working directory; otherwise output falls back to filenames under ./watermarked/
  • Without --overwrite, existing destination paths are not replaced; a _watermarked suffix is appended to avoid collisions

Windows notes

  • Quote paths that contain spaces:
    • PowerShell/CMD: --input "C:\Users\me\My Photos\photo 01.jpg"
  • Quote globs to keep behavior consistent across shells and avoid shell expansion differences:
    • --input ".\photos\**\*.jpg"
  • PowerShell example:
wmk add --input ".\My Photos\Client A" --recursive --text "(c) ACME" --pos br --opacity 35
  • CMD example:
wmk add --input ".\My Photos\*.jpg" --watermark ".\brand logo.png" --pos tr --opacity 35

Why offline CLI (vs online watermark tools)

If you are searching for "add watermark to image online free", an offline CLI is often better for production workflows:

  • Privacy: images stay on your machine
  • Speed: no upload/download loop
  • Batch scale: watermark hundreds of files in one command
  • Automation: scriptable for product photos, photography delivery, and repeatable pipelines

Supported formats and behavior

  • Input/output formats: jpg, jpeg, png, webp, tiff, bmp, gif
  • GIF behavior: first frame only
  • JPEG output is written as RGB (quality 95)
  • PNG/WEBP preserve alpha when present

Common searches this tool solves

  • how to add watermark to image
  • add watermark to photo
  • put watermark on picture
  • how to watermark a photo
  • add logo to image
  • add text watermark to photo
  • batch watermark images
  • bulk watermark photos
  • watermark multiple photos at once
  • add watermark to 100 photos
  • signature watermark
  • copyright watermark on images

CLI reference

wmk add [OPTIONS]

Options:
  --input, -i      File path, folder path, or glob pattern
  --output, -o     Output file (single mode) or output folder (batch mode)
  --watermark, -w  Watermark image path
  --text, -t       Text watermark content
  --pos            Watermark position: tl|tr|bl|br|c
  --opacity        Opacity 0-100 (0 invisible, 100 fully visible)
  --recursive      Recurse subfolders for folder input
  --overwrite      Overwrite existing outputs
  --dry-run        Print planned outputs without writing files
  --verbose        Show traceback/debug details

Validation rules:

  • Exactly one of --watermark or --text in non-interactive mode
  • If --input is missing, wizard prompts for required fields

Library usage (optional)

CLI is the primary interface. If you need direct Python usage:

from pathlib import Path

from watermarker.engine import process_single

process_single(
    input_path=Path("photo.jpg"),
    output_path=Path("photo_watermarked.jpg"),
    text="(c) ACME",
    position="br",
    opacity=35,
    overwrite=True,
)

Open source trust signals

FAQ and troubleshooting

wmk command is not found on Windows

  • For pipx installs, run pipx ensurepath and restart terminal.
  • For pip installs, ensure your Python Scripts directory is on PATH.

Why does GIF output look static?

  • v1 processes only the first GIF frame.

Why can text look slightly different across machines?

  • The tool tries common system fonts first and falls back to Pillow default when needed.

Development

python -m pip install -e .[dev]
ruff check .
ruff format --check .
pytest

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

add_watermark-0.1.1.tar.gz (13.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

add_watermark-0.1.1-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

File details

Details for the file add_watermark-0.1.1.tar.gz.

File metadata

  • Download URL: add_watermark-0.1.1.tar.gz
  • Upload date:
  • Size: 13.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for add_watermark-0.1.1.tar.gz
Algorithm Hash digest
SHA256 ff7c4c0f3b77d6fb3c5124b4973b2ae9430e0bb8d17347040783a3fa518f052d
MD5 aaa449bfd07e872f9b54211ed45372ce
BLAKE2b-256 62f2191a7443f02428688e86f46ed46df861467f38f73b2f358b0cbc23ecc2c7

See more details on using hashes here.

File details

Details for the file add_watermark-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: add_watermark-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 13.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for add_watermark-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4da72565d0390b91129e4ae4d62c6b315369dfdc213419a500cdd787451fc1a3
MD5 396f2d795606a2575e7fa8b398960c7c
BLAKE2b-256 acca4b2888d9b0742209d56ad85d03795e56c1978402727dd219ced756bf377e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page