MSDN > 論壇首頁 > Windows Presentation Foundation (WPF) > How to use an animated gif?
發問發問
 

已答覆How to use an animated gif?

  • 2006年3月28日 上午 12:04Derek Ju 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    I was wondering if there was a way to play an animated gif?  I tried setting the source of an image to a gif file but it only loads the first frame of the gif and that's it.

解答

  • 2006年3月28日 上午 06:39R Go 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     已答覆

    Unfortunately for V1, we have not automatic way of animating a GIF. This is something we are looking at fixing for the next version.

    One workaround would be animate the different frames manually.

  • 2006年3月28日 下午 06:27Rahul Patil [MSFT] 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     已答覆

    Another really simple workaround is to use MediaElement, and set the source of the MediaElement to the gif file.

        <MediaElement Source="animated.gif"/>

     

    -Thanks

    Rahul Patil

所有回覆

  • 2006年3月28日 上午 06:39R Go 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     已答覆

    Unfortunately for V1, we have not automatic way of animating a GIF. This is something we are looking at fixing for the next version.

    One workaround would be animate the different frames manually.

  • 2006年3月28日 下午 04:54Derek Ju 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    Hm, ok.  Do you have any suggestions on how I can go about animating manually?
  • 2006年3月28日 下午 06:27Rahul Patil [MSFT] 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     已答覆

    Another really simple workaround is to use MediaElement, and set the source of the MediaElement to the gif file.

        <MediaElement Source="animated.gif"/>

     

    -Thanks

    Rahul Patil

  • 2006年3月29日 下午 10:09chongqing 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    Have anyone tried this?

    It seems mediaElement won't show animated gif either.

    this is my code.

    <MediaElement x:Name="loadingGif" Width="50" Height="100" Source="pack://siteoforigin:,,,/images/loading.gif" HorizontalAlignment="Center"></MediaElement>

    thanks/chong

  • 2006年3月29日 下午 10:51Dennis Cheng - MSFT 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    The MediaElement doesn't support the pack:// scheme yet. Try a relative or absolute URI such as http:// or file://. It downloads and plays the GIF just fine.

  • 2006年4月1日 上午 12:01Derek Ju 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    For some reason I still cannot get this to work :(.

    Here is all I am doing:

    <MediaElement Source="animation.gif">

    I have the animation.gif as an item in my project.  When I load up my Window however, I just see a blank space.  The link is correct because if I switch MediaElement with Image I see the first frame of my gif.

  • 2006年4月1日 上午 12:12Dennis Cheng - MSFT 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    That relative path is shorthand for "pack://application:,,,/animation.gif" which doesn't work. The best way to refer to media today is to use an absolute URI to a loose file outside of the project.
  • 2006年4月2日 上午 04:31csammis 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    I'm using a MediaElement to animate a GIF successfully, in this way:

    <MediaElement LoadedBehavior="Play" Source="file://C:/anim.gif" />

    However, when the GIF has transparency, the MediaElement shows black in the areas that should be transparent...ostensibly, the transparent areas of the GIF would show the underlying control.  How can I change this?

    Also, I don't really like the idea of using a MediaElement for the task of animating small GIFs, such as animating emoticons for use in an IM application.  I feel that it's way too heavy an object to create and destroy frequently.  Does anyone have details on the frame-by-frame animation method?

  • 2006年4月2日 下午 05:09Jared Bienz 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    This article shows you how to enumerate through each frame in the animated gif file and obtain them as System.Drawing.Bitmap instances:

    http://www.eggheadcafe.com/articles/stripimagefromanimatedgif.asp

    This thread shows how to convert a System.Drawing.Bitmap into a BitmapSource, which can be displayed in the WPF Image control:

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=320846&SiteID=1

    I would think you could leverage this to create a user control based on the WPF Image control and a timer. The only thing I'm not sure of is how to determine how long you should pause between each frame. That information is of course stored in the gif file, but I'm not sure if you can obtain it through .Net.

    Unfortunately, I don't really have an idea how slow this would be. I'd venture to guess that the conversion of a Drawing.Bitmap to BitmapSource is a fairly costly process. You would probably want to convert all frames of the gif to BitmapSources as you load the gif file, and then cache them so you don't have to convert on each frame draw.

    Hope that helps...

    Jared

  • 2006年10月23日 上午 10:50d00d 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    Has the support for animated GIFs using Image been provided in the latest versions of WPF?
  • 2006年11月28日 下午 09:07NewYoda 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    I'd also like to use animated GIFs.
    I tried:
    <Grid>
            <MediaElement Source="D:\Animation.gif" />
    </Grid>
    However, my Window is blank. I also tried to use Width and Height properties, but that didn't solve my problem.
  • 2006年11月30日 下午 05:17Robert A. WlodarczykMSFT, 版主使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    Image element does not support Animated GIFs in this version. Some people have had luck using the MediaElement for Animated GIFs, but no guarantee is made about this solution.
  • 2007年3月26日 下午 09:31Rob Reiss 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    As a learning project I created a WPF control to display animated GIF files.  The "ImageAnim" control mimics most of the behavior of Microsoft's WPF "Image" control with the additional benefit of handling animated GIF's.  You can download ImageAnim.dll from www.robreiss.com. (its free)

    Rob Reiss

  • 2008年5月12日 下午 12:21indrajit chavan 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    Hi All,

    For me giving file:// source to mediaelement is also not working.so i opted for http as follows


    Code Snippet
        <MediaElement Source="http://192.168.2.41/it/spinner_48.gif" x:Name="me" LoadedBehavior="Play" ToolTip="Loading..." Canvas.Top="50" UnloadedBehavior="Play" MediaFailed="me_MediaFailed"></MediaElement>
            <TextBlock x:Name="txtError"></TextBlock>

           

     

    but strange thing is it works in IE7 and fails in IE6. for IE6 it raises Mediafailed event and the exception is

    Code Snippet

    "media failed. system.windows.media.invalidwmpversionexception:Windows media player 10 or later is required--->system.runtime.interopservices.comexception(0x88989507).Exception from HRESULT(0x88989507)

    -------------------End of innerexception stack trace-------------------------"

     

     

    Above exception is caught in mediafailed event as follows:

     

    Code Snippet

    private void me_MediaFailed(object sender, ExceptionRoutedEventArgs e)
            {

                txtError.Text = "media failed " + e.ErrorException.ToString();
            }

     

     

    I agree that my client machine has windows media player 9 but how can need of WMP 10 be justified for a simple animated gif? How can i ask my client to take ie7 not ie6 and WMP 10 not 9 just for RICH UX web site(mostly containing animated gif) without video ?It really is going to embrace me

     

     

  • 2008年5月19日 下午 02:39olayaida 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     

    There is a better and easier way to animate a GIF. try using winforms PictureBox with the WindowsFormsHost element.
    The code will looks like

    <Window x:Class="Wing.TeleGYM.Client.Controls.StartupScreen"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wfi="clr-namespaceTongue Tiedystem.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
        xmlns:winForms="clr-namespaceTongue Tiedystem.Windows.Forms;assembly=System.Windows.Forms"
        Loaded="Window_Loaded" >

                <DockPanel ... >
                   
                    <wfi:WindowsFormsHost HorizontalAlignment="Center">
                        <winFormsStick out tongueictureBox x:Name="pictureBoxLoading" Width="320" Height="20" ></winFormsStick out tongueictureBox>
                    </wfi:WindowsFormsHost>
                </DockPanel >

    </Window >

    In the Window_Loaded function add the following line of code

    pictureBoxLoading.Image = Properties.Resources.StartUp_Loading; // From resources

    or

    pictureBoxLoading.Image = c:\loading.gif // from dis

    hope this will help
  • 2008年6月4日 上午 06:03Sergey Ukraine 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     提議的解答
    To solve the problem with playing animated GIFs I have created control derived from System.Windows.Controls.Image. This control uses System.Drawing.ImageAnimator class for animating GIF. The main functionality of class is the following:

    using System;
    using System.Drawing;
    using System.Windows;
    using System.Windows.Interop;
    using System.Windows.Threading;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using IpmPlayerLogWriter;

    public class GIFImageControl : System.Windows.Controls.Image
    {
        delegate void OnFrameChangedDelegate();  
        private Bitmap _Bitmap;

        public AnimatedImageControl(string path)
        {
                _Bitmap = (Bitmap)Bitmap.FromFile(path);
                ImageAnimator.Animate(_Bitmap, new EventHandler(OnFrameChanged));
        }


        private void OnFrameChanged(object sender, EventArgs e)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                new OnFrameChangedDelegate(OnFrameChangedInMainThread));
        }

        private void OnFrameChangedInMainThread()
        {
            ImageAnimator.UpdateFrames(_Bitmap);
            this.Source = this.GetBitmapSource(_Bitmap);
            InvalidateVisual();
        }

        private BitmapSource GetBitmapSource(Bitmap gdiBitmap)
        {
            return Imaging.CreateBitmapSourceFromHBitmap(
                gdiBitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
    }

    Hope that it helps :)
  • 2008年6月4日 上午 07:18Sergey Ukraine 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     提議的解答
    I have found one problem in the code I have posted above. Method GetBitmapSource gives memory leak and then GDI crashes. It is better be changed that way:

        [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
        public static extern IntPtr DeleteObject(IntPtr hDc);

        private BitmapSource GetBitmapSource(Bitmap gdiBitmap)
        {
                IntPtr hBitmap = gdiBitmap.GetHbitmap();
                bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(hBitmap,
                                                                     IntPtr.Zero,
                                                                     Int32Rect.Empty,
                                                                     BitmapSizeOptions.FromEmptyOptions());
                DeleteObject(hBitmap);
        }


  • 2009年3月20日 下午 10:06Greg Wilson 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    This thread is great.  I used Sergey Ukraine's info here and made a downloadable control that will display animated .gif from either the filesystem, or from an embedded resource in the assembly.  Additionally, I added the functionality to Play/Pause the animation by clicking on the .gif.  (On by default, but can be turned off with AllowClickToPause to false.)

    I posted the code on my blog, where the whole downloadable project can be downloaded.


    The Pragmatic TSQL Programmer
  • 2009年7月17日 下午 02:02jesus romero 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     提議的解答

    Hi

    I had the same problem, so I created a new control, deriving it from the Image class, and applying an animation to the image with a dependency property called FrameIndex. I guess that the frame rate is 10 frames per second.

    This control works well when you are adding the control manually to a container. Some modifications are be required to use it from XAML (using a parameterless constructor).

    The control accepts any URI (I tried with packed URIs) in the constructor.

    class GifImage : Image {

        public int FrameIndex {
            get { return (int)GetValue(FrameIndexProperty); }
            set { SetValue(FrameIndexProperty, value); }
        }

        public static readonly DependencyProperty FrameIndexProperty =
            DependencyProperty.Register("FrameIndex", typeof(int), typeof(GifImage), new UIPropertyMetadata(0, new PropertyChangedCallback(ChangingFrameIndex)));

        static void ChangingFrameIndex(DependencyObject obj, DependencyPropertyChangedEventArgs ev) {
            GifImage ob = obj as GifImage;
            ob.Source = ob.gf.Frames[(int)ev.NewValue];
            ob.InvalidateVisual();
        }
        GifBitmapDecoder gf;
        Int32Animation anim ;           
        public GifImage(Uri uri) {
            gf = new GifBitmapDecoder(uri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
            anim = new Int32Animation(0, gf.Frames.Count - 1, new Duration(new TimeSpan(0,0, 0,gf.Frames.Count/10,(int)((gf.Frames.Count/10.0-gf.Frames.Count/10)*1000))));
            anim.RepeatBehavior = RepeatBehavior.Forever;
            Source = gf.Frames[0];
        }
        bool animationIsWorking = false;
        protected override void OnRender(DrawingContext dc) {
            base.OnRender(dc);
            if (!animationIsWorking) {
                BeginAnimation(FrameIndexProperty, anim);
                animationIsWorking = true;
            }
        }
    }

    • 已提議為解答ptkdb 2009年8月20日 下午 02:05
    •  
  • 2009年8月20日 下午 01:59ptkdb 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    Works nicely...   Thanks for this. 

       Had some very marginal success using a MediaElement but the playback was horrid and drilling through the myriad of properties, clocks, storyboards, triggers, speedratios, repeatbehavior was getting more and more frustrating just to animate a 16x16 icon.

      I think this is about as straightforward as is possible for a simple animation in WPF. 

    Only tweek I had to make was to apply "Stretch=Stretch.None" to keep the image at its original size when I used it as content in a button.

    • 已編輯ptkdb 2009年8月20日 下午 02:05felt it needed embellishment
    •  
  • 2009年9月9日 下午 01:03jlspublic 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     包含代碼
    Jesus,

    I like your approach since it doesn't require the image format to be retranslated from an HBitmap for every frame display the way Sergey and Greg's did.  I implemented a variation that can be used from XAML and that hides a little more of the implementation from the caller (by not having an exposed FrameIndex property).  I no habla C# so my version is in VB:

    Imports System.Drawing
    Imports System.Threading
    Imports Image = System.Windows.Controls.Image
    
    Public Class AnimatedGIFViewer
        Inherits Image
    
        Private _GIFDecoder As GifBitmapDecoder
        Private _FrameTimer As Timer
        Private _ShowingFrame As Boolean = False
        Private _FrameIndex As Integer
    
        Public Property GIFSource() As Uri
            Get
                Return DirectCast(GetValue(GIFSourceProperty), Uri)
            End Get
    
            Set(ByVal value As Uri)
                SetValue(GIFSourceProperty, value)
            End Set
        End Property
    
        Public Shared ReadOnly GIFSourceProperty As DependencyProperty = _
            DependencyProperty.Register( _
                "GIFSource" _
                , GetType(Uri) _
                , GetType(AnimatedGIFViewer) _
                , New FrameworkPropertyMetadata(Nothing, AddressOf GIFSource_Changed) _
            )
    
        Private Shared Sub GIFSource_Changed(ByVal sender As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
            DirectCast(sender, AnimatedGIFViewer).GIFSourceSet()
        End Sub
    
        Private Sub GIFSourceSet()
            KillCurrentTimer()
    
            If IsNothing(GIFSource) Then
                _GIFDecoder = Nothing
            Else
                _GIFDecoder = New GifBitmapDecoder(GIFSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default)
                _FrameIndex = 0
                _FrameTimer = New Timer(AddressOf ShowFrame, Nothing, 200, 200)
            End If
        End Sub
    
        Private Sub ShowFrame(ByVal State As Object)
    
            'Avoid getting flooded 
            'with event calls since
            'the timer doesn't pay
            'any attention to whether
            'we are keeping up or not.
            If _ShowingFrame Then
                Exit Sub
            End If
    
            _ShowingFrame = True
            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, New Action(AddressOf OnFrameChanged))
            _ShowingFrame = False
        End Sub
    
        Private Sub OnFrameChanged()
            Source = _GIFDecoder.Frames(_FrameIndex)
            _FrameIndex += 1
    
            If (_FrameIndex = _GIFDecoder.Frames.Count) Then
                _FrameIndex = 0
            End If
    
        End Sub
    
        Private Sub KillCurrentTimer()
    
            If (Not IsNothing(_FrameTimer)) Then
                Dim FrameTimerDisposed As New AutoResetEvent(False)
                _FrameTimer.Dispose(FrameTimerDisposed)
                'In order to ensure that we don't have
                'two timers going at once, we will wait
                'for the dispose to complete but only 
                'for up to 1 second.
                FrameTimerDisposed.WaitOne(1000)
                _ShowingFrame = False
                _FrameTimer = Nothing
            End If
    
        End Sub
    
        Private Sub AnimatedGIFViewer_Unloaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Unloaded
            KillCurrentTimer()
        End Sub
    
    End Class
    
    

    You can use it XAML as follows:

            <local:AnimatedGIFViewer 
                Height="130" 
                Width="156" 
                x:Name="Image1" 
                Stretch="None" 
    GIFSource="pack://application:,,,/MyProject;component/MyGif.gif"
             />
    
    


    -JLS
  • 2009年9月21日 下午 03:44msp.netdev 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    Thanks, this solution works fine, but how is possible that microsoft don't fix mediaElement control problem !?
  • 2009年10月13日 下午 04:06Giuseppe Ugo 使用者勳章使用者勳章使用者勳章使用者勳章使用者勳章
     
    I would really hope Microsoft supports animated GIF directly in Image