Use nodejs to add a full page translucent watermark to the picture

Posted by WilliamNz on Mon, 21 Feb 2022 14:37:47 +0100

Business background

As the export function of middle and background projects, it is usually required to have the traceability of export.

When the exported data form is a picture, a watermark is usually added to the picture to achieve this purpose.

DEMO

So how to add a watermark that can be used as the identity of the exporter before exporting the picture? Look at the finished product first:

The original picture above is a picture I casually found on the Internet. The effect after adding watermark is shown in the picture.

Business requirement decomposition

Here, we need to consider three key points of this requirement under this business scenario:

  • The watermark needs to cover the whole picture
  • The watermark text is translucent to ensure the readability of the original image
  • The watermark text shall be clear and readable

model selection

Like me, I am responsible for implementing the above requirements on a nodejs server. There are many options, such as directly using c lib imagemagick or various node watermarking libraries encapsulated by others. In this article, we will choose to use the encapsulation of the Jimp library.

The official github page of the Jimp library describes itself as follows:

An image processing library for Node written entirely in JavaScript, with zero native dependencies.

It also provides a large number of API s for operating pictures

  • blit - Blit an image onto another.
  • blur - Quickly blur an image.
  • color - Various color manipulation methods.
  • contain - Contain an image within a height and width.
  • cover - Scale the image so the given width and height keeping the aspect ratio.
  • displace - Displaces the image based on a displacement map
  • dither - Apply a dither effect to an image.
  • flip - Flip an image along it's x or y axis.
  • gaussian - Hardcore blur.
  • invert - Invert an images colors
  • mask - Mask one image with another.
  • normalize - Normalize the colors in an image
  • print - Print text onto an image
  • resize - Resize an image.
  • rotate - Rotate an image.
  • scale - Uniformly scales the image by a factor.

In the business scenario described in this article, we only need to use some of the API s.

Design and Implementation

input parameter design:

  • url: the storage address of the original picture (for Jimp, it can be a remote address or a local address)
  • textSize: the text size of the watermark to be added
  • opacity: transparency
  • Text: watermark text to be added
  • dstPath: the address of the output picture after adding the watermark. The address is the relative path of the script execution directory
  • rotate: rotation angle of watermark text
  • colWidth: because the rotatable watermark text is overlaid on the original image as a picture, here we define the width of the watermark image, which is 300 pixels by default
  • rowHeight: the reason is the same as above. The height of the watermark image is 50 pixels by default. (PS: the size of the watermark image here can be roughly understood as the interval of the watermark text)

Therefore, the above parameters can be exposed in the coverTextWatermark function of the module

coverTextWatermark

/**
 * @param {String} mainImage - Path of the image to be watermarked
 * @param {Object} options
 * @param {String} options.text     - String to be watermarked
 * @param {Number} options.textSize - Text size ranging from 1 to 8
 * @param {String} options.dstPath  - Destination path where image is to be exported
 * @param {Number} options.rotate   - Text rotate ranging from 1 to 360
 * @param {Number} options.colWidth - Text watermark column width
 * @param {Number} options.rowHeight- Text watermark row height
 */

module.exports.coverTextWatermark = async (mainImage, options) => {
  try {
    options = checkOptions(options);
    const main = await Jimp.read(mainImage);
    const watermark = await textWatermark(options.text, options);
    const positionList = calculatePositionList(main, watermark)
    for (let i =0; i < positionList.length; i++) {
      const coords = positionList[i]
      main.composite(watermark,
        coords[0], coords[1] );
    }
    main.quality(100).write(options.dstPath);
    return {
      destinationPath: options.dstPath,
      imageHeight: main.getHeight(),
      imageWidth: main.getWidth(),
    };
  } catch (err) {
    throw err;
  }
}

textWatermark

Jimp cannot directly rotate the text by a certain angle and write it to the original image, so we need to generate a new image binary stream according to the watermark text and rotate it. Finally, the newly generated image is added to the original image as a real watermark. The following is the function definition of generating watermark image:

const textWatermark = async (text, options) => {
  const image = await new Jimp(options.colWidth, options.rowHeight, '#FFFFFF00');
  const font = await Jimp.loadFont(SizeEnum[options.textSize])
  image.print(font, 10, 0, {
    text,
    alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
    alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
  },
  400,
  50)
  image.opacity(options.opacity);
  image.scale(3)
  image.rotate( options.rotation )
  image.scale(0.3)
  return image
}

calculatePositionList

So far, the original image and the watermark image have existed. If we want to achieve the watermark effect of covering the original image, we also need to calculate which coordinates the watermark image should be drawn on the original image, so as to achieve the purpose of covering the original image with watermark.

const calculatePositionList = (mainImage, watermarkImg) => {
  const width = mainImage.getWidth()
  const height = mainImage.getHeight()
  const stepWidth = watermarkImg.getWidth()
  const stepHeight = watermarkImg.getHeight()
  let ret = []
  for(let i=0; i < width; i=i+stepWidth) {
    for (let j = 0; j < height; j=j+stepHeight) {
      ret.push([i, j])
    }
  }
  return ret
}

As shown in the above code, we use a two-dimensional array to record the coordinate list of all watermark images that need to appear on the original image.

summary

So far, all the main functions of using Jim to add text watermark to pictures have been explained.

github address: https://github.com/swearer23/...

npm: npm i jimp-fullpage-watermark

Inspiration thanks

https://github.com/sushantpau...

https://github.com/luthraG/im...

Image Processing in NodeJS with Jimp - Medium

Example code:

var watermark = require('jimp-fullpage-watermark');

watermark.coverTextWatermark('./img/main.jpg', {
  textSize: 5,
  opacity: 0.5,
  rotation: 45,
  text: 'watermark test',
  colWidth: 300,
  rowHeight: 50
}).then(data => {
    console.log(data);
}).catch(err => {
    console.log(err);
});

Topics: node.js