前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C# .net core中如何将多张png图片合并成一个gif

C# .net core中如何将多张png图片合并成一个gif

作者头像
乔达摩@嘿
发布2023-07-31 10:27:51
5450
发布2023-07-31 10:27:51
举报
文章被收录于专栏:嘿dotNet嘿dotNet

背景

我们有很多这样的序列帧:

image-20230727114152382
image-20230727114152382

我这边要把这些序列帧裁切最后合并成gif,以下是我裁切后的png文件:

image-20230727115247029
image-20230727115247029

我一开始选用的是 SixLabors.ImageSharp

这是裁切代码:

代码语言:javascript
复制
using var image = Image.Load("input.jpg");
image.Clone(x => x.Crop(new Rectangle(10, 10, 250, 250)));
image.Save("output.jpg");

gif合成方案1(SixLabors.ImageSharp)

这里直接给出核心代码

代码语言:javascript
复制
public string FrameCombine(List<FrameConfig> frames, int fps)
{
    Image firstFrame = null;
    var delay = 100 / fps; //根据帧率技术延迟
    GifDisposalMethod disposalMethod = GifDisposalMethod.RestoreToBackground; //背景处理方式
    string outputPath = null;

    for (int i = 0; i < frames.Count; i++)
    {
        Image tempImage = Image.Load(frames[i].Path);
        if (i == 0) //第一帧做底图
        {
            outputPath = Path.Combine(Path.GetDirectoryName(frames[i].Path), "sticker.gif");
            if (File.Exists(outputPath))
            {
                return null;
            }

            firstFrame = tempImage;
            firstFrame.Frames.RootFrame.Metadata.GetGifMetadata().FrameDelay = delay;
            firstFrame.Metadata.GetGifMetadata().RepeatCount = 0;
        }
        else
        {
        	//把其他帧合到第一帧上
            firstFrame.Frames.AddFrame(tempImage.Frames.RootFrame);
            var meta = firstFrame.Frames[i].Metadata.GetGifMetadata();
            meta.FrameDelay = delay;
            meta.DisposalMethod = disposalMethod;
        }
    }

    firstFrame.SaveAsGif(outputPath);

    return outputPath;
}

最后合成效果(都多多少少有点问题)

大致显示正常(但锯齿和毛边严重)

sticker
sticker

还有这样的(带莫名的绿色噪点/绿底等):

sticker
sticker
sticker
sticker

这样的(莫名灰底):

sticker
sticker

试了很多方方法,想尽办法调各种属性都不行,看来用SixLabors.ImageSharp比较难解决了;

gif合成方案2(FFmpeg)--推荐

前面SixLabors.ImageSharp方案生成的gif太多问题了,最终是用FFmpeg重新合成才实现的。

步骤

首先,为所有图片生成一个统一的调色板:

代码语言:javascript
复制
ffmpeg -i %02d.png -vf "palettegen" palette.png

然后,使用这个调色板的颜色为基础来生成GIF:

代码语言:javascript
复制
ffmpeg -r 16 -i  %02d.png  -i palette.png -lavfi paletteuse sticker.gif

-r 16 :帧率
-i palette.png :是用于为GIF提供颜色调色板的图像。
-lavfi paletteuse:这是一个复杂的滤镜图描述,指示ffmpeg如何处理输入内容。paletteuse是一个特定的滤镜,它使用前面的name.png输入作为源来生成一个调色板,并使用这个调色板来处理其他输入(在本例中即img_%d.png匹配到的文件)。

将这两条命令合成一条

代码语言:javascript
复制
ffmpeg  -r 16 -i %02d.png -filter_complex "palettegen=stats_mode=single[pal],[0:v][pal]paletteuse" sticker.gif

C#写法(用了这个执行控制台命令的nuget CliWrap

代码语言:javascript
复制
var workDir = Path.GetDirectoryName(frames[0].Path);
var outputPath = Path.Combine(workDir, "sticker.gif");
var param = $" -r {fps} -i %02d.png -filter_complex \"palettegen=stats_mode=single[pal],[0:v][pal]paletteuse\" {outputPath} -y";

try
{
    var result = await Cli.Wrap("ffmpeg").WithArguments(param).WithWorkingDirectory(workDir).ExecuteBufferedAsync();

    if (result.ExitCode == 0)
    {
        return outputPath;
    }

    return outputPath;
}
catch (Exception ex)
{
    logger.LogError(ex, "FrameCombine2 failed:{0}", frames[0]?.Path);
}

最后展示效果

sticker
sticker
sticker
sticker
sticker
sticker

总结

有的时候其实是比较简单的问题,但如果思路限制在C#的话可能还是比较麻烦的,要去一个个图片处理库试了;

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-07-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
    • gif合成方案1(SixLabors.ImageSharp)
      • gif合成方案2(FFmpeg)--推荐
      • 总结
      相关产品与服务
      图片处理
      图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档