DEV Community

Mate Technologies
Mate Technologies

Posted on

I Built a Desktop Watermarking Tool in Python (WatermarkX)

I recently built WatermarkX, a lightweight desktop app for batch image watermarking using Python.

What started as a small internal tool for my own content workflow turned into a full GUI application with drag & drop, live progress tracking, and repeat diagonal watermarks.

In this post, I’ll walk through what it does, how it’s built, and some lessons learned.

✨ What WatermarkX Does

WatermarkX is a local desktop application that lets you apply text and logo watermarks to multiple images at once.

Key features:

Text watermarks with rotation, opacity, font size, and stroke/outline

Repeat diagonal (tiled) watermark mode

PNG logo watermark support (with transparency)

Drag & drop image loading

Batch processing with progress bar, ETA, and speed

Stop / resume processing

Everything runs locally — no uploads, no accounts

Supported formats:

PNG

JPG / JPEG

BMP

GIF

🧠 Tech Stack

The app is written entirely in Python:

Tkinter + ttkbootstrap – GUI

tkinterdnd2 – drag & drop support

Pillow (PIL) – image processing

threading – background processing so the UI stays responsive

The core watermarking logic uses Pillow’s ImageDraw and ImageFont, creating a rotated RGBA text layer that gets composited onto each image.

For tiled watermarks, I generate a single rotated watermark layer and then paste it repeatedly across the canvas with calculated spacing.

Everything runs locally on your machine.

🔧 Interesting Implementation Details

  1. Zero-clip rotated text

To avoid cropped text after rotation, I first measure the text using textbbox, add margins, render it onto a transparent canvas, and only then rotate:

bbox = d.textbbox((0,0), text, font=font, stroke_width=stroke)

This ensures the watermark never gets clipped.

  1. Diagonal repeat watermarking

Instead of rotating the entire image, I rotate just the watermark and tile it diagonally across the image:

Create watermark layer once

Calculate spacing from watermark dimensions

Paste in nested loops across the canvas

This keeps things fast even for large batches.

  1. Non-blocking UI

Processing runs in a background thread so the GUI stays responsive:

Progress bar updates per image

ETA is calculated from elapsed time

Speed shown as images/sec

Stop button sets a shared flag checked inside the processing loop

Simple, but effective.

📦 Packaging

The app is packaged as a standalone desktop executable so users don’t need Python installed.

That involved:

Handling resource paths (_MEIPASS)

Bundling fonts and icons

Making sure Pillow + Tkinter play nicely in production builds

Desktop Python distribution is still a bit rough around the edges, but totally doable.

🚀 Why I Built It

I frequently need to watermark screenshots and marketing images, and existing tools were either:

Web-based (slow + privacy concerns)

Overkill

Subscription-heavy

So I built exactly what I needed: fast, offline, and simple.

After friends started asking for it, I decided to polish it and release it.

🔗 Project Link

If you’d like to check it out:

https://gum.new/gum/cmka62o2l001w04l42jmy3i9y

Feedback, feature ideas, and code suggestions are very welcome.

🙏 Final Thoughts

This was a fun reminder that Python is still great for shipping real desktop tools — not just scripts and APIs.

If you’re thinking about building your own GUI utilities: just start. Tkinter + Pillow can take you surprisingly far.

Thanks for reading 🙂

Top comments (0)