How ImageKit Performs Intelligent Watermark Scaling: Algorithm and Implementation

ImageKit automatically scales down watermark text to fit within image boundaries by calculating width and height ratios and applying the smaller scale factor, ensuring the watermark never overflows regardless of font size or text length.

ImageKit is an open-source Rust image processing toolkit that handles dynamic watermarking with automatic size adjustment. The library implements intelligent watermark scaling in the add_watermark function within src/processor.rs, preserving user-requested dimensions when possible while preventing text overflow through proportional reduction.

How Intelligent Watermark Scaling Works

The scaling algorithm follows a six-step process that balances user preferences with image constraints. As implemented in src/processor.rs, the logic ensures watermarks remain readable without exceeding the canvas boundaries.

Step 1: Determine the Drawable Area with Padding

First, the function retrieves the image dimensions using img.dimensions(). It then subtracts a constant 10-pixel padding from each side to create a safe drawable region. This ensures the watermark does not touch the absolute edge of the image.

// Lines 40-42 in src/processor.rs
let (img_width, img_height) = img.dimensions();
let max_drawable_width = img_width - 10;
let max_drawable_height = img_height - 10;

Step 2: Measure Text at the Requested Font Size

The helper function layout_text calculates the bounding box of the supplied text using the user-specified font size. This initial measurement determines whether the text fits naturally or requires compression.

// Lines 43-44: Initial measurement
let (text_width, text_height) = layout_text(text, fonts, Scale::uniform(font_size));

Step 3: Detect Overflow and Calculate Scaling Ratios

If the measured text exceeds the drawable area in either dimension, the algorithm computes two scaling ratios: one for width and one for height. The code selects the smaller ratio to ensure the text fits within both constraints simultaneously.

// Lines 45-48: Ratio calculation
let width_ratio = max_drawable_width as f32 / text_width as f32;
let height_ratio = max_drawable_height as f32 / text_height as f32;
let scale_factor = width_ratio.min(height_ratio);

Step 4: Apply the Minimum Scale Factor

The new font size equals the original size multiplied by scale_factor. The implementation floors this value and clamps it to a minimum of 1 pixel, preventing invalid zero or negative sizes.

// Lines 49-51: Apply scaling
let new_font_size = (font_size as f32 * scale_factor).floor() as u32;
let new_font_size = new_font_size.max(1);
let scale = Scale::uniform(new_font_size as f32);

Step 5: Re-layout and Render

Finally, the system invokes layout_text again with the adjusted scale (line 53) to generate the glyph positions. The glyphs are then drawn at the chosen position, guaranteeing the watermark fits entirely within the padded boundaries.

Implementation Details in src/processor.rs

The core logic resides in the add_watermark function, which coordinates between the CLI arguments defined in src/cli.rs and the rendering pipeline. The function accepts parameters including font_size, WatermarkPosition, and HexColor, but overrides the size when overflow is detected.

Key architectural components include:

  • layout_text: A private helper that computes text dimensions using the rusttype crate.
  • Padding constant: Hardcoded at 10px to maintain visual margin regardless of image resolution.
  • Scale clamping: Ensures the font never collapses to zero, maintaining at least 1px height for visibility.

Usage Examples

You can trigger intelligent scaling both via the command line and programmatically. In both cases, the API accepts a requested font size, but the final rendered size may differ based on image dimensions.

Command-Line Interface

When using the imagekit CLI, simply specify your desired font size. The tool automatically reduces the size if the text would overflow the target image.


# Request 72pt text on a small image

imagekit -i example/img-src/large-photo.jpg \
         -o example/img-out/ \
         --watermark-text "© 2026 MyCompany" \
         --font-size 72 \
         --watermark-position se

Result: The watermark renders at a reduced size (e.g., 38pt) to fit within the padded drawable area.

Rust Programmatic API

When calling add_watermark directly, pass your preferred size as an argument. The function handles scaling internally using the algorithm described above.

use imagekit::processor::add_watermark;
use imagekit::cli::{HexColor, WatermarkPosition};
use rusttype::Font;
use image::DynamicImage;

let mut img = image::open("input.png")?;
let font_data = std::fs::read("assets/Roboto-Regular.ttf")?;
let font = Font::try_from_vec(font_data).unwrap();

// Request 80pt; actual size may be smaller
add_watermark(
    &mut img,
    "Confidential",
    &[font],
    80, // requested_font_size
    WatermarkPosition::South,
    HexColor::from_rgba(255, 255, 255, 128),
)?;
img.save("output.png")?;

Summary

  • Intelligent watermark scaling in ImageKit automatically adjusts font size to prevent text overflow.
  • The algorithm calculates width_ratio and height_ratio, applying the minimum value as a scale_factor.
  • A constant 10px padding ensures watermarks maintain a safe margin from image edges.
  • The implementation in src/processor.rs (lines 40-53) preserves the requested size when possible, only scaling down when necessary.
  • Both CLI and programmatic APIs support this feature transparently, requiring no manual size calculations from the user.

Frequently Asked Questions

How does ImageKit determine when to scale a watermark down?

ImageKit compares the rendered text dimensions against the drawable area (image size minus 10px padding). If either the text_width exceeds max_drawable_width or text_height exceeds max_drawable_height, the system calculates scaling ratios and reduces the font size proportionally using the smaller ratio to ensure a perfect fit.

What is the minimum font size ImageKit will render for a watermark?

The algorithm clamps the scaled font size to a minimum of 1 pixel using .max(1). This prevents invalid rendering attempts while ensuring the watermark remains technically visible, even on extremely small images.

Can I disable automatic watermark scaling in ImageKit?

No, the intelligent scaling behavior is built into the add_watermark function in src/processor.rs and cannot be disabled via configuration flags. The algorithm always enforces the constraint that watermarks must fit within the padded image boundaries to prevent partial or clipped text rendering.

Which Rust crates does ImageKit use for text measurement and rendering?

ImageKit relies on the rusttype crate for font parsing and glyph layout, the image crate for raster operations, and anyhow for error handling. These dependencies are declared in Cargo.toml and power the layout_text helper function that enables accurate dimension calculations required for intelligent scaling.

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 →