Skip to content

Instantly share code, notes, and snippets.

@mntone
Last active December 20, 2015 14:48
Show Gist options
  • Save mntone/6149033 to your computer and use it in GitHub Desktop.
Save mntone/6149033 to your computer and use it in GitHub Desktop.
- GIF animation custom control for WPF: When BitmapImage load from Uri, this UI control can animate, however, when from Stream, this UI control "cannot" animate (BitmapImage load only 1 frame). - WPF のための GIF アニメーションカスタムコントロール: BitmapImage で、Uri から読み込んだとき、UI コントロールはアニメーションできます。しかし、Stream から読み込んだとき、アニメーションできません (何故ならば、BitmapImage は 1 フレームしか読み込まない…
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace Mntone.CustomControls
{
public class AnimatedImage: Image
{
public bool IsAnimationWorking { get; private set; }
private Int32Animation _animation = null;
private BitmapDecoder _decoder = null;
private BitmapMetadata _metadata = null;
private ushort _delay = 0;
private void ClearAnimation()
{
if( _animation != null )
BeginAnimation( FrameIndexProperty, null );
IsAnimationWorking = false;
_animation = null;
_decoder = null;
_metadata = null;
_delay = 0;
}
private void PrepareAnimation( BitmapImage bi )
{
if( _decoder.Frames.Count == 1)
{
base.Source = _decoder.Frames[0];
return;
}
_metadata = ( BitmapMetadata )_decoder.Frames[0].Metadata;
var od = _metadata.GetQuery( "/grctlext/Delay" );
_delay = ( ushort )od;
var ts = TimeSpan.FromMilliseconds( _decoder.Frames.Count * 10 * ( double )_delay );
_animation = new Int32Animation( 0, _decoder.Frames.Count - 1, new Duration( ts ), FillBehavior.Stop ) { RepeatBehavior = RepeatBehavior.Forever };
base.Source = _decoder.Frames[0];
BeginAnimation( FrameIndexProperty, _animation );
IsAnimationWorking = true;
}
private bool IsAnimatedGifImage( BitmapImage bi )
{
var flag = false;
if( bi.UriSource != null )
{
_decoder = BitmapDecoder.Create( bi.UriSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad );
flag = _decoder.GetType() == typeof( GifBitmapDecoder ) && _decoder.Frames.Count > 1;
}
else if( bi.StreamSource != null )
{
try
{
//bi.StreamSource.Position = 0;
_decoder = BitmapDecoder.Create( bi.StreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad );
flag = _decoder.GetType() == typeof( GifBitmapDecoder ) && _decoder.Frames.Count > 1;
}
catch
{
flag = false;
}
}
if( !flag && _decoder != null )
_decoder = null;
return flag;
}
protected virtual void OnChangingFrameIndex( DependencyPropertyChangedEventArgs args )
{
var idx = ( int )args.NewValue;
base.Source = _decoder.Frames[idx];
InvalidateVisual();
}
protected virtual void OnSourceChanged( DependencyPropertyChangedEventArgs args )
{
ClearAnimation();
var bi = args.NewValue as BitmapImage;
if( bi == null )
{
var source = args.NewValue as ImageSource;
base.Source = source;
return;
}
if( !IsAnimatedGifImage( bi ) )
{
base.Source = bi;
return;
}
PrepareAnimation( bi );
}
private static void ChangingFrameIndex( DependencyObject obj, DependencyPropertyChangedEventArgs args )
{
var ai = obj as AnimatedImage;
if( ai == null || !ai.IsAnimationWorking )
return;
ai.OnChangingFrameIndex( args );
}
private static void OnSourceChanged( DependencyObject obj, DependencyPropertyChangedEventArgs args )
{
var ai = obj as AnimatedImage;
if( ai == null )
return;
ai.OnSourceChanged( args );
}
#region 依存プロパティー
public uint FrameIndex
{
get { return ( uint )GetValue( FrameIndexProperty ); }
set { SetValue( FrameIndexProperty, value ); }
}
public static readonly DependencyProperty FrameIndexProperty
= DependencyProperty.Register( "FrameIndex", typeof( int ), typeof( AnimatedImage ), new UIPropertyMetadata( 0, ChangingFrameIndex ) );
public new ImageSource Source
{
get { return ( ImageSource )GetValue( SourceProperty ); }
set { SetValue( SourceProperty, value ); }
}
public static readonly new DependencyProperty SourceProperty
= DependencyProperty.Register(
"Source",
typeof( ImageSource ),
typeof( AnimatedImage ),
new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsMeasure, OnSourceChanged ) );
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment