A custom program to watermark images using Image Magick.

image-magick photography watermark

A whitetail deer looks to the side of the image. This post details my process for applying watermarks to images as fast as possible. I have a TIL post on generating the initial watermark image and then applying that watermark to a batch of images using ImageMagick.

The backstory: I had begun to create a lot of cropped images and portrait orientation photos, and I wanted the watermark size to dynamically adjust to the image size, Also, I schedule many of the photos I share on Twitter with Buffer in a batch, and Buffer’s size limit is 10 MB. So I want to automatically resize any photo that is over 10 MB to under 10 MB.

The result is a little bit of hacky C++ code that I built and then installed, so I can call it from anywhere. Since it isn’t research code, I hard-coded some items in there. Of course, adjust for your own needs! The C++ file and CMakeLists.txt is on Github, amy-tabb/custom-watermark, with my watermark trans_stamp3.png so you have something to play around with.

There is one argument, the input directory. What the program does is read through all the files in the directory, determining if the files are or are not image files. It creates a watermarked copy if the file is an image file, with water- as the file’s prefix. This allows me to run

custom-watermark --input $PWD

in a directory with sidecar files from editing RAW files. Nothing is lost, only watermarked images created.

The image examples in this post were created using the custom-watermark program. Original sizes were:

  • deer, first image: 4985 x 3323.
  • butterfly, second image: 1938 x 2908.
  • hummingbird, third image: 3406 x 2272.

and resized smaller to be more web friendly.

Preliminaries:

  • C++,
  • C++ 17 compiler,
  • Cmake project,
  • need exiftool. sudo apt install exiftool on Ubuntu.
  • need Image Magick. sudo apt install imagemagick on Ubuntu.

C++ code: hardcoded values.

Butterfly on a thistle. Over in the .cpp file at amy-tabb/custom-watermark, you’ll want to adjust the hardcoded values as needed. They are indicated with hardcoded item in the comments.

Maximum filesize

I set the maximum filesize to 10 MB.

    // hardcoded item # 1
    std::uintmax_t maxfilesize = 10*1000000;

Later, if the filesize of the watermarked file is greater than this maximum, the file is resized down until it is smaller than the maximum.

    std::uintmax_t filesize = filesys::file_size(watermarkedPath);
    
    // 1 MB to 1000000 bytes. so

    cout << "Current size as a proportion, " << float(filesize)/float(maxfilesize) << endl;
    while (filesize > maxfilesize){
     ...
    }

Watermark directory and filename

These paths are for the watermark to apply to the input directory. You’ll want to make this an absolute path if you install.

   // hardcoded item # 2
   string watermark_directory = "/home/atabb/Pictures/KeepStamps";

   // hardcoded item #3
   string watermark_filename = "trans_stamp3.png";

Size of the watermark

Hummingbird drinking nectar from a flower. I empirically (see how I made it sound researchy?) determined what size I wanted the watermark to be relative to the rest of the image. Too big, and it is obnoxious. Too small, you might as well not have include a watermark. Ehh. I think these proportions below work better on Twitter versus on the website, where these proportions might be too small. A note: all of my images have the 3:2 or 2:3 aspect ratio.

// hardcoded item #4
   // landscape
   if (imageheight < imagewidth){
	stamp_width = round(double(imagewidth)*0.12);  //(*.12)
	stamp_height = round(double(stamp_width)/3.2);
    }	else {
	// portrait
	stamp_width = round(double(imagewidth)*0.22);  
	stamp_height = round(double(stamp_width)/3.2);
   }

Where to place the watermark

I place the watermark in the lower right corner. This command puts all of the previous parameters together to get one magical command string, where, hackily, I do a system call to ImageMagick.

// hardcoded item #5, where the watermark will be placed.
   command = "composite " + watermark_directory + watermark_filename + " " + filename 
              + " -gravity southeast -geometry " + ToString<int>(stamp_width) 
              + "x" + ToString<int>(stamp_height) + "+10+10 " 
	      + read_directory + "water-" + image_names[i];
					
   system(command.c_str());
   

Final words

Again, the project is at Github: amy-tabb/custom-watermark, and the post with instructions to create your own watermark is here. Happy watermarking!

© Amy Tabb 2018 - 2023. All rights reserved. The contents of this site reflect my personal perspectives and not those of any other entity.