Search code examples
node.jssharp

How can I overlay an image on top of an animated gif using sharp?


I am trying to overlay text on top of an animated gif using sharp. The text is being generated using node-canvas, and I am converting it to a buffer to be overlayed. The resulting gif only has the overlayed text on the first frame, instead of every single frame.

I've read all over the internet that in order to fix this, I need to set tile to true when using the composite method. However in my case this does not fix the issue I am having.

Here is my code:

        const text: string = this.interaction.options.getString("text", true);
        const processedImage = sharp(editImage.getData(), {
            animated: !editImage.isStatic(),
            pages: -1
        });
        const imageData = await processedImage.metadata();
        const fontSize: number = Math.min(imageData.width, imageData.height) / 8;
        const canvas = new Canvas(imageData.width, imageData.height);
        const ctx = canvas.getContext("2d");
        ctx.font = `${fontSize}px Impact`;
        const lines = StringUtils.wrapText(ctx, text, imageData.width);
        this.memeText(canvas, text, fontSize);
        const textPng = await sharp(await canvas.toBuffer())
            .png()
            .toBuffer();
        const compiledImage: Buffer = await processedImage
            .gif()
            .composite([{ input: textPng, tile: true, gravity: "northwest" }])
            .toBuffer();
        const embed = EmbedUtils.gifEmbed(
            imageData.width,
            imageData.height,
            10,
            (Date.now() - this.interaction.createdTimestamp) / 1000,
            "attachment://meme." + editImage.getExtension()
        );
        await this.interaction.followUp({
            files: [
                {
                    attachment: compiledImage,
                    name: "meme." + editImage.getExtension()
                }
            ],
            embeds: [embed]
        });

Here is the gif before:

enter image description here

And here is the gif after:

enter image description here

If anyone has any potential solutions, please let me know. I am also more than willing to provide more context if needed. Thanks you!


Solution

  • It turns out that when working with animated GIFs using sharp, you have to use metadata.pageHeight instead of metadata.height.