Introduction

Watermarking is the process of superimposing a logo or piece of text atop a document or image file, and it’s an important process when it comes to both the copyright protection and marketing of digital works.1

Adding a watermark to our work ensures that if anything we make ends up going viral, our brand is recognized.

Watermarking also ensures that people do not use these images without referring to the “original publisher”.

Hugo is an open-source static site generator i.e. SSG written in Go. Hugo is for people who want to hard code their website without worrying about setting up complicated runtimes, dependencies and databases.


Let’s get started πŸš€

From HUGO v0.80.0 they have added support for overlay images, with which we can add watermark. So, ensure you have v0.80 or greater installed on your system.

You can check that by typing hugo version in your Terminal or Command prompt.

Now, we will be dealing here with “in-post images”, that is images that are inside a blog post. For theme-specific images such as Cover Images, Header Images you need to modify the code slightly for this to work.

For the scope of this article, we will add the watermark to the right bottom corner images.

Let’s understand the basics

About Page Bundles πŸ—

For our implementation to work we need to use Page Bundles

HUGO has a term called Page Resources which are only accessible from Page Bundles and this is essential for getting the image we want to add a Watermark to!

Page resources contain images, documents, etc. and have page-relative URLs and their metadata.

So for “Page Bundling” to work your site’s content folder should look similar to:

* (site-root)
β”œβ”€β”€ content
β”‚   β”œβ”€β”€ post-one
β”‚   β”‚   β”œβ”€β”€ index.md
β”‚   β”‚   └── images
β”‚   β”‚       β”œβ”€β”€ image_one.jpeg
β”‚   β”‚       β”œβ”€β”€ image_two.jpeg
β”‚   β”‚       └── image_three.jpeg
β”‚   └── post-two
β”‚       β”œβ”€β”€ index.md
β”‚       └── images
β”‚           └── image_one.jpeg
└── themes

Okay so basically for the above site, post-one has all the files inside its directory, which can be called “Page Resources”. So index.md and the images under images directory can be fetched with and processed as per our needs with the help of the Bundled resources.

About the Logo image 🎞️

As of writing this post, we can only add an overlay of an image over another image and not text over the image.

So we have to 1st get the image (called ’logo image’ henceforth) we want to add as a watermark and place it in the desired location under assets directory so that it could be accessible by HUGO’s resource handler.

For this tutorial, we’ll place the logo image at ./assets/images/logo.png.

About Markdown Render Hooks πŸͺ

Hugo offers really handy Markdown Render Hooks. These allow custom templates to override markdown rendering functionality.

We will be using render-image hook to process out the images in the post as per our needs.

The render-image hook stays in the location shown below.

* (site root)
β”œβ”€β”€ layouts
β”‚   └── _default
β”‚       └── _markup
β”‚           └── render-image.html
└── themes

The code snippet </>

We will be using the following code into render-image.html which will add a watermark(an image at ./assets/images/logo.png) at the right bottom corner of the original image.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!-- contents of render-image.html -->
{{- $link := split .Destination "#" }}
{{- $image := (.Page.Resources.ByType "image").GetMatch (printf "*%s*" (index $link 0)) }}
{{- $logo := (resources.Get "images/logo.png") }}

{{- if and $image $logo }}
{{- $size := math.Round (mul $image.Height 0.30) }}
{{- $size := cond (ge $size 80) ($size) (80.0) }}

{{- $logo := $logo.Resize (printf "%.0fx jpg" $size) }}
{{- $image := $image.Filter (images.Overlay $logo (sub $image.Width $logo.Width) (sub $image.Height $logo.Height) ) }}
{{- $finalUrl := cond (isset $link 1) (printf "%s#%s" ($image.Permalink) (index $link 1)) ($image.Permalink) -}}

<img src="{{ $finalUrl | safeURL }}" alt="{{ .Text }}" {{ with .Title}} title="{{ . }}" {{ end }} />
{{- else }}
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" {{ with .Title}} title="{{ . }}" {{ end }} />
{{- end }}

✨ I’ll be updating the code here so that it uses dynamic values and adds a decent-sized watermark for images of multiple sizes. GitHub Gist Link

Code explanation πŸ—£οΈ

  • The render-image markdown-hook has these variables with it, of which the .Destination variable gives us the path to the resource (in our case, image).

  • We split the image path into 2 parts, with # as the delimiter, so that the resource path does not have any extra text attached with it. Then we get the actual image resource and store it in $image.

  • We then get the image we want as a watermark and store it into $logo.

  • Then we check whether both $image and $logo aren’t empty then proceed to watermarking, else we display the original image as it is with .Destination.

  • Now that both $image and $logo are present we make some calculations so that the size of the watermark is decent, not huge not so small! We’ll not look into that part of the code as it out-of-scope for this blog.

  • The line below is where we tell HUGO to add the watermark($logo) over the image.

    {{- $image := $image.Filter (images.Overlay $logo (sub $image.Width $logo.Width) (sub $image.Height $logo.Height) ) }}
    
    • images.Overlay takes 3 arguments: image resource, position on x-axis, position on y-axis

    • Now as we want to add the logo to the right bottom corner, we’ll set the X and Y-axis of the logo image such that it will fit into the place.

    • For this we subtract the Width of logo from image’s Width, same goes for Height, we subtract the Height of logo from image’s Height.

      position on X = $image.Width- $logo.Width
      
      position on Y = $image.Height - $logo.Height
      
  • We then use Filter function to add the overlay over the original image.

  • Now with HUGO magic πŸͺ„ we have a nicely watermarked image with the logo we want!

  • Finally, we will add the params we initially removed from the URL, and add those back after the # and store the image’s URL in $finalUrl. Then add a link to the generated image with the template.


Results πŸ–ΌοΈ

As you can see in the image below, we have a watermark adityatelange.in (the logo image) in right bottom corner just by using the regular markdown syntax. πŸŽ‰

![Sample Results](media/images/sample.jpg#center "Sample Result with a watermark")

Turns into ↓