Я создал простую программу, используя discord.js, я хочу объединить неподвижное изображение с изображением, содержащим анимированные кадры, тогда бот отправит результат анимированного изображения и фон неподвижного изображения в одном изображении.
const Discord = require('discord.js');
const sharp = require('sharp');
const client = new Discord.Client({ intents: ["GUILDS", "GUILD_MESSAGES"] });
client.on('messageCreate', async message => {
if (message.content === '!merge') {
const background = await sharp('logo.png').resize(288, 288);
const overlay = await sharp('banana.gif').resize(288, 288);
const result = await background.composite([{ input: await overlay.toBuffer(), gravity: 'center' }]).toBuffer();
message.channel.send({ files: [result] });
}
});
client.login('your-token');
Но результат не удался, присылает статическое изображение без анимированных кадров в формате GIF.
Я пытался найти посылку, но ничего не нашел.
Мы надеемся, что кто-нибудь сможет нам помочь в этом, спасибо.
Чтобы создать анимированное изображение, вы должны указать Sharp, чтобы анимировать результат композиции.
Согласно документации поведение составного элемента по умолчанию должно иметь значение по умолчанию —animated = false. Итак, что вы хотите сделать, так это сообщить ему, какие изображения анимированы.
В соответствии с этим ТАК Ответ мы можем скомпоновать изображение, создав рулон изображения фона и скомпоновав его.
Однако, когда я сделал это и попробовал чтобы бот Discord отправлял данные прямого буфера, в результате это было статическое изображение... Поэтому обходной путь состоит в том, чтобы записать изображение в файл, отправить файл, а затем очистить файл после его отправки.
Ваш адаптация кода этого ответа находится здесь:
const Discord = require('discord.js');
const sharp = require('sharp');
const fs = require('fs'); // we'll use fs to clean up the file afterward.
const client = new Discord.Client({ intents: ["GUILDS", "GUILD_MESSAGES"] });
async function overlayGif (background, gifOverlay, outFile) { //takes two input paths.
const backgroundImg = await sharp(background).resize(288, 288);
const overlay = await sharp(gifOverlay, {animated: true}).resize(288, 288); //make sure animated is true.
const metadata = await overlay.metadata(); //We'll use the gif metadata to normalize the background.
const imgRoll = backgroundImg.extend({bottom: 288*(metadata.pages-1), extendWith: 'repeat'}); //Must extend to repeat how ever many pages (frames) are in the gif.
const result = await imgRoll.composite([
{ input: await overlay.toBuffer(), gravity: 'center', animated: true}
]).gif (
{progressive: metadata.isProgressive, delay: metadata.delay, loop: metadata.loop}
//Just copying the metadata from the gif to the output format (not sure this is necessary).
);
const resInfo = await result.toFile(outFile); //Write the result to a gif file.
return result;
}
client.on('messageCreate', async message => {
if (message.content === '!merge') {
const tmpFile = (new Date()).getTime()+".gif";
const result = await overlayGif ("logo.png", "banana.gif", tmpFile);
message.channel.send({ files: [tmpFile]}).then(async (msg)=>{
fs.unlink(tmpFile, (err)=>{
if (err) console.error(err);
});// clean up the file.
}).catch(async (err) => {
fs.unlink(tmpFile, (err)=>{
if (err) console.error(err);
});// clean up file if bot was unable to send.
});
}
});
client.login('your-token');
Судя по вашему коду, вы используете устаревшую версию Discord. Для тех, кто использует Discord v14 и более поздние версии, код будет выглядеть так:
const Discord = require('discord.js');
const sharp = require('sharp');
const Color = require('color');
const fs = require('fs');
const client = new Discord.Client({ intents: [
Discord.GatewayIntentBits.Guilds,
Discord.GatewayIntentBits.GuildMessages,
Discord.GatewayIntentBits.MessageContent]
});
async function overlayGif (background, gifOverlay, outFile) { //takes two input paths.
const backgroundImg = await sharp(background).resize(288, 288);
const overlay = await sharp(gifOverlay, {animated: true}).resize(288, 288); //make sure animated is true.
const metadata = await overlay.metadata(); //We'll use the gif metadata to normalize the background.
const imgRoll = backgroundImg.extend({bottom: 288*(metadata.pages-1), extendWith: 'repeat'}); //Must extend to repeat how ever many pages (frames) are in the gif.
const result = await imgRoll.composite([
{ input: await overlay.toBuffer(), gravity: 'center', animated: true}
]).gif (
{progressive: metadata.isProgressive, delay: metadata.delay, loop: metadata.loop}
//Just copying the metadata from the gif to the output format (not sure this is necessary).
);
const resInfo = await result.toFile(outFile); //Write the result to a gif file.
return result;
}
client.on('messageCreate', async message => {
console.info(message.content);
if (message.content === '!merge') {
const tmpFile = (new Date()).getTime()+".gif";
const result = await overlayGif ("logo.png", "banana.gif", tmpFile);
message.channel.send({ files: [tmpFile]}).then(async (msg)=>{
fs.unlink(tmpFile, (err)=>{
if (err) console.error(err);
});// clean up the file.
}).catch(async (err) => {
fs.unlink(tmpFile, (err)=>{
if (err) console.error(err);
});
});
}
});
client.login("super-secret-token");
В этом примере я использую текущее время для создания «уникального» имени файла. Используйте соответствующий пакет, чтобы сделать файлы по-настоящему уникальными, и обязательно используйте правильную обработку ошибок. Этот код предназначен для демонстрационных целей (в качестве отправной точки).
@AchrafOu ответ был обновлен после множества препятствий.
Это меня буквально спасло, и я пытался это исправить целую неделю. Спасибо тебе от всего сердца, чувак, и я благодарен тебе за это. Теперь это работает благодаря вам. Еще раз спасибо. <3
Спасибо за ответ @sharp-dev, я исправил ошибку, как просили, но анимированного результата все равно не дает.