Business background

As the export function of the background project, it is usually required to have the traceability of the export.

When the exported data is an image, watermarks are added to the image to achieve this purpose.

DEMO

So how to add a watermark to the image before exporting it as the identity of the exporter? First, the finished product:

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

Business requirement decomposition

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

  • The watermark needs to cover the entire image
  • The watermark text is translucent to ensure the readability of the original picture
  • The watermark text should be legible

The selection

As I am responsible for implementing the above requirements on a NodeJS server, there are quite a few options, such as directly using C lib Imagemagick or the various Node watermarking libraries that someone has packaged. In this article, we will choose to use encapsulation of the Jimp library.

The official Github page for 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 number of apis for manipulating images

  • 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 these apis.

Design and implementation

Input parameter design:

  • Url: The storage address of the original image (in the case of Jimp, this can be a remote or local address)
  • TextSize: indicates the watermark textSize to be added
  • Opacity:
  • Text: watermark text to be added
  • DstPath: indicates the address of the output image after the watermark is added. The address is the relative path of the script execution directory
  • Rotate: Indicates the rotation Angle of watermark text
  • ColWidth: Since the rotatable watermarked text is overlaid on the original image as an image, define the width of the watermarked image here. The default is 300 pixels
  • RowHeight: For the same reason, the height of the watermark image, the default is 50 pixels. (PS: The size of watermark picture here can be roughly understood as the interval of watermark text)

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

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;
  }
}
Copy the code

textWatermark

Jimp cannot directly rotate the text by an Angle and write to the original image, so we need to generate a new image binary stream from the watermarked text and rotate it. Finally, the newly generated image is added to the original image as a real watermark. Here is the function definition for generating watermarked images:

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}Copy the code

calculatePositionList

So far, the original image and the watermark image are available. If we want to achieve the watermark effect of covering the original image, we also need to calculate the coordinates on which the watermark image should be painted on the original image, so as to achieve the purpose of covering the original image with the 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
}
Copy the code

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

conclusion

At this point, all the main functions of adding text watermarks to images using Jimp have been explained.

Github address: github.com/swearer23/j…

NPM: NPM I jimp-fullpage-watermark

Inspiration thanks

Github.com/sushantpaud…

Github.com/luthraG/ima…

Image Processing in NodeJS with Jimp – Medium

Sample code:

var watermark = require('jimp-fullpage-watermark'); Watermark. CoverTextWatermark (". / img/main. JPG ', {textSize: 5, opacity: 0.5, rotation: 45, the text: 'watermark test', colWidth: 300, rowHeight: 50 }).then(data => { console.log(data); }).catch(err => { console.log(err); });Copy the code