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:
And here is the gif after:
If anyone has any potential solutions, please let me know. I am also more than willing to provide more context if needed. Thanks you!
It turns out that when working with animated GIFs using sharp, you have to use metadata.pageHeight
instead of metadata.height
.