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/>.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Media;
using System.Windows.Threading;
using QuickLook.Common.Helpers;
using QuickLook.Plugin.ImageViewer.Exiv2;
@@ -31,15 +29,68 @@ 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 = 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 =
DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage),
new UIPropertyMetadata(null, LoadImage));
new UIPropertyMetadata(null, AnimationUriChanged));
public static readonly DependencyProperty MetaProperty =
DependencyProperty.Register("Meta", typeof(Meta), typeof(AnimatedImage));
private ObjectAnimationUsingKeyFrames _animator = new ObjectAnimationUsingKeyFrames();
private bool _disposed;
public int AnimationFrameIndex
{
get => (int) GetValue(AnimationFrameIndexProperty);
set => SetValue(AnimationFrameIndexProperty, value);
}
public Uri AnimationUri
{
@@ -53,90 +104,33 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
set => SetValue(MetaProperty, value);
}
public void Dispose()
private static void AnimationUriChanged(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
BeginAnimation(SourceProperty, null);
Source = null;
_animator.KeyFrames.Clear();
_disposed = true;
}
private static void LoadImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
var instance = obj as AnimatedImage;
if (instance == null)
if (!(obj is AnimatedImage instance))
return;
var thumbnail = instance.Meta?.GetThumbnail(true);
instance.Source = thumbnail;
//var thumbnail = instance.Meta?.GetThumbnail(true);
//instance.Source = thumbnail;
if (thumbnail != null)
LoadFullImageAsync(obj, ev);
else
LoadFullImage(obj, ev);
instance.AnimationFrameIndex = 0;
}
private static void LoadFullImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
private static void AnimationFrameIndexChanged(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
{
var instance = obj as AnimatedImage;
if (instance == null)
if (!(obj is AnimatedImage instance))
return;
instance._animator = LoadFullImageCore((Uri) ev.NewValue);
instance.BeginAnimation(SourceProperty, instance._animator);
}
private static void LoadFullImageAsync(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
new Task(() =>
{
Task.Run(() =>
{
var instance = obj as AnimatedImage;
if (instance == null)
return;
var image = instance._animation.GetRenderedFrame((int) ev.NewValue);
var animator = LoadFullImageCore((Uri) ev.NewValue);
instance.Dispatcher.Invoke(DispatcherPriority.Render,
new Action(() =>
{
if (instance._disposed)
{
ProcessHelper.PerformAggressiveGC();
return;
instance.Dispatcher.BeginInvoke(
new Action(() => { instance.Source = image; }), DispatcherPriority.Loaded);
}).Start();
}
instance._animator = animator;
instance.BeginAnimation(SourceProperty, instance._animator);
Debug.WriteLine($"LoadFullImageAsync {Thread.CurrentThread.ManagedThreadId}");
}));
});
}
private static ObjectAnimationUsingKeyFrames 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);
}
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;
}
#endregion DependencyProperty
}
}

View File

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

View File

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

View File

@@ -70,6 +70,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.MailViewer
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Common", "QuickLook.Common\QuickLook.Common.csproj", "{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}"
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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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|x86.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -218,6 +228,7 @@ Global
{2C58F9B2-D8FA-4586-942B-5170CECE5963} = {D18A23FF-76BD-43BD-AC32-786D166EBAC9}
{863ECAAC-18D9-4256-A27D-0F308089FB47} = {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
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62}