diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/AnimatedImage.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/AnimatedImage.cs
index 1a14bdc..8a107ed 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/AnimatedImage.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/AnimatedImage.cs
@@ -1,4 +1,4 @@
-// Copyright © 2017 Paddy Xu
+// Copyright © 2018 Paddy Xu
//
// This file is part of QuickLook program.
//
@@ -17,12 +17,9 @@
using System;
using System.IO;
-using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Media;
using System.Windows.Threading;
-using QuickLook.Common.Helpers;
using QuickLook.Plugin.ImageViewer.Exiv2;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
@@ -30,17 +27,14 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
public class AnimatedImage : Image, IDisposable
{
private AnimationProvider _animation;
- private bool _disposed;
public void Dispose()
{
BeginAnimation(AnimationFrameIndexProperty, null);
Source = null;
+
+ _animation?.Dispose();
_animation = null;
-
- _disposed = true;
-
- Task.Delay(500).ContinueWith(t => ProcessHelper.PerformAggressiveGC());
}
private static void LoadFullImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
@@ -48,11 +42,11 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
if (!(obj is AnimatedImage instance))
return;
- instance._animation = LoadFullImageCore((Uri) ev.NewValue);
+ instance._animation = LoadFullImageCore((Uri) ev.NewValue, instance.Dispatcher);
instance.BeginAnimation(AnimationFrameIndexProperty, instance._animation.Animator);
}
- private static AnimationProvider LoadFullImageCore(Uri path)
+ private static AnimationProvider LoadFullImageCore(Uri path, Dispatcher uiDispatcher)
{
byte[] sign;
using (var reader =
@@ -64,7 +58,7 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
AnimationProvider provider = null;
if (sign[0] == 'G' && sign[1] == 'I' && sign[2] == 'F' && sign[3] == '8')
- provider = new GIFAnimationProvider(path.LocalPath);
+ provider = new GifAnimationProvider(path.LocalPath, uiDispatcher);
//else if (sign[0] == 0x89 && sign[1] == 'P' && sign[2] == 'N' && sign[3] == 'G')
// provider = new APNGAnimationProvider();
//else
@@ -122,13 +116,9 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
if (!(obj is AnimatedImage instance))
return;
- new Task(() =>
- {
- var image = instance._animation.GetRenderedFrame((int) ev.NewValue);
-
- instance.Dispatcher.BeginInvoke(
- new Action(() => { instance.Source = image; }), DispatcherPriority.Loaded);
- }).Start();
+ var image = instance._animation.GetRenderedFrame((int) ev.NewValue);
+ //if (!ReferenceEquals(instance.Source, image))
+ instance.Source = image;
}
#endregion DependencyProperty
diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/AnimationProvider.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/AnimationProvider.cs
index 5b7514b..dee9104 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/AnimationProvider.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/AnimationProvider.cs
@@ -15,23 +15,29 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+using System;
using System.Windows.Media;
using System.Windows.Media.Animation;
-using System.Windows.Media.Imaging;
+using System.Windows.Threading;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{
- internal abstract class AnimationProvider
+ internal abstract class AnimationProvider : IDisposable
{
- public AnimationProvider(string path)
+ protected AnimationProvider(string path, Dispatcher uiDispatcher)
{
Path = path;
+ Dispatcher = uiDispatcher;
}
+ public Dispatcher Dispatcher { get; }
+
public string Path { get; }
public Int32Animation Animator { get; protected set; }
- public abstract DrawingImage GetRenderedFrame(int index);
+ public abstract void Dispose();
+
+ public abstract ImageSource GetRenderedFrame(int index);
}
}
\ No newline at end of file
diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/GIFAnimationProvider.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/GIFAnimationProvider.cs
index 3b10aa2..d54b90f 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/GIFAnimationProvider.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/AnimatedImage/GIFAnimationProvider.cs
@@ -1,4 +1,4 @@
-// Copyright © 2017 Paddy Xu
+// Copyright © 2018 Paddy Xu
//
// This file is part of QuickLook program.
//
@@ -16,187 +16,60 @@
// along with this program. If not, see .
using System;
-using System.Collections.Generic;
-using System.Linq;
+using System.Drawing;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
+using System.Windows.Threading;
using QuickLook.Common.ExtensionMethods;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{
- internal class GIFAnimationProvider : AnimationProvider
+ internal class GifAnimationProvider : AnimationProvider
{
- private readonly List _decodedFrames;
- private readonly int _lastRenderedFrameIndex;
- private readonly DrawingGroup renderedFrame;
+ private Bitmap _frame;
+ private BitmapSource _frameSource;
+ private bool _isPlaying;
- public GIFAnimationProvider(string path) : base(path)
+ public GifAnimationProvider(string path, Dispatcher uiDispatcher) : base(path, uiDispatcher)
{
- var decoder = new GifBitmapDecoder(new Uri(path), BitmapCreateOptions.PreservePixelFormat,
- BitmapCacheOption.OnLoad);
+ _frame = (Bitmap) Image.FromFile(path);
+ _frameSource = _frame.ToBitmapSource();
- _decodedFrames = new List(decoder.Frames.Count);
- decoder.Frames.ForEach(f => _decodedFrames.Add(GetFrameInfo(f)));
-
- renderedFrame = new DrawingGroup();
- _lastRenderedFrameIndex = -1;
-
- var delay = _decodedFrames[0].Delay.TotalMilliseconds;
-
- Animator = new Int32Animation(0, decoder.Frames.Count - 1,
- new Duration(TimeSpan.FromMilliseconds(delay * (decoder.Frames.Count - 1))))
+ Animator = new Int32Animation(0, 1, new Duration(TimeSpan.FromMilliseconds(50)))
{
RepeatBehavior = RepeatBehavior.Forever
};
}
- public override DrawingImage GetRenderedFrame(int index)
+ public override void Dispose()
{
- for (var i = _lastRenderedFrameIndex + 1; i < index; i++)
- MakeFrame(renderedFrame, _decodedFrames[i], i > 0 ? _decodedFrames[i - 1] : null);
+ if (_frame == null)
+ return;
- MakeFrame(
- renderedFrame,
- _decodedFrames[index],
- index > 0 ? _decodedFrames[index - 1] : null);
-
- var di=new DrawingImage(renderedFrame);
- di.Freeze();
+ ImageAnimator.StopAnimate(_frame, OnFrameChanged);
+ _frame.Dispose();
- return di;
+ _frame = null;
+ _frameSource = null;
}
- #region private methods
-
- private static void MakeFrame(
- DrawingGroup renderedFrame,
- FrameInfo currentFrame,
- FrameInfo previousFrame)
+ public override ImageSource GetRenderedFrame(int index)
{
- if (previousFrame == null)
- renderedFrame.Children.Clear();
- else
- switch (previousFrame.DisposalMethod)
- {
- case FrameDisposalMethod.Unspecified:
- case FrameDisposalMethod.Combine:
- break;
- case FrameDisposalMethod.RestorePrevious:
- renderedFrame.Children.RemoveAt(renderedFrame.Children.Count - 1);
- break;
- case FrameDisposalMethod.RestoreBackground:
- var bg = renderedFrame.Children.First();
- renderedFrame.Children.Clear();
- renderedFrame.Children.Add(bg);
- break;
- }
-
- renderedFrame.Children.Add(new ImageDrawing(currentFrame.Frame, currentFrame.Rect));
- }
-
- private static FrameInfo GetFrameInfo(BitmapFrame frame)
- {
- var frameInfo = new FrameInfo
- {
- Frame = frame,
- Delay = TimeSpan.FromMilliseconds(100),
- DisposalMethod = FrameDisposalMethod.Unspecified,
- Width = frame.PixelWidth,
- Height = frame.PixelHeight,
- Left = 0,
- Top = 0
- };
-
- try
- {
- if (frame.Metadata is BitmapMetadata metadata)
- {
- const string delayQuery = "/grctlext/Delay";
- const string disposalQuery = "/grctlext/Disposal";
- const string widthQuery = "/imgdesc/Width";
- const string heightQuery = "/imgdesc/Height";
- const string leftQuery = "/imgdesc/Left";
- const string topQuery = "/imgdesc/Top";
-
- var delay = metadata.GetQueryOrNull(delayQuery);
- if (delay.HasValue)
- frameInfo.Delay = TimeSpan.FromMilliseconds(10 * delay.Value);
-
- var disposal = metadata.GetQueryOrNull(disposalQuery);
- if (disposal.HasValue)
- frameInfo.DisposalMethod = (FrameDisposalMethod) disposal.Value;
-
- var width = metadata.GetQueryOrNull(widthQuery);
- if (width.HasValue)
- frameInfo.Width = width.Value;
-
- var height = metadata.GetQueryOrNull(heightQuery);
- if (height.HasValue)
- frameInfo.Height = height.Value;
-
- var left = metadata.GetQueryOrNull(leftQuery);
- if (left.HasValue)
- frameInfo.Left = left.Value;
-
- var top = metadata.GetQueryOrNull(topQuery);
- if (top.HasValue)
- frameInfo.Top = top.Value;
- }
- }
- catch (NotSupportedException)
+ if (!_isPlaying)
{
+ _isPlaying = true;
+ ImageAnimator.Animate(_frame, OnFrameChanged);
}
- return frameInfo;
+ return _frameSource;
}
- #endregion
-
- #region structs
-
- private class FrameInfo
+ private void OnFrameChanged(object sender, EventArgs e)
{
- public BitmapSource Frame { get; set; }
- public FrameDisposalMethod DisposalMethod { get; set; }
- public TimeSpan Delay { get; set; }
- public Rect Rect => new Rect(Left, Top, Width, Height);
-
- public double Width { private get; set; }
- public double Height { private get; set; }
- public double Left { private get; set; }
- public double Top { private get; set; }
- }
-
- private enum FrameDisposalMethod
- {
- Unspecified = 0,
- Combine = 1,
- RestoreBackground = 2,
- RestorePrevious = 3
- }
-
- #endregion
- }
-
- #region extensions
-
- public static class Extensions
- {
- public static T? GetQueryOrNull(this BitmapMetadata metadata, string query)
- where T : struct
- {
- if (metadata.ContainsQuery(query))
- {
- var value = metadata.GetQuery(query);
- if (value != null)
- return (T) value;
- }
-
- return null;
+ ImageAnimator.UpdateFrames();
+ _frameSource = _frame.ToBitmapSource();
}
}
-
- #endregion
}
\ No newline at end of file
diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml.cs
index 34bc7fd..9ce7fed 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/ImagePanel.xaml.cs
@@ -1,4 +1,4 @@
-// Copyright © 2017 Paddy Xu
+// Copyright © 2018 Paddy Xu
//
// This file is part of QuickLook program.
//
diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Plugin.cs
index 10b324b..434a3a5 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Plugin.cs
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Plugin.cs
@@ -1,4 +1,4 @@
-// Copyright © 2017 Paddy Xu
+// Copyright © 2018 Paddy Xu
//
// This file is part of QuickLook program.
//
@@ -84,6 +84,7 @@ namespace QuickLook.Plugin.ImageViewer
public void Cleanup()
{
+ _ip?.Dispose();
_ip = null;
}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/QuickLook.Plugin.ImageViewer.csproj b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/QuickLook.Plugin.ImageViewer.csproj
index 2f34f70..eccba99 100644
--- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/QuickLook.Plugin.ImageViewer.csproj
+++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/QuickLook.Plugin.ImageViewer.csproj
@@ -79,7 +79,7 @@
-
+
diff --git a/QuickLook.sln.DotSettings b/QuickLook.sln.DotSettings
index 385a2aa..734638b 100644
--- a/QuickLook.sln.DotSettings
+++ b/QuickLook.sln.DotSettings
@@ -19,7 +19,7 @@
0
NEVER
- Copyright © $CURRENT_YEAR$ $USER_NAME$
+ Copyright © $CURRENT_YEAR$ Paddy Xu
This file is part of $SOLUTION$ program.