Use my home-made GIF and APNG animator. It's really save CPU compared to previous one!

This commit is contained in:
Paddy Xu
2017-07-31 00:14:21 +03:00
parent 071a3b4f22
commit 2f12127cc9
12 changed files with 658 additions and 33 deletions

View File

@@ -0,0 +1,108 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using LibAPNG;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{
internal class APNGAnimationProvider : IAnimationProvider
{
public void GetAnimator(ObjectAnimationUsingKeyFrames animator, string path)
{
var decoder = new APNGBitmap(path);
if (decoder.IsSimplePNG)
{
animator.KeyFrames.Add(
new DiscreteObjectKeyFrame(decoder.DefaultImage.GetBitmapSource(), TimeSpan.Zero));
animator.Duration = Duration.Forever;
return;
}
var clock = TimeSpan.Zero;
var header = decoder.IHDRChunk;
Frame prevFrame = null;
BitmapSource prevRenderedFrame = null;
foreach (var rawFrame in decoder.Frames)
{
var frame = MakeFrame(header, rawFrame, prevFrame, prevRenderedFrame);
prevFrame = rawFrame;
prevRenderedFrame = frame;
var delay = TimeSpan.FromSeconds(
(double) rawFrame.fcTLChunk.DelayNum /
(rawFrame.fcTLChunk.DelayDen == 0 ? 100 : rawFrame.fcTLChunk.DelayDen));
animator.KeyFrames.Add(new DiscreteObjectKeyFrame(frame, clock));
clock += delay;
}
animator.Duration = clock;
animator.RepeatBehavior = RepeatBehavior.Forever;
}
private static BitmapSource MakeFrame(IHDRChunk header, Frame rawFrame, Frame previousFrame,
BitmapSource previousRenderedFrame)
{
var visual = new DrawingVisual();
using (var context = visual.RenderOpen())
{
switch (rawFrame.fcTLChunk.DisposeOp)
{
case DisposeOps.APNGDisposeOpNone:
// restore previousRenderedFrame
//if (previousRenderedFrame != null)
//{
// var fullRect = new Rect(0, 0, header.Width, header.Height);
// context.DrawImage(previousRenderedFrame, fullRect);
//}
break;
case DisposeOps.APNGDisposeOpPrevious:
// restore previousFrame
if (previousFrame != null)
{
var pFrameRect = new Rect(previousFrame.fcTLChunk.XOffset,
previousFrame.fcTLChunk.YOffset,
previousFrame.fcTLChunk.Width, previousFrame.fcTLChunk.Height);
context.DrawImage(previousFrame.GetBitmapSource(), pFrameRect);
}
break;
case DisposeOps.APNGDisposeOpBackground:
// do nothing
break;
}
// draw current frame
var frameRect = new Rect(rawFrame.fcTLChunk.XOffset, rawFrame.fcTLChunk.YOffset,
rawFrame.fcTLChunk.Width, rawFrame.fcTLChunk.Height);
context.DrawImage(rawFrame.GetBitmapSource(), frameRect);
}
var bitmap = new RenderTargetBitmap(
header.Width, header.Height,
96, 96,
PixelFormats.Pbgra32);
bitmap.Render(visual);
return bitmap;
}
}
}

View File

@@ -0,0 +1,76 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{
public class AnimatedImage : Image, IDisposable
{
public static readonly DependencyProperty AnimationUriProperty =
DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage),
new UIPropertyMetadata(null, LoadImage));
private readonly ObjectAnimationUsingKeyFrames _animator = new ObjectAnimationUsingKeyFrames();
public Uri AnimationUri
{
get => (Uri) GetValue(AnimationUriProperty);
set => SetValue(AnimationUriProperty, value);
}
public void Dispose()
{
BeginAnimation(SourceProperty, null);
Source = null;
_animator.KeyFrames.Clear();
}
private static void LoadImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
var instance = obj as AnimatedImage;
if (instance == null)
return;
var path = ((Uri) ev.NewValue).LocalPath;
var ext = Path.GetExtension(path).ToLower();
IAnimationProvider provider;
switch (ext)
{
case ".gif":
provider = new GIFAnimationProvider();
break;
case ".png":
provider = new APNGAnimationProvider();
break;
default:
provider = new ImageMagickProvider();
break;
}
provider.GetAnimator(instance._animator, path);
instance.BeginAnimation(SourceProperty, instance._animator);
}
}
}

View File

@@ -0,0 +1,182 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{
internal class GIFAnimationProvider : IAnimationProvider
{
public void GetAnimator(ObjectAnimationUsingKeyFrames animator, string path)
{
var decoder =
new GifBitmapDecoder(new Uri(path), BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.Default);
var clock = TimeSpan.Zero;
BitmapSource prevFrame = null;
FrameInfo prevInfo = null;
foreach (var rawFrame in decoder.Frames)
{
var info = GetFrameInfo(rawFrame);
var frame = MakeFrame(
decoder.Frames[0],
rawFrame, info,
prevFrame, prevInfo);
prevFrame = frame;
prevInfo = info;
animator.KeyFrames.Add(new DiscreteObjectKeyFrame(frame, clock));
clock += info.Delay;
}
animator.Duration = clock;
animator.RepeatBehavior = RepeatBehavior.Forever;
}
#region private methods
private static BitmapSource MakeFrame(
BitmapSource fullImage,
BitmapSource rawFrame, FrameInfo frameInfo,
BitmapSource previousFrame, FrameInfo previousFrameInfo)
{
var visual = new DrawingVisual();
using (var context = visual.RenderOpen())
{
if (previousFrameInfo != null && previousFrame != null &&
previousFrameInfo.DisposalMethod == FrameDisposalMethod.Combine)
{
var fullRect = new Rect(0, 0, fullImage.PixelWidth, fullImage.PixelHeight);
context.DrawImage(previousFrame, fullRect);
}
context.DrawImage(rawFrame, frameInfo.Rect);
}
var bitmap = new RenderTargetBitmap(
fullImage.PixelWidth, fullImage.PixelHeight,
fullImage.DpiX, fullImage.DpiY,
PixelFormats.Pbgra32);
bitmap.Render(visual);
return bitmap;
}
private static FrameInfo GetFrameInfo(BitmapFrame frame)
{
var frameInfo = new FrameInfo
{
Delay = TimeSpan.FromMilliseconds(100),
DisposalMethod = FrameDisposalMethod.Replace,
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<ushort>(delayQuery);
if (delay.HasValue)
frameInfo.Delay = TimeSpan.FromMilliseconds(10 * delay.Value);
var disposal = metadata.GetQueryOrNull<byte>(disposalQuery);
if (disposal.HasValue)
frameInfo.DisposalMethod = (FrameDisposalMethod) disposal.Value;
var width = metadata.GetQueryOrNull<ushort>(widthQuery);
if (width.HasValue)
frameInfo.Width = width.Value;
var height = metadata.GetQueryOrNull<ushort>(heightQuery);
if (height.HasValue)
frameInfo.Height = height.Value;
var left = metadata.GetQueryOrNull<ushort>(leftQuery);
if (left.HasValue)
frameInfo.Left = left.Value;
var top = metadata.GetQueryOrNull<ushort>(topQuery);
if (top.HasValue)
frameInfo.Top = top.Value;
}
}
catch (NotSupportedException)
{
}
return frameInfo;
}
#endregion
#region structs
private class FrameInfo
{
public TimeSpan Delay { get; set; }
public FrameDisposalMethod DisposalMethod { get; set; }
public double Width { private get; set; }
public double Height { private get; set; }
public double Left { private get; set; }
public double Top { private get; set; }
public Rect Rect => new Rect(Left, Top, Width, Height);
}
private enum FrameDisposalMethod
{
Replace = 0,
Combine = 1,
RestoreBackground = 2,
RestorePrevious = 3
}
#endregion
}
#region extensions
public static class Extensions
{
public static T? GetQueryOrNull<T>(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;
}
}
#endregion
}

View File

@@ -0,0 +1,26 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System.Windows.Media.Animation;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{
internal interface IAnimationProvider
{
void GetAnimator(ObjectAnimationUsingKeyFrames animator, string path);
}
}

View File

@@ -0,0 +1,51 @@
// Copyright © 2017 Paddy Xu
//
// This file is part of QuickLook program.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Media.Animation;
using ImageMagick;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{
internal class ImageMagickProvider : IAnimationProvider
{
public void GetAnimator(ObjectAnimationUsingKeyFrames animator, string path)
{
// set dcraw.exe for Magick.NET
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
using (var image = new MagickImage(path))
{
image.Rotate(image.Orientation == OrientationType.RightTop
? 90
: image.Orientation == OrientationType.BottomRight
? 180
: image.Orientation == OrientationType.LeftBotom
? 270
: 0);
animator.KeyFrames.Add(new DiscreteObjectKeyFrame(image.ToBitmapSource(), TimeSpan.Zero));
animator.Duration = Duration.Forever;
}
Directory.SetCurrentDirectory(App.AppPath);
}
}
}

View File

@@ -4,14 +4,16 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:QuickLook.Plugin.ImageViewer" xmlns:local="clr-namespace:QuickLook.Plugin.ImageViewer"
xmlns:animatedImage="clr-namespace:QuickLook.Plugin.ImageViewer.AnimatedImage"
mc:Ignorable="d" mc:Ignorable="d"
x:Name="imagePanel" x:Name="imagePanel"
d:DesignHeight="300" d:DesignWidth="300"> d:DesignHeight="300" d:DesignWidth="300">
<Grid> <Grid>
<ScrollViewer x:Name="viewPanel" BorderThickness="0" HorizontalScrollBarVisibility="Auto" <ScrollViewer x:Name="viewPanel" BorderThickness="0" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto" Focusable="False" IsManipulationEnabled="True"> VerticalScrollBarVisibility="Auto" Focusable="False" IsManipulationEnabled="True">
<Image x:Name="viewPanelImage" Stretch="None" Source="{Binding Source, ElementName=imagePanel}" <animatedImage:AnimatedImage x:Name="viewPanelImage" Stretch="None"
RenderOptions.BitmapScalingMode="{Binding RenderMode, ElementName=imagePanel}" /> RenderOptions.BitmapScalingMode="{Binding RenderMode, ElementName=imagePanel}"
AnimationUri="{Binding ImageUriSource, ElementName=imagePanel}" />
</ScrollViewer> </ScrollViewer>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -34,9 +34,10 @@ namespace QuickLook.Plugin.ImageViewer
/// <summary> /// <summary>
/// Interaction logic for ImagePanel.xaml /// Interaction logic for ImagePanel.xaml
/// </summary> /// </summary>
public partial class ImagePanel : UserControl, INotifyPropertyChanged public partial class ImagePanel : UserControl, INotifyPropertyChanged, IDisposable
{ {
private Point? _dragInitPos; private Point? _dragInitPos;
private Uri _imageSource;
private DateTime _lastZoomTime = DateTime.MinValue; private DateTime _lastZoomTime = DateTime.MinValue;
private double _maxZoomFactor = 3d; private double _maxZoomFactor = 3d;
private double _minZoomFactor = 0.1d; private double _minZoomFactor = 0.1d;
@@ -111,6 +112,16 @@ namespace QuickLook.Plugin.ImageViewer
} }
} }
public Uri ImageUriSource
{
get => _imageSource;
set
{
_imageSource = value;
OnPropertyChanged();
}
}
public BitmapSource Source public BitmapSource Source
{ {
get => _source; get => _source;
@@ -118,9 +129,18 @@ namespace QuickLook.Plugin.ImageViewer
{ {
_source = value; _source = value;
OnPropertyChanged(); OnPropertyChanged();
if (ImageUriSource == null)
viewPanelImage.Source = _source;
} }
} }
public void Dispose()
{
viewPanelImage?.Dispose();
viewPanelImage = null;
}
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<int> ImageScrolled; public event EventHandler<int> ImageScrolled;

View File

@@ -0,0 +1,176 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>LibAPNG</name>
</assembly>
<members>
<member name="P:LibAPNG.fcTLChunk.SequenceNumber">
<summary>
Sequence number of the animation chunk, starting from 0
</summary>
</member>
<member name="P:LibAPNG.fcTLChunk.Width">
<summary>
Width of the following frame
</summary>
</member>
<member name="P:LibAPNG.fcTLChunk.Height">
<summary>
Height of the following frame
</summary>
</member>
<member name="P:LibAPNG.fcTLChunk.XOffset">
<summary>
X position at which to render the following frame
</summary>
</member>
<member name="P:LibAPNG.fcTLChunk.YOffset">
<summary>
Y position at which to render the following frame
</summary>
</member>
<member name="P:LibAPNG.fcTLChunk.DelayNum">
<summary>
Frame delay fraction numerator
</summary>
</member>
<member name="P:LibAPNG.fcTLChunk.DelayDen">
<summary>
Frame delay fraction denominator
</summary>
</member>
<member name="P:LibAPNG.fcTLChunk.DisposeOp">
<summary>
Type of frame area disposal to be done after rendering this frame
</summary>
</member>
<member name="P:LibAPNG.fcTLChunk.BlendOp">
<summary>
Type of frame area rendering for this frame
</summary>
</member>
<member name="P:LibAPNG.APNGBitmap.IsSimplePNG">
<summary>
Indicate whether the file is a simple PNG.
</summary>
</member>
<member name="P:LibAPNG.APNGBitmap.DefaultImageIsAnimated">
<summary>
Indicate whether the default image is part of the animation
</summary>
</member>
<member name="P:LibAPNG.APNGBitmap.DefaultImage">
<summary>
Gets the base image.
If IsSimplePNG = True, returns the only image;
if False, returns the default image
</summary>
</member>
<member name="P:LibAPNG.APNGBitmap.Frames">
<summary>
Gets the frame array.
If IsSimplePNG = True, returns empty
</summary>
</member>
<member name="P:LibAPNG.APNGBitmap.IHDRChunk">
<summary>
Gets the IHDR Chunk
</summary>
</member>
<member name="P:LibAPNG.APNGBitmap.acTLChunk">
<summary>
Gets the acTL Chunk
</summary>
</member>
<member name="P:LibAPNG.Chunk.RawData">
<summary>
Get raw data of the chunk
</summary>
</member>
<member name="M:LibAPNG.Chunk.ModifyChunkData(System.Int32,System.Byte[])">
<summary>
Modify the ChunkData part.
</summary>
</member>
<member name="M:LibAPNG.Chunk.ModifyChunkData(System.Int32,System.UInt32)">
<summary>
Modify the ChunkData part.
</summary>
</member>
<member name="M:LibAPNG.Helper.ConvertEndian(System.Byte[])">
<summary>
Convert big-endian to little-endian or reserve
</summary>
</member>
<member name="M:LibAPNG.Helper.ConvertEndian(System.Int32)">
<summary>
Convert big-endian to little-endian or reserve
</summary>
</member>
<member name="M:LibAPNG.Helper.ConvertEndian(System.UInt32)">
<summary>
Convert big-endian to little-endian or reserve
</summary>
</member>
<member name="M:LibAPNG.Helper.ConvertEndian(System.Int16)">
<summary>
Convert big-endian to little-endian or reserve
</summary>
</member>
<member name="M:LibAPNG.Helper.ConvertEndian(System.UInt16)">
<summary>
Convert big-endian to little-endian or reserve
</summary>
</member>
<member name="M:LibAPNG.Helper.IsBytesEqual(System.Byte[],System.Byte[])">
<summary>
Compare two byte array
</summary>
</member>
<member name="T:LibAPNG.Frame">
<summary>
Describe a single frame.
</summary>
</member>
<member name="P:LibAPNG.Frame.IHDRChunk">
<summary>
Gets or Sets the acTL chunk
</summary>
</member>
<member name="P:LibAPNG.Frame.fcTLChunk">
<summary>
Gets or Sets the fcTL chunk
</summary>
</member>
<member name="P:LibAPNG.Frame.IENDChunk">
<summary>
Gets or Sets the IEND chunk
</summary>
</member>
<member name="P:LibAPNG.Frame.OtherChunks">
<summary>
Gets or Sets the other chunks
</summary>
</member>
<member name="P:LibAPNG.Frame.IDATChunks">
<summary>
Gets or Sets the IDAT chunks
</summary>
</member>
<member name="M:LibAPNG.Frame.AddOtherChunk(LibAPNG.OtherChunk)">
<summary>
Add an Chunk to end end of existing list.
</summary>
</member>
<member name="M:LibAPNG.Frame.AddIDATChunk(LibAPNG.IDATChunk)">
<summary>
Add an IDAT Chunk to end end of existing list.
</summary>
</member>
<member name="M:LibAPNG.Frame.GetStream">
<summary>
Gets the frame as PNG FileStream.
</summary>
</member>
</members>
</doc>

View File

@@ -18,10 +18,8 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Windows; using System.Windows;
using ImageMagick; using ImageMagick;
using XamlAnimatedGif;
namespace QuickLook.Plugin.ImageViewer namespace QuickLook.Plugin.ImageViewer
{ {
@@ -35,7 +33,10 @@ namespace QuickLook.Plugin.ImageViewer
".orf", ".pef", ".ptx", ".pxn", ".r3d", ".raf", ".raw", ".rwl", ".rw2", ".rwz", ".sr2", ".srf", ".srw", ".orf", ".pef", ".ptx", ".pxn", ".r3d", ".raf", ".raw", ".rwl", ".rw2", ".rwz", ".sr2", ".srf", ".srw",
".tif", ".x3f", ".tif", ".x3f",
// normal // normal
".bmp", ".ggg", ".ico", ".icon", ".jpg", ".jpeg", ".png", ".psd", ".svg", ".wdp", ".tiff", ".tga", ".webp" ".bmp", ".ico", ".icon", ".jpg", ".jpeg", ".psd", ".svg", ".wdp", ".tif", ".tiff", ".tga",
".webp",
// animated
".png", ".apng", ".gif"
}; };
private Size _imageSize; private Size _imageSize;
private ImagePanel _ip; private ImagePanel _ip;
@@ -58,9 +59,6 @@ namespace QuickLook.Plugin.ImageViewer
public void Prepare(string path, ContextObject context) public void Prepare(string path, ContextObject context)
{ {
// set dcraw.exe for Magick.NET
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
_imageSize = ImageFileHelper.GetImageSize(path) ?? Size.Empty; _imageSize = ImageFileHelper.GetImageSize(path) ?? Size.Empty;
if (!_imageSize.IsEmpty) if (!_imageSize.IsEmpty)
@@ -73,9 +71,6 @@ namespace QuickLook.Plugin.ImageViewer
public void View(string path, ContextObject context) public void View(string path, ContextObject context)
{ {
// set dcraw.exe for Magick.NET
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
_ip = new ImagePanel(); _ip = new ImagePanel();
context.ViewerContent = _ip; context.ViewerContent = _ip;
@@ -86,8 +81,6 @@ namespace QuickLook.Plugin.ImageViewer
LoadImage(_ip, path); LoadImage(_ip, path);
context.IsBusy = false; context.IsBusy = false;
Directory.SetCurrentDirectory(App.AppPath);
} }
public void Cleanup() public void Cleanup()
@@ -97,21 +90,7 @@ namespace QuickLook.Plugin.ImageViewer
private void LoadImage(ImagePanel ui, string path) private void LoadImage(ImagePanel ui, string path)
{ {
if (Path.GetExtension(path).ToLower() == ".gif") ui.ImageUriSource = new Uri(path);
AnimationBehavior.SetSourceUri(ui.viewPanelImage, new Uri(path));
using (var image = new MagickImage(path))
{
image.Rotate(image.Orientation == OrientationType.RightTop
? 90
: image.Orientation == OrientationType.BottomRight
? 180
: image.Orientation == OrientationType.LeftBotom
? 270
: 0);
ui.Source = image.ToBitmapSource();
}
} }
} }
} }

View File

@@ -55,6 +55,9 @@
<Reference Include="ExifLib, Version=1.7.0.0, Culture=neutral, PublicKeyToken=30284005913968db, processorArchitecture=MSIL"> <Reference Include="ExifLib, Version=1.7.0.0, Culture=neutral, PublicKeyToken=30284005913968db, processorArchitecture=MSIL">
<HintPath>..\..\packages\ExifLib.1.7.0.0\lib\net45\ExifLib.dll</HintPath> <HintPath>..\..\packages\ExifLib.1.7.0.0\lib\net45\ExifLib.dll</HintPath>
</Reference> </Reference>
<Reference Include="LibAPNG">
<HintPath>.\LibAPNG.dll</HintPath>
</Reference>
<Reference Include="Magick.NET-Q8-AnyCPU, Version=7.0.0.0, Culture=neutral, PublicKeyToken=2004825badfa91ec, processorArchitecture=MSIL"> <Reference Include="Magick.NET-Q8-AnyCPU, Version=7.0.0.0, Culture=neutral, PublicKeyToken=2004825badfa91ec, processorArchitecture=MSIL">
<HintPath>..\..\packages\Magick.NET-Q8-AnyCPU.7.0.6.102\lib\net40\Magick.NET-Q8-AnyCPU.dll</HintPath> <HintPath>..\..\packages\Magick.NET-Q8-AnyCPU.7.0.6.102\lib\net40\Magick.NET-Q8-AnyCPU.dll</HintPath>
</Reference> </Reference>
@@ -65,14 +68,16 @@
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Xaml" /> <Reference Include="System.Xaml" />
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
<Reference Include="XamlAnimatedGif, Version=1.1.10.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XamlAnimatedGif.1.1.10\lib\net45\XamlAnimatedGif.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\..\GitVersion.cs"> <Compile Include="..\..\GitVersion.cs">
<Link>Properties\GitVersion.cs</Link> <Link>Properties\GitVersion.cs</Link>
</Compile> </Compile>
<Compile Include="AnimatedImage\AnimatedImage.cs" />
<Compile Include="AnimatedImage\APNGAnimationProvider.cs" />
<Compile Include="AnimatedImage\GIFAnimationProvider.cs" />
<Compile Include="AnimatedImage\IAnimationProvider.cs" />
<Compile Include="AnimatedImage\ImageMagickProvider.cs" />
<Compile Include="ImageFileHelper.cs" /> <Compile Include="ImageFileHelper.cs" />
<Compile Include="ImagePanel.xaml.cs"> <Compile Include="ImagePanel.xaml.cs">
<DependentUpon>ImagePanel.xaml</DependentUpon> <DependentUpon>ImagePanel.xaml</DependentUpon>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="ExifLib" version="1.7.0.0" targetFramework="net462" /> <package id="ExifLib" version="1.7.0.0" targetFramework="net462" />
<package id="Magick.NET-Q8-AnyCPU" version="7.0.6.102" targetFramework="net462" /> <package id="Magick.NET-Q8-AnyCPU" version="7.0.6.102" targetFramework="net462" />
<package id="XamlAnimatedGif" version="1.1.10" targetFramework="net462" />
</packages> </packages>