I have been trying to get my args to work and they do but I am not sure how to make a separator for it so I don't have to use the command twice. Here's my code.
const discord = require('discord.js');
const Jimp = require('jimp');
const fs = require('fs')
module.exports = {
name: "cat",
aliases: [],
run: async(client, message, args) => {
//const top = args[0]
//const bottom = args[1]
let [top, bottom] = args
Jimp.read("assets/cat.jpg").then(function(image) {
Jimp.loadFont(Jimp.FONT_SANS_32_WHITE).then(function(font) {
image.print(font, 60, 22, top, 5);
image.print(font, 60, 350, bottom);
image.write('output-image.jpg');
});
});
await message.channel.send({
files: [
"output-image.jpg"
]
});
fs.unlinkSync('output-image.jpg');
}
};
And here's the output I get.
The problem is that you want to send the file outside of the promise's .then()
method. When you call await message.channel.send()
the file is just being read by jimp
and the output-image.jpg
is nowhere near ready.
As your run()
method is already an async function, you could use async-await to make your code more readable. That way you can get rid of the callbacks and make it easier to follow what's happening and in what order.
As Skulaurun Mrusal mentioned in their comment, you don't even need to save the file, you could just send a buffer. Jimp has a .getBuffer()
method you can use to generate a binary buffer of an image.
You can send this buffer as an attachment. Discord.js has a MessageAttachment
object that accepts a buffer as the first argument. You can send this attachment by passing it to message.channel.send(new MessageAttachment(buffer))
.
Currently, as your args
is an array of space-separated strings, you can only add one word as the text on the top and another one as the bottom text. It's probably easier to accept two longer text that's inside double quotes ("
).
So the command should be used like this:
!cat "This is the text on the top" "And we are down here"
You can use a "simple" regex that matches strings that are inside double quotes. In the next example, you can see that matches
is an array of the two substring inside the double quotes. They include the quotes too, so you'll need to get rid of that with a String#replace()
method.
let content = '!cat "This is the text on the top" "And we are down here"'
let matches = content.match(/"(.*?)"/g)
console.log({ matches })
At the moment you're using "magic numbers" (60, 22, 350, 5, etc.) to position the text. It won't work and (depending on the text submitted through the command) it will be all over the image, and chances are it will never be centred.
Jimp has different align modes you can take advantage of. To align the text to the centre horizontally, you can use HORIZONTAL_ALIGN_CENTER
, to align to the top, you can use VERTICAL_ALIGN_TOP
, etc. Make sure to set the max width and max height to the image's width and height. You can get it using image.bitmap.width
and image.bitmap.height
const { MessageAttachment } = require('discord.js');
const Jimp = require('jimp');
module.exports = {
name: 'cat',
aliases: [],
run: async (client, message, args) => {
let matches = message.content.match(/"(.*?)"/g);
let [topText, bottomText] = matches
? matches.map((m) => m.replace(/"/g, '').toUpperCase())
: args;
if (!topText)
return message.channel.send(`Don't forget to add the text you want to print`);
try {
let image = await Jimp.read('cat.jpg');
let font = await Jimp.loadFont(Jimp.FONT_SANS_64_WHITE);
let padding = 40;
let pos = {
x: 0,
yTop: padding,
yBottom: padding * -1,
maxWidth: image.bitmap.width,
maxHeight: image.bitmap.height,
};
image.print(
font,
pos.x,
pos.yTop,
{
text: topText,
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
alignmentY: Jimp.VERTICAL_ALIGN_TOP,
},
pos.maxWidth,
pos.maxHeight,
);
if (bottomText)
image.print(
font,
pos.x,
pos.yBottom,
{
text: bottomText,
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
alignmentY: Jimp.VERTICAL_ALIGN_BOTTOM,
},
pos.maxWidth,
pos.maxHeight,
);
let buffer = await image.getBufferAsync(Jimp.MIME_JPEG);
message.channel.send(new MessageAttachment(buffer));
} catch (err) {
console.log(err);
message.channel.send('Oops, there was an error. Maybe try again later?!');
}
},
};
The image of the cat is available on Unsplash.