C#中的GIF动画文件帧率比应该低。

5
我的软件运行完后会出现全屏加载页面,其中包括一个预加载的gif文件...它与Windows 8用于商店和Metro的文件完全相同。然而问题是,无论gif文件的fps和速度如何,C#窗体都会显示较低的fps。我真的不知道该怎么办,因为我已经尝试在互联网上寻找解决方案,但我遇到的一切都不清楚或无关。我怀疑编译器以某种方式忽略了我导入的gif文件中集成的fps。但我不知道如何将fps设置为文件中的值,或者让IDE/编译器在处理该文件时忽略其规则。请建议。这是我正在使用的文件属性链接http://preloaders.net/en/search/windows%208,它是从顶部行的中间开始的...它有75帧,其他都是原样...我目前正在使用一个picturebox控件将gif包含在我的项目中(它在一个winform项目中)。
2个回答

12

这只是一个普通的意外事件,GIF文件会以10毫秒为单位指定每帧的显示时间。但是Windows上的计时器默认情况下不够精确,无法计时如此低的时间间隔。计时器由系统时钟中断更新,它默认情况下每秒钟会进行64次打点。这样给计时器带来的精度不超过15.625毫秒。实际上,您的GIF将以约2/3的速度播放。

您可以通过启动另一个程序(例如Windows Media Player或Firefox或Chrome浏览器)来改变结果,然后您会突然看到您的GIF以设计速度播放。

您需要像这些程序一样做同样的事情,即改变时钟中断率以获得一致的播放速度。您需要使用 timeBeginPeriod,传递10以将计时器精度提高到10毫秒。如果您的UI线程不响应并且开始计时器太晚,则可能需要将该值调低。请确保在不再需要播放时再次调用pinvoke timeEndPeriod(),通常在FormClosed事件处理程序中。

代码模板:

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
        timeBeginPeriod(timerAccuracy);
    }

    protected override void OnFormClosed(FormClosedEventArgs e) {
        timeEndPeriod(timerAccuracy);
        base.OnFormClosed(e);
    }

    // Pinvoke:
    private const int timerAccuracy = 10;
    [System.Runtime.InteropServices.DllImport("winmm.dll")]
    private static extern int timeBeginPeriod(int msec);
    [System.Runtime.InteropServices.DllImport("winmm.dll")]
    public static extern int timeEndPeriod(int msec);
}

2
有一次我妈妈告诉我,如果她把媒体播放器保持在后台运行,她的小球游戏就会运行得更好 - 那时我只是笑了笑。现在我明白了解释的原因 :) - Tolga Evcimen
1
但我现在来这里是因为我的Windows窗体应用程序出现了问题,而且这段代码对媒体播放器也没有任何影响。在应用此样板代码时,我还需要注意其他方面吗? - Tolga Evcimen
显然你敲错了门。点击“提问”按钮,展示体面的复现代码。 - Hans Passant
我可以,但那不是一个重复的问题吗?这是问题的链接:http://stackoverflow.com/questions/34224074/gifs-framerate-seems-lower-then-actual?noredirect=1#comment56192330_34224074 - Tolga Evcimen
@TolgaEvcimen 是的,曾经有一段时间我发现如果我最小化反恐精英专用服务器(它是一个游戏服务器),并运行Windows Media Player,它会将ping时间减少到原来的1/7... 直到我得到答案之前,我从未知道为什么。 - Niklas
@HansPassant 目前在 WinForms 上是否更改了这种行为? - Niklas

1

那个被接受的答案对我不起作用,或者我只是没有做对。

但是我通过使用计时器找到了一种解决方案。请参见此链接:https://social.msdn.microsoft.com/Forums/vstudio/en-US/c5ce514f-6fe7-4870-ae3f-c49fb946d294/too-slow-gif?forum=vbgeneral

是的,它是VB,但我们可以在C#中做类似的事情。它们非常相似。 以上解决方案将gif加载到图像中,并在计时器触发时逐个加载图像。

在我的情况下,我从GIF图像中提取所有帧并将这些图像加载到我的表单构造函数中的图像数组中,应用了类似的方法。

    public partial class Splash : Form
{
    Image[] images = new Image[60];
    public Splash()
    {
        InitializeComponent();
        LoadImages();
    }

    private void LoadImages()
    {
        for (int i = 1; i <= 60; i++)
        {
            string path = $@"{Application.StartupPath}\loading\loading{i:0000}.png";
            Image image = Image.FromFile(path);
            images[i - 1] = image;
        }
    }

    int i = 0;
    private void timer1_Tick(object sender, EventArgs e)
    {
        i = i % 60;
        pictureBox1.Image = images[i];
        i += 1;
    }
}

我正在处理加载闪屏,最终完成了上述提到的事情。流畅、优美。只需调整计时器间隔以获得更高的帧率即可。

接受的答案已不再有效,此外PictureBox使用了一个ImageAnimator,它有一个硬编码的50毫秒延迟来更改gif中的下一张图片,似乎无法更改:/ 我正在使用您的答案,谢谢! - Bloodday

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接