You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Node.js Sharp包合成动图无动画效果问题求助

问题原因

Sharp 的 composite 方法处理 GIF 时,只会提取并处理 GIF 的第一帧,因此最终输出的是静态图,无法保留原 GIF 的动画效果。要实现静态背景+动态GIF的合成,需要逐帧处理GIF的每一个动画帧,再重新打包成新的GIF。

解决方案

使用 gifwrap 库(专门处理GIF帧的工具)配合 sharp 来逐帧合成,步骤如下:

1. 安装依赖

npm install gifwrap sharp

2. 修改后的代码

const Discord = require('discord.js');
const { GifReader, GifWriter } = require('gifwrap');
const sharp = require('sharp');
const fs = require('fs').promises;

const client = new Discord.Client({ intents: ["GUILDS", "GUILD_MESSAGES"] });

client.on('messageCreate', async message => {
    if (message.content === '!merge') {
        try {
            // 读取静态背景图并转为Buffer
            const bgBuffer = await fs.readFile('logo.png');
            const bgSharp = sharp(bgBuffer).resize(288, 288);
            const bgData = await bgSharp.raw().toBuffer({ resolveWithObject: true });
            
            // 读取GIF文件并解析所有帧
            const gifBuffer = await fs.readFile('banana.gif');
            const reader = new GifReader(gifBuffer);
            
            // 准备合成后的帧数据
            const frames = [];
            for (let i = 0; i < reader.numFrames(); i++) {
                // 提取当前GIF帧的原始数据
                const frame = reader.frameInfo(i);
                const frameBuffer = reader.getFrameData(i);
                
                // 将GIF帧转为Sharp可处理的格式,调整尺寸
                const frameSharp = sharp(Buffer.from(frameBuffer), {
                    raw: {
                        width: frame.width,
                        height: frame.height,
                        channels: 4
                    }
                }).resize(288, 288);
                const frameData = await frameSharp.raw().toBuffer();
                
                // 合成背景与当前帧:背景在下,GIF帧在上(带透明通道)
                const compositeBuffer = await sharp(bgData.data, {
                    raw: {
                        width: bgData.info.width,
                        height: bgData.info.height,
                        channels: 4
                    }
                })
                .composite([{
                    input: frameData,
                    raw: {
                        width: 288,
                        height: 288,
                        channels: 4
                    },
                    gravity: 'center'
                }])
                .raw()
                .toBuffer();
                
                // 将合成后的帧加入列表,保留原帧的延迟时间
                frames.push({
                    data: compositeBuffer,
                    delayCentiseconds: frame.delayCentiseconds
                });
            }
            
            // 将所有合成帧打包为新的GIF
            const writer = new GifWriter(288, 288);
            await Promise.all(frames.map(frame => writer.addFrame(frame.data, { delayCentiseconds: frame.delayCentiseconds })));
            const finalGifBuffer = writer.getOutputBuffer();
            
            // 发送合成后的GIF
            message.channel.send({ files: [{ attachment: finalGifBuffer, name: 'merged.gif' }] });
        } catch (err) {
            console.error(err);
            message.channel.send('合成图片时出错了!');
        }
    }
});

client.login('your-token');

代码说明

  • GifReader 负责解析原GIF的所有帧、延迟时间等动画信息
  • 对每一帧单独执行合成操作:将静态背景与当前GIF帧叠加,确保每帧都保留动画效果
  • GifWriter 将合成后的所有帧重新打包为新的GIF,同时保留原GIF的帧延迟参数,保证动画速度一致
  • 使用 sharp.raw() 处理像素数据,提升合成效率,同时确保透明通道正确叠加

内容的提问来源于stack exchange,提问作者AchrafOu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 20:33:33