CodeGo.net>以编程方式创建动画的位图图像

我想“手动”创建一个System.Drawing.Bitmap实例,其中包含一个动画.

要创建的Bitmap实例应满足以下条件:

>这是一个动画(image.FrameDimensionsLists具有一个时间维度)
>它具有多个帧(image.GetFrameCount(dimension)> 1)
>我可以获得帧之间的延迟(image.GetPropertyItem(0x5100).Value)

我很确定可以通过某些WinApi创建这样的图像.这也是GIF解码器实际上所做的.

我知道如果可以手动制作任何来源的帧,就可以播放动画,但是我想以兼容的方式来制作动画:如果我可以生成这样的位图,则可以在Button,Label上简单地使用它,PictureBox或任何其他现有控件,以及内置的ImageAnimator也可以自动处理它.

大多数类似的主题建议将帧转换为动画GIF.但是,这不是一个好的解决方案,因为它不能处理真实的颜色和半透明性(例如APNG动画).

更新:经过一番探索,我了解到我可以使用WIC来实现解码器.但是,我不想在Windows中注册新的解码器,而是使用COM,因此请尽量避免使用.更不用说最后我将拥有一个IWICBitmapSource,我仍然需要将其转换为位图.

更新2:我设置了赏金.如果可以实现以下方法,则您是赢家:

public void Bitmap CreateAnimation(Bitmap[] frames, int[] delays)
{
    // Any WinApi is allowed. WIC is also allowed, but not preferred.
    // Creating an animated GIF is not an acceptable answer. What if frames are from an APNG?
}

解决方法:

    public void Bitmap CreateAnimation(Bitmap[] frames, int[] delays)

像这样对预期的实现设置严格的限制不是很明智.通过利用TIFF图像格式在技术上是可能的,它能够存储多个帧.但是,它们不是基于时间的,只有GIF编解码器支持.需要一个额外的参数,以便可以在需要渲染下一幅图像时更新控件.像这样:

    public static Image CreateAnimation(Control ctl, Image[] frames, int[] delays) {
        var ms = new System.IO.MemoryStream();
        var codec = ImageCodecInfo.GetImageEncoders().First(i => i.MimeType == "image/tiff");

        EncoderParameters encoderParameters = new EncoderParameters(2);
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.MultiFrame);
        encoderParameters.Param[1] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)EncoderValue.CompressionLZW);
        frames[0].Save(ms, codec, encoderParameters);

        encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.FrameDimensionPage);
        for (int i = 1; i < frames.Length; i++) {
            frames[0].SaveAdd(frames[i], encoderParameters);
        }
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.Flush);
        frames[0].SaveAdd(encoderParameters);

        ms.Position = 0;
        var img = Image.FromStream(ms);
        Animate(ctl, img, delays);
        return img;
    }

Animate()方法需要一个Timer来选择下一帧并更新控件:

    private static void Animate(Control ctl, Image img, int[] delays) {
        int frame = 0;
        var tmr = new Timer() { Interval = delays[0], Enabled = true };
        tmr.Tick += delegate {
            frame++;
            if (frame >= delays.Length) frame = 0;
            img.SelectActiveFrame(FrameDimension.Page, frame);
            tmr.Interval = delays[frame];
            ctl.Invalidate();
        };
        ctl.Disposed += delegate { tmr.Dispose(); };
    }

用法示例:

    public Form1() {
        InitializeComponent();
        pictureBox1.Image = CreateAnimation(pictureBox1,
            new Image[] { Properties.Resources.Frame1, Properties.Resources.Frame2, Properties.Resources.Frame3 },
            new int[] { 1000, 2000, 300 });
    }

一种更明智的解决方法是完全降低返回值的要求,因此您不必生成TIFF.只需将Animate()方法与Action< Image>参数以获取控件的属性更新.但不是您要求的.

上一篇:c#-使用矩形在图像上创建搜索区域


下一篇:java-绘制到画布