Использование составной функции пакета node js Sharp не дает анимированного результата

Я создал простую программу, используя 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.
Я пытался найти посылку, но ничего не нашел.

Мы надеемся, что кто-нибудь сможет нам помочь в этом, спасибо.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
132
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Чтобы создать анимированное изображение, вы должны указать 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");

В этом примере я использую текущее время для создания «уникального» имени файла. Используйте соответствующий пакет, чтобы сделать файлы по-настоящему уникальными, и обязательно используйте правильную обработку ошибок. Этот код предназначен для демонстрационных целей (в качестве отправной точки).

Спасибо за ответ @sharp-dev, я исправил ошибку, как просили, но анимированного результата все равно не дает.

AchrafOu 05.05.2024 05:18

@AchrafOu ответ был обновлен после множества препятствий.

Sharp Dev 05.05.2024 23:12

Это меня буквально спасло, и я пытался это исправить целую неделю. Спасибо тебе от всего сердца, чувак, и я благодарен тебе за это. Теперь это работает благодаря вам. Еще раз спасибо. <3

AchrafOu 05.05.2024 23:57

Другие вопросы по теме