0

These are my codes I used for adding watermark to an image:

    const ORIGINAL_IMAGE = "https://example/sample_image;
    const LOGO = fs.readFileSync('gangle.png');
    const LOGO_MARGIN_PERCENTAGE = 5;

    let [image, logo] = await Promise.all([
      Jimp.read(ORIGINAL_IMAGE),
      Jimp.read(LOGO)
    ]);

    logo.resize(image.bitmap.width, Jimp.AUTO);

    const xMargin = (image.bitmap.width * LOGO_MARGIN_PERCENTAGE) / 100;
    const yMargin = (image.bitmap.width * LOGO_MARGIN_PERCENTAGE) / 100;

    const X = image.bitmap.width - logo.bitmap.width - xMargin;
    const Y = image.bitmap.height - logo.bitmap.height - yMargin;

    image.composite(logo, X, Y, [
      {
        mode: Jimp.BLEND_SCREEN,
        opacitySource: 0.1,
        opacityDest: 1
      }
    ]);

    image.write('animatedimg.gif')

But it only works on image with filetype png/jpg/jpeg. It doesn't work on gif image.

It will generate a file 'animatedimg.gif', but that file won't load to any image viewer or browser.

If I try to open that file in mac, the popup will appear with message: "The file “animatedimg.gif” could not be opened because it is empty."

Is there any way to do that in jimp? Or is there other npm package for that? Thank you.

noyruto88
  • 767
  • 2
  • 18
  • 40
  • 1
    you'd need to process each frame of the GIF adding the watermark to each one ... does *jimp* have such functionality? perhaps [gifwrap](https://www.npmjs.com/package/gifwrap) will help – Jaromanda X Nov 04 '20 at 03:29
  • @JaromandaX I will try that, thank you. – noyruto88 Nov 04 '20 at 03:38
  • @JaromandaX Is there a way to read image from url using gifwrap? – noyruto88 Nov 06 '20 at 02:16
  • sorry, I haven't read the documentation for gifwrap - there's something about it being useful *in conjunction with jimp* either in jimp or gifwrap documentation - read documentation and try things is all I'll say, because it's your project – Jaromanda X Nov 06 '20 at 02:20
  • @noyruto88 No, you'll have to do it yourself. Make an HTTP request, write that file to your file system, and then leverage `gifwrap` to read that file you just saved with `GifUtil.read`. – Adam Zerner Dec 22 '20 at 22:08

2 Answers2

2

Confusingly, Jimp only deals with single frame GIFs, not the multi-frame animated GIFs that most people think of. So you need to use gifwrap.

From there you could iterate over each frame in the multi-frame GIF. Each frame is a GifFrame, which can be converted back and forth to a Jimp instance (see Leveraging Jimp in the docs). You can add your watermark to each Jimp instance that corresponds to a GifFrame. Something like this:

async function getGifFramesWithWatermarks(gifPath) {
  const readGif = await GifUtil.read(gifPath);
  const promises = readGif.frames.map(getGifFrameWithWatermark);
  const gifFramesWithWatermarks = await Promise.all(promises);

  return gifFramesWithWatermarks;
}

async function getGifFrameWithWatermark(gifFrame) {
  const jimpImage = GifUtil.copyAsJimp(Jimp, gifFrame);

  addWatermark(jimpImage); // function you will write

  return new GifFrame(jimpImage.bitmap, {
    disposalMethod: gifFrame.disposalMethod, // not documented by gifwrap but it's in the source
    delayCentisecs: gifFrame.delayCentisecs, // you'll probably want this
  });
}

const gifFramesWithWatermarks = await getGifFramesWithWatermark(GIF_PATH);
await GifUtil.write(WRITE_PATH, gifFramesWithWatermarks);
Adam Zerner
  • 17,797
  • 15
  • 90
  • 156
2

UPDATE i wrote this npm library that you can use to write text on gif. its still has some bugs tho: https://www.npmjs.com/package/text-on-gif

this worked for me

const Jimp = require("jimp");
const { GifUtil,GifFrame,BitmapImage} = require('gifwrap');
var frames = [];

Jimp.loadFont(Jimp.FONT_SANS_32_WHITE).then(async function(font){
    await GifUtil.read("gif.gif").then(inputGif => {
        inputGif.frames.forEach(function(frame){
            jimpCopied = GifUtil.copyAsJimp(Jimp, frame);
            jimpCopied.print(font,0,0,"sanidhya");
            const GifCopied = new GifFrame(new BitmapImage(jimpCopied.bitmap,{
                disposalMethod: frame.disposalMethod,
                delayCentisecs: frame.delayCentisecs,
            }));
        frames.push(GifCopied);   
        });
    });
    GifUtil.quantizeDekker(frames);
    GifUtil.write("nyahhaha.gif",frames);
});

NOTE

the qunatize*() function is needed only if your Frame uses more than 256 color indexes

codeboi
  • 150
  • 1
  • 9