working on new Gif viewer

This commit is contained in:
Paddy Xu
2018-06-13 18:43:33 +03:00
parent d4feb2c867
commit c13839cb19
11 changed files with 429 additions and 139 deletions

View File

@@ -0,0 +1,35 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
namespace QuickLook.Plugin.CameraRawViewer
{
internal class DCraw
{
private static readonly string DCrawPath =
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
Environment.Is64BitProcess ? "dcraw64.exe" : "dcraw32.exe");
public static string ConvertToTiff(string input)
{
var output = Path.GetTempFileName();
using (var p = new Process())
{
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = DCrawPath;
p.StartInfo.Arguments = $"-w -W -h -T -O \"{output}\" \"{input}\"";
p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
p.Start();
p.WaitForExit(10000);
}
return new FileInfo(output).Length > 0 ? output : string.Empty;
}
}
}

View File

@@ -0,0 +1,85 @@
// 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.Linq;
using QuickLook.Common.Plugin;
namespace QuickLook.Plugin.CameraRawViewer
{
public class Plugin : IViewer
{
private static readonly string[] Formats =
{
// camera raw
".ari", ".arw", ".bay", ".crw", ".cr2", ".cap", ".dcs", ".dcr", ".dng", ".drf", ".eip", ".erf", ".fff",
".iiq", ".k25", ".kdc", ".mdc", ".mef", ".mos", ".mrw", ".nef", ".nrw", ".obm", ".orf", ".pef", ".ptx",
".pxn", ".r3d", ".raf", ".raw", ".rwl", ".rw2", ".rwz", ".sr2", ".srf", ".srw", ".x3f"
};
private string _image = string.Empty;
private ImageViewer.Plugin _imageViewierPlugin;
public int Priority => -1;//int.MaxValue;
public void Init()
{
}
public bool CanHandle(string path)
{
return false;
return !Directory.Exists(path) && Formats.Any(path.ToLower().EndsWith);
}
public void Prepare(string path, ContextObject context)
{
_imageViewierPlugin=new ImageViewer.Plugin();
_imageViewierPlugin.Prepare(path, context);
}
public void View(string path, ContextObject context)
{
_image = DCraw.ConvertToTiff(path);
if (string.IsNullOrEmpty(_image))
throw new Exception("DCraw failed.");
_imageViewierPlugin.View(_image, context);
// correct title
context.Title = Path.GetFileName(path);
}
public void Cleanup()
{
_imageViewierPlugin.Cleanup();
_imageViewierPlugin = null;
try
{
File.Delete(_image);
}
catch (Exception)
{
// ignored
}
}
}
}

View File

@@ -0,0 +1,50 @@
// 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.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("QuickLook.Plugin.ImageViewer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("pooi.moe")]
[assembly: AssemblyProduct("QuickLook.Plugin.ImageViewer")]
[assembly: AssemblyCopyright("Copyright © Paddy Xu 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("fe5a5111-9607-4721-a7be-422754002ed8")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]

View File

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>QuickLook.Plugin.CameraRawViewer</RootNamespace>
<AssemblyName>QuickLook.Plugin.CameraRawViewer</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.CameraRawViewer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.CameraRawViewer\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.CameraRawViewer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<OutputPath>..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.CameraRawViewer\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>
</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\GitVersion.cs">
<Link>Properties\GitVersion.cs</Link>
</Compile>
<Compile Include="DCraw.cs" />
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\QuickLook.Common\QuickLook.Common.csproj">
<Project>{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}</Project>
<Name>QuickLook.Common</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\QuickLook.Plugin.ImageViewer\QuickLook.Plugin.ImageViewer.csproj">
<Project>{fe5a5111-9607-4721-a7be-422754002ed8}</Project>
<Name>QuickLook.Plugin.ImageViewer</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="dcraw32.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dcraw64.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -16,13 +16,11 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media.Animation; using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
using QuickLook.Common.Helpers; using QuickLook.Common.Helpers;
using QuickLook.Plugin.ImageViewer.Exiv2; using QuickLook.Plugin.ImageViewer.Exiv2;
@@ -31,15 +29,68 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{ {
public class AnimatedImage : Image, IDisposable public class AnimatedImage : Image, IDisposable
{ {
private AnimationProvider _animation;
private bool _disposed;
public void Dispose()
{
BeginAnimation(AnimationFrameIndexProperty, null);
Source = null;
_animation = null;
_disposed = true;
Task.Delay(500).ContinueWith(t => ProcessHelper.PerformAggressiveGC());
}
private static void LoadFullImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
if (!(obj is AnimatedImage instance))
return;
instance._animation = LoadFullImageCore((Uri) ev.NewValue);
instance.BeginAnimation(AnimationFrameIndexProperty, instance._animation.Animator);
}
private static AnimationProvider LoadFullImageCore(Uri path)
{
byte[] sign;
using (var reader =
new BinaryReader(new FileStream(path.LocalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
sign = reader.BaseStream.Length < 4 ? new byte[] {0, 0, 0, 0} : reader.ReadBytes(4);
}
AnimationProvider provider = null;
if (sign[0] == 'G' && sign[1] == 'I' && sign[2] == 'F' && sign[3] == '8')
provider = new GIFAnimationProvider(path.LocalPath);
//else if (sign[0] == 0x89 && sign[1] == 'P' && sign[2] == 'N' && sign[3] == 'G')
// provider = new APNGAnimationProvider();
//else
// provider = new ImageMagickProvider();
return provider;
}
#region DependencyProperty
public static readonly DependencyProperty AnimationFrameIndexProperty =
DependencyProperty.Register("AnimationFrameIndex", typeof(int), typeof(AnimatedImage),
new UIPropertyMetadata(-1, AnimationFrameIndexChanged));
public static readonly DependencyProperty AnimationUriProperty = public static readonly DependencyProperty AnimationUriProperty =
DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage), DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage),
new UIPropertyMetadata(null, LoadImage)); new UIPropertyMetadata(null, AnimationUriChanged));
public static readonly DependencyProperty MetaProperty = public static readonly DependencyProperty MetaProperty =
DependencyProperty.Register("Meta", typeof(Meta), typeof(AnimatedImage)); DependencyProperty.Register("Meta", typeof(Meta), typeof(AnimatedImage));
private ObjectAnimationUsingKeyFrames _animator = new ObjectAnimationUsingKeyFrames(); public int AnimationFrameIndex
private bool _disposed; {
get => (int) GetValue(AnimationFrameIndexProperty);
set => SetValue(AnimationFrameIndexProperty, value);
}
public Uri AnimationUri public Uri AnimationUri
{ {
@@ -53,90 +104,33 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
set => SetValue(MetaProperty, value); set => SetValue(MetaProperty, value);
} }
public void Dispose() private static void AnimationUriChanged(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{ {
BeginAnimation(SourceProperty, null); if (!(obj is AnimatedImage instance))
Source = null;
_animator.KeyFrames.Clear();
_disposed = true;
}
private static void LoadImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
var instance = obj as AnimatedImage;
if (instance == null)
return; return;
var thumbnail = instance.Meta?.GetThumbnail(true); //var thumbnail = instance.Meta?.GetThumbnail(true);
instance.Source = thumbnail; //instance.Source = thumbnail;
if (thumbnail != null) LoadFullImage(obj, ev);
LoadFullImageAsync(obj, ev);
else instance.AnimationFrameIndex = 0;
LoadFullImage(obj, ev);
} }
private static void LoadFullImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev) private static void AnimationFrameIndexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{ {
var instance = obj as AnimatedImage; if (!(obj is AnimatedImage instance))
if (instance == null)
return; return;
instance._animator = LoadFullImageCore((Uri) ev.NewValue); new Task(() =>
instance.BeginAnimation(SourceProperty, instance._animator);
}
private static void LoadFullImageAsync(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
Task.Run(() =>
{ {
var instance = obj as AnimatedImage; var image = instance._animation.GetRenderedFrame((int) ev.NewValue);
if (instance == null)
return;
var animator = LoadFullImageCore((Uri) ev.NewValue); instance.Dispatcher.BeginInvoke(
new Action(() => { instance.Source = image; }), DispatcherPriority.Loaded);
instance.Dispatcher.Invoke(DispatcherPriority.Render, }).Start();
new Action(() =>
{
if (instance._disposed)
{
ProcessHelper.PerformAggressiveGC();
return;
}
instance._animator = animator;
instance.BeginAnimation(SourceProperty, instance._animator);
Debug.WriteLine($"LoadFullImageAsync {Thread.CurrentThread.ManagedThreadId}");
}));
});
} }
private static ObjectAnimationUsingKeyFrames LoadFullImageCore(Uri path) #endregion DependencyProperty
{
byte[] sign;
using (var reader =
new BinaryReader(new FileStream(path.LocalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
sign = reader.BaseStream.Length < 4 ? new byte[] {0, 0, 0, 0} : reader.ReadBytes(4);
}
IAnimationProvider provider;
if (sign[0] == 'G' && sign[1] == 'I' && sign[2] == 'F' && sign[3] == '8')
provider = new GIFAnimationProvider();
else if (sign[0] == 0x89 && sign[1] == 'P' && sign[2] == 'N' && sign[3] == 'G')
provider = new APNGAnimationProvider();
else
provider = new ImageMagickProvider();
var animator = new ObjectAnimationUsingKeyFrames();
provider.GetAnimator(animator, path.LocalPath);
animator.Freeze();
return animator;
}
} }
} }

View File

@@ -15,12 +15,23 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using System.Windows.Media;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{ {
internal interface IAnimationProvider internal abstract class AnimationProvider
{ {
void GetAnimator(ObjectAnimationUsingKeyFrames animator, string path); public AnimationProvider(string path)
{
Path = path;
}
public string Path { get; }
public Int32Animation Animator { get; protected set; }
public abstract DrawingImage GetRenderedFrame(int index);
} }
} }

View File

@@ -16,86 +16,91 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using QuickLook.Common.ExtensionMethods;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage namespace QuickLook.Plugin.ImageViewer.AnimatedImage
{ {
internal class GIFAnimationProvider : IAnimationProvider internal class GIFAnimationProvider : AnimationProvider
{ {
public void GetAnimator(ObjectAnimationUsingKeyFrames animator, string path) private readonly List<FrameInfo> _decodedFrames;
private readonly int _lastRenderedFrameIndex;
private readonly DrawingGroup renderedFrame;
public GIFAnimationProvider(string path) : base(path)
{ {
var decoder = var decoder = new GifBitmapDecoder(new Uri(path), BitmapCreateOptions.PreservePixelFormat,
new GifBitmapDecoder(new Uri(path), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
BitmapCacheOption.OnLoad);
var clock = TimeSpan.Zero; _decodedFrames = new List<FrameInfo>(decoder.Frames.Count);
BitmapSource prevFrame = null; decoder.Frames.ForEach(f => _decodedFrames.Add(GetFrameInfo(f)));
FrameInfo prevInfo = null;
BitmapSource prevprevFrame = null; renderedFrame = new DrawingGroup();
foreach (var rawFrame in decoder.Frames) _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))))
{ {
var info = GetFrameInfo(rawFrame); RepeatBehavior = RepeatBehavior.Forever
var frame = MakeFrame(decoder.Frames[0], rawFrame, info, prevFrame, prevInfo, prevprevFrame); };
prevprevFrame = prevFrame; }
prevFrame = frame;
prevInfo = info;
animator.KeyFrames.Add(new DiscreteObjectKeyFrame(frame, clock)); public override DrawingImage GetRenderedFrame(int index)
clock += info.Delay; {
} for (var i = _lastRenderedFrameIndex + 1; i < index; i++)
MakeFrame(renderedFrame, _decodedFrames[i], i > 0 ? _decodedFrames[i - 1] : null);
animator.Duration = clock; MakeFrame(
animator.RepeatBehavior = RepeatBehavior.Forever; renderedFrame,
_decodedFrames[index],
index > 0 ? _decodedFrames[index - 1] : null);
var di=new DrawingImage(renderedFrame);
di.Freeze();
return di;
} }
#region private methods #region private methods
private static BitmapSource MakeFrame( private static void MakeFrame(
BitmapSource fullImage, DrawingGroup renderedFrame,
BitmapSource rawFrame, FrameInfo frameInfo, FrameInfo currentFrame,
BitmapSource previousFrame, FrameInfo previousFrameInfo, FrameInfo previousFrame)
BitmapSource previouspreviousFrame)
{ {
var visual = new DrawingVisual(); if (previousFrame == null)
using (var context = visual.RenderOpen()) renderedFrame.Children.Clear();
{ else
if (previousFrameInfo != null && previousFrame != null) switch (previousFrame.DisposalMethod)
{ {
var fullRect = new Rect(0, 0, fullImage.PixelWidth, fullImage.PixelHeight); case FrameDisposalMethod.Unspecified:
case FrameDisposalMethod.Combine:
switch (previousFrameInfo.DisposalMethod) break;
{ case FrameDisposalMethod.RestorePrevious:
case FrameDisposalMethod.Unspecified: renderedFrame.Children.RemoveAt(renderedFrame.Children.Count - 1);
case FrameDisposalMethod.Combine: break;
context.DrawImage(previousFrame, fullRect); case FrameDisposalMethod.RestoreBackground:
break; var bg = renderedFrame.Children.First();
case FrameDisposalMethod.RestorePrevious: renderedFrame.Children.Clear();
if (previouspreviousFrame != null) renderedFrame.Children.Add(bg);
context.DrawImage(previouspreviousFrame, fullRect); break;
break;
case FrameDisposalMethod.RestoreBackground:
break;
}
} }
context.DrawImage(rawFrame, frameInfo.Rect); renderedFrame.Children.Add(new ImageDrawing(currentFrame.Frame, currentFrame.Rect));
}
var bitmap = new RenderTargetBitmap(
fullImage.PixelWidth, fullImage.PixelHeight,
Math.Floor(fullImage.DpiX), Math.Floor(fullImage.DpiY),
PixelFormats.Pbgra32);
bitmap.Render(visual);
return bitmap;
} }
private static FrameInfo GetFrameInfo(BitmapFrame frame) private static FrameInfo GetFrameInfo(BitmapFrame frame)
{ {
var frameInfo = new FrameInfo var frameInfo = new FrameInfo
{ {
Frame = frame,
Delay = TimeSpan.FromMilliseconds(100), Delay = TimeSpan.FromMilliseconds(100),
DisposalMethod = FrameDisposalMethod.Unspecified, DisposalMethod = FrameDisposalMethod.Unspecified,
Width = frame.PixelWidth, Width = frame.PixelWidth,
@@ -153,14 +158,15 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
private class FrameInfo private class FrameInfo
{ {
public TimeSpan Delay { get; set; } public BitmapSource Frame { get; set; }
public FrameDisposalMethod DisposalMethod { 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 Width { private get; set; }
public double Height { private get; set; } public double Height { private get; set; }
public double Left { private get; set; } public double Left { private get; set; }
public double Top { private get; set; } public double Top { private get; set; }
public Rect Rect => new Rect(Left, Top, Width, Height);
} }
private enum FrameDisposalMethod private enum FrameDisposalMethod

View File

@@ -78,10 +78,10 @@
<Link>Properties\GitVersion.cs</Link> <Link>Properties\GitVersion.cs</Link>
</Compile> </Compile>
<Compile Include="AnimatedImage\AnimatedImage.cs" /> <Compile Include="AnimatedImage\AnimatedImage.cs" />
<Compile Include="AnimatedImage\APNGAnimationProvider.cs" /> <None Include="AnimatedImage\APNGAnimationProvider.cs" />
<Compile Include="AnimatedImage\GIFAnimationProvider.cs" /> <Compile Include="AnimatedImage\GIFAnimationProvider.cs" />
<Compile Include="AnimatedImage\IAnimationProvider.cs" /> <Compile Include="AnimatedImage\AnimationProvider.cs" />
<Compile Include="AnimatedImage\ImageMagickProvider.cs" /> <None Include="AnimatedImage\ImageMagickProvider.cs" />
<Compile Include="exiv2\Meta.cs" /> <Compile Include="exiv2\Meta.cs" />
<Compile Include="ImageFileHelper.cs" /> <Compile Include="ImageFileHelper.cs" />
<Compile Include="ImagePanel.xaml.cs"> <Compile Include="ImagePanel.xaml.cs">

View File

@@ -70,6 +70,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.MailViewer
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Common", "QuickLook.Common\QuickLook.Common.csproj", "{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Common", "QuickLook.Common\QuickLook.Common.csproj", "{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.CameraRawViewer", "QuickLook.Plugin\QuickLook.Plugin.CameraRawViewer\QuickLook.Plugin.CameraRawViewer.csproj", "{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -200,6 +202,14 @@ Global
{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}.Release|Any CPU.Build.0 = Release|Any CPU {85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}.Release|Any CPU.Build.0 = Release|Any CPU
{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}.Release|x86.ActiveCfg = Release|Any CPU {85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}.Release|x86.ActiveCfg = Release|Any CPU
{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}.Release|x86.Build.0 = Release|Any CPU {85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}.Release|x86.Build.0 = Release|Any CPU
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}.Debug|x86.ActiveCfg = Debug|x86
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}.Debug|x86.Build.0 = Debug|x86
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}.Release|Any CPU.Build.0 = Release|Any CPU
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}.Release|x86.ActiveCfg = Release|x86
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA}.Release|x86.Build.0 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -218,6 +228,7 @@ Global
{2C58F9B2-D8FA-4586-942B-5170CECE5963} = {D18A23FF-76BD-43BD-AC32-786D166EBAC9} {2C58F9B2-D8FA-4586-942B-5170CECE5963} = {D18A23FF-76BD-43BD-AC32-786D166EBAC9}
{863ECAAC-18D9-4256-A27D-0F308089FB47} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {863ECAAC-18D9-4256-A27D-0F308089FB47} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
{45E94893-3076-4A8E-8969-6955B6340739} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93} {45E94893-3076-4A8E-8969-6955B6340739} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
{BD58F3FC-7601-47BA-AAA1-D8A9D54A33DA} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62} SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62}