【问题标题】:C# GIF encoder/decoderC# GIF 编码器/解码器
【发布时间】:2018-09-08 17:33:22
【问题描述】:

我正在开发一个程序,它可以加载一个动画 GIF 文件并更改一些像素,然后将其作为新的动画 GIF 文件返回。输出的 GIF 动画在 Windows、浏览器和 Photoshop 中都很好。

但是,如果我尝试用我的程序加载 GIF,它不会动画。此外,我无法获得正确的调色板。加载代码与我最初用来加载原始 GIF 的代码完全相同。

这是我的保存代码:

   public int saveAsGif(string absPath, byte[] mark)
    {
        BitmapPalette palette = new BitmapPalette(getPaletteAsMediaColorList(m_Pal));

        int width = m_CanvasWidth;
        int height = m_CanvasHeight;

        using (FileStream fs = new FileStream(absPath, FileMode.Create))
        {
            GifBitmapEncoder encoder = new GifBitmapEncoder();

            for (int f = 0; f < m_NumberOfFrames; f++)
            {
                FrameData frame = m_Frames[f];
                byte[] pixels = frame.pixels;

                BitmapSource image = BitmapSource.Create(
                    width,
                    height,
                    96,
                    96,
                    System.Windows.Media.PixelFormats.Indexed8,
                    palette,
                    pixels,
                    width);

                encoder.Frames.Add(BitmapFrame.Create(image));

            }
            encoder.Save(fs);

            fs.Close();
        }

        return RESULT_SUCCESFUL;
    }

为了确保这不是我的加载代码,我使用以下代码创建了一个普通的新项目:

    private void Form1_Load(object sender, EventArgs e)
    {
        Bitmap test1 = new Bitmap(@"F:\original.gif");
        pictureBox1.Image = test1;

        Bitmap test2 = new Bitmap(@"F:\exported.gif");
        pictureBox2.Image = test2;
    }

original.gif 将完美加载和播放,exported.gif 只会显示静止帧。但是,在 Windows/Browser/Photoshop 中,exported.gif 会播放。

【问题讨论】:

  • `如果我尝试用我的程序加载 GIF,它不会动画`,你用哪个控件来显示它?即使使用普通的图片框,它仍然会显示动画
  • "输出的 GIF 动画在 Windows、浏览器和 Photoshop 中都很好。"所以它被创建得很好。我认为您向我们展示的代码不是问题。
  • "即使使用普通的图片框,它仍然会显示动画":这不适用于导出的 GIF。我已经用加载示例更新了我的初始帖子。所有 GIF(我用上面的代码导出的除外)都可以正常加载和播放。
  • 这真的感觉像是图片框的一个问题,它不像您为转换后的 gif 尝试的所有其他 gif 渲染器那样宽容。建议您使用 gif 并不完美,但对于除了图片框之外的所有内容都足够接近。我很好奇它是否与每帧的位图有关。 96dpi 是一个奇怪的选择,但我认为它不会影响 gif,因为 gif 不关心 dpi。也许无论如何设置为72,看看会发生什么。此外,您的步幅不正确。步幅是位图一行的字节数,或(width * pixels.BitsPerPixel + 7)/8
  • 也许值得调整一下,看看它是否能让 PictureBox 开心。在这里完全猜测,因为一切看起来都不错,并且您正在编写并显示除 PictureBox 控件之外的任何地方的 gif。

标签: c# encoding gif decoding


【解决方案1】:

我找到了一个相对简单的解决方案。它并不完美,但它对我有用。它仅适用于 GifBitmapEncoder,不需要额外的库。

所有你需要做的;

  1. 将 GIF 数据从编码器写入内存流。
  2. 二进制写入前 13 个字节(GIF89a 标头和内容)。
  3. 二进制写入“ApplicationExtention”块。
  4. 二进制写入其余的 GIF 数据。

ApplicationExtention 块允许动画。如果未设置延迟时间,则使用默认时间 100 毫秒。如果您确实想要为每帧自定义延迟,则需要在其间添加更多字节(请参阅 GIF 文件格式文档)。

代码:

public void saveAsGif(string absPath)
{
    int width = m_CanvasWidth;
    int height = m_CanvasHeight;

    GifBitmapEncoder encoder = new GifBitmapEncoder();
    BitmapPalette palette = new BitmapPalette(getPaletteAsMediaColorList(m_Pal));

    for (int f = 0; f < m_NumberOfFrames; f++)
    {
        FrameData frame = m_Frames[f];
        byte[] pixels = frame.pixels;

        BitmapSource image = BitmapSource.Create(
            width,
            height,
            96,
            96,
            System.Windows.Media.PixelFormats.Indexed8,
            palette,
            pixels,
            width);

        encoder.Frames.Add(BitmapFrame.Create(image));
    }

    byte[] GifData;
    using (MemoryStream ms = new MemoryStream())
    {
        encoder.Save(ms);
        GifData = ms.ToArray();
    }

    byte[] ApplicationExtention = { 33, 255, 11, 78, 69, 84, 83, 67, 65, 80, 69, 50, 46, 48, 3, 1, 0, 0, 0 };

    using (FileStream fs = new FileStream(absPath, FileMode.Create))
    {
        fs.Write(GifData, 0, 13);
        fs.Write(ApplicationExtention, 0, ApplicationExtention.Length);
        fs.Write(GifData, 13, GifData.Length - 13);
    }
}

【讨论】:

    猜你喜欢
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 1970-01-01
    • 2011-05-18
    相关资源
    最近更新 更多