How to Add Custom Watermarks to Images Using ImageKit: A Complete Guide

ImageKit enables adding custom watermarks to images through both a command-line interface with flags like --watermark-text and --watermark-position, and a Rust library API via the add_watermark function in src/processor.rs, supporting RGBA colors, nine positioning options, and automatic font scaling.

ImageKit is a Rust-based open-source tool for batch image processing that includes a robust watermarking pipeline. Whether you need to brand a photo gallery or protect image assets, the library provides both CLI convenience and programmatic flexibility. According to the hzbd/imagekit source code, watermarking is implemented through a modular architecture that separates option parsing, font management, and image manipulation into distinct components.

Understanding ImageKit's Watermark Architecture

The watermarking system in ImageKit follows a three-stage pipeline designed for parallel processing and thread safety.

CLI Configuration and Color Parsing

In src/cli.rs, the Cli struct defines all watermark-related command-line arguments. Users can specify text content, position, font size, and color through flags like --watermark-text, --watermark-position, and --watermark-color. The file also implements the HexColor parser to handle RGBA color values (e.g., #ffffff80 for semi-transparent white) and the WatermarkPosition enum with nine variants: nw, north, ne, west, center, east, sw, south, and se.

Font Loading and Thread Pool Setup

The library entry point in src/lib.rs loads three embedded fallback fonts—Roboto, Source Han Sans SC, and Noto Sans Thai—and stores them in an Arc<Vec<Font>>. This thread-safe reference counting allows the font data to be shared cheaply across Rayon's thread pool when processing multiple images concurrently.

Image Processing and Watermark Rendering

The core logic resides in src/processor.rs. The process_image function handles optional resizing before calling add_watermark when text is provided. This function calculates appropriate scaling to prevent text overflow, invokes layout_text to rasterize glyphs using the fallback font stack, computes pixel offsets based on the selected position, and blends the final text onto the image using the specified RGBA color.

Adding Watermarks via Command Line

The simplest way to add watermarks is using the pre-built binary. ImageKit supports batch processing entire directories while applying consistent watermark styling.

Example command for a semi-transparent watermark in the bottom-right corner:

./imagekit -i ./example/img-src -o ./example/img-out \
  --width 800 \
  --watermark-text "© My Brand" \
  --watermark-position se \
  --font-size 32 \
  --watermark-color "#ffffff80"

This command resizes images to 800px width, applies the text "© My Brand" at 32pt font size in the southeast (bottom-right) position, and sets the color to white with 50% opacity.

Adding Watermarks Programmatically

For Rust applications, you can integrate ImageKit's watermarking directly using the library API. The run function accepts a Cli struct containing all watermark parameters.

use imagekit::{run, cli::Cli};
use std::path::PathBuf;

fn main() -> anyhow::Result<()> {
    let cli = Cli {
        input_dir: PathBuf::from("./example/img-src"),
        output_dir: PathBuf::from("./example/img-out"),
        width: Some(800),
        height: None,
        watermark_text: Some("@My Phone".into()),
        watermark_position: imagekit::cli::WatermarkPosition::Se,
        font_size: 24,
        watermark_color: imagekit::cli::HexColor(image::Rgba([255, 255, 255, 128])),
        quality: 85,
        output_format: None,
    };

    run(cli)
}

This approach allows dynamic configuration at runtime while leveraging the same parallel processing backend as the CLI.

Customizing Watermark Appearance

ImageKit provides granular control over watermark positioning and styling through several key parameters.

Position Options: The WatermarkPosition enum supports nine anchor points: northwest (nw), north (top-center), northeast (ne), west (left-center), center, east (right-center), southwest (sw), south (bottom-center), and southeast (se). The library calculates pixel offsets automatically based on the rendered text's bounding box.

Automatic Font Scaling: In src/processor.rs, the add_watermark function includes logic to shrink text dynamically if the requested font_size would cause the watermark to overflow the image boundaries. This ensures watermarks remain visible and properly proportioned regardless of image dimensions.

RGBA Color Support: Colors are specified using the HexColor type, which parses standard hex codes with optional alpha channels. The format supports both 6-character RGB (e.g., #ff0000) and 8-character RGBA (e.g., #ff000080 for 50% transparent red).

Using Custom Fonts

While ImageKit includes three built-in fonts for international text support, you can substitute custom typefaces by interfacing directly with the processor module.

use rusttype::Font;
use imagekit::processor::add_watermark;
use image::{DynamicImage, Rgba};

fn custom_watermark(img: &mut DynamicImage) {
    let data = include_bytes!("MyFont.ttf") as &[u8];
    let font = Font::try_from_bytes(data).expect("invalid font data");

    add_watermark(
        img,
        "Custom Font Watermark",
        &[font],
        36,
        imagekit::cli::WatermarkPosition::Center,
        imagekit::cli::HexColor(Rgba([255, 0, 0, 200])),
    );
}

This example loads a custom TTF file and calls add_watermark directly with a single-font slice, bypassing the default font stack loaded in src/lib.rs.

Summary

  • CLI Integration: Use flags like --watermark-text, --watermark-position, and --watermark-color in src/cli.rs for quick batch processing.
  • Library API: Import imagekit::run and construct a Cli struct for programmatic control within Rust applications.
  • Parallel Processing: The system uses Rayon and Arc<Vec<Font>> in src/lib.rs for efficient multi-threaded watermarking of image batches.
  • Flexible Positioning: Nine position variants (nw, north, ne, west, center, east, sw, south, se) are calculated automatically in src/processor.rs.
  • Smart Rendering: The add_watermark function auto-scales text to fit image bounds and supports RGBA transparency via HexColor.

Frequently Asked Questions

What watermark positions does ImageKit support?

ImageKit supports nine positioning options defined in src/cli.rs: northwest (nw), north (north), northeast (ne), west (west), center (center), east (east), southwest (sw), south (south), and southeast (se). The add_watermark function in src/processor.rs calculates the exact pixel coordinates based on the text bounding box and selected anchor point.

How does ImageKit handle fonts for international text?

The library loads three fallback fonts in src/lib.rs: Roboto for Latin scripts, Source Han Sans SC for Chinese characters, and Noto Sans Thai for Thai scripts. These are stored in an Arc<Vec<Font>> and shared across threads, with the layout_text function in src/processor.rs attempting each font in sequence until it finds one that can render the requested characters.

Can I make the watermark semi-transparent?

Yes. The HexColor parser in src/cli.rs supports 8-character hex codes with alpha channels (e.g., #ffffff80 for 50% opacity white). When rendering, the add_watermark function respects the alpha value when blending glyphs onto the underlying image in src/processor.rs.

Does ImageKit prevent watermarks from overflowing small images?

Yes. The add_watermark function in src/processor.rs (lines 38-52) includes automatic scaling logic that detects when the requested font_size would cause text to exceed image boundaries. It proportionally shrinks the text to ensure the watermark remains fully visible regardless of image dimensions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →