mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-11 17:59:17 +00:00
Fix #106: display thumbnails
This commit is contained in:
@@ -16,10 +16,16 @@
|
|||||||
// 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.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media.Animation;
|
using System.Windows.Media.Animation;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using QuickLook.Helpers;
|
||||||
|
using QuickLook.Plugin.ImageViewer.Exiv2;
|
||||||
|
|
||||||
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
|
namespace QuickLook.Plugin.ImageViewer.AnimatedImage
|
||||||
{
|
{
|
||||||
@@ -29,7 +35,11 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
|
|||||||
DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage),
|
DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage),
|
||||||
new UIPropertyMetadata(null, LoadImage));
|
new UIPropertyMetadata(null, LoadImage));
|
||||||
|
|
||||||
private readonly ObjectAnimationUsingKeyFrames _animator = new ObjectAnimationUsingKeyFrames();
|
public static readonly DependencyProperty MetaProperty =
|
||||||
|
DependencyProperty.Register("Meta", typeof(Meta), typeof(AnimatedImage));
|
||||||
|
|
||||||
|
private ObjectAnimationUsingKeyFrames _animator = new ObjectAnimationUsingKeyFrames();
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public Uri AnimationUri
|
public Uri AnimationUri
|
||||||
{
|
{
|
||||||
@@ -37,11 +47,19 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
|
|||||||
set => SetValue(AnimationUriProperty, value);
|
set => SetValue(AnimationUriProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Meta Meta
|
||||||
|
{
|
||||||
|
private get => (Meta) GetValue(MetaProperty);
|
||||||
|
set => SetValue(MetaProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
BeginAnimation(SourceProperty, null);
|
BeginAnimation(SourceProperty, null);
|
||||||
Source = null;
|
Source = null;
|
||||||
_animator.KeyFrames.Clear();
|
_animator.KeyFrames.Clear();
|
||||||
|
|
||||||
|
_disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LoadImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
|
private static void LoadImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
|
||||||
@@ -50,8 +68,55 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
|
|||||||
if (instance == null)
|
if (instance == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var path = ((Uri) ev.NewValue).LocalPath;
|
var thumbnail = instance.Meta?.GetThumbnail(true);
|
||||||
var ext = Path.GetExtension(path).ToLower();
|
instance.Source = thumbnail;
|
||||||
|
|
||||||
|
if (thumbnail != null)
|
||||||
|
LoadFullImageAsync(obj, ev);
|
||||||
|
else
|
||||||
|
LoadFullImage(obj, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadFullImage(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
|
||||||
|
{
|
||||||
|
var instance = obj as AnimatedImage;
|
||||||
|
if (instance == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
instance._animator = LoadFullImageCore((Uri) ev.NewValue);
|
||||||
|
instance.BeginAnimation(SourceProperty, instance._animator);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LoadFullImageAsync(DependencyObject obj, DependencyPropertyChangedEventArgs ev)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
var instance = obj as AnimatedImage;
|
||||||
|
if (instance == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var animator = LoadFullImageCore((Uri) ev.NewValue);
|
||||||
|
|
||||||
|
instance.Dispatcher.Invoke(DispatcherPriority.Render,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var ext = Path.GetExtension(path.LocalPath).ToLower();
|
||||||
|
|
||||||
IAnimationProvider provider;
|
IAnimationProvider provider;
|
||||||
|
|
||||||
@@ -67,10 +132,11 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
|
|||||||
provider = new ImageMagickProvider();
|
provider = new ImageMagickProvider();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
var animator = new ObjectAnimationUsingKeyFrames();
|
||||||
|
provider.GetAnimator(animator, path.LocalPath);
|
||||||
|
animator.Freeze();
|
||||||
|
|
||||||
provider.GetAnimator(instance._animator, path);
|
return animator;
|
||||||
|
|
||||||
instance.BeginAnimation(SourceProperty, instance._animator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -28,9 +28,6 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
|
|||||||
{
|
{
|
||||||
public void GetAnimator(ObjectAnimationUsingKeyFrames animator, string path)
|
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))
|
using (var image = new MagickImage(path))
|
||||||
{
|
{
|
||||||
image.Density = new Density(Math.Floor(image.Density.X), Math.Floor(image.Density.Y));
|
image.Density = new Density(Math.Floor(image.Density.X), Math.Floor(image.Density.Y));
|
||||||
@@ -39,8 +36,6 @@ namespace QuickLook.Plugin.ImageViewer.AnimatedImage
|
|||||||
animator.KeyFrames.Add(new DiscreteObjectKeyFrame(image.ToBitmapSource(), TimeSpan.Zero));
|
animator.KeyFrames.Add(new DiscreteObjectKeyFrame(image.ToBitmapSource(), TimeSpan.Zero));
|
||||||
animator.Duration = Duration.Forever;
|
animator.Duration = Duration.Forever;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.SetCurrentDirectory(App.AppPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -15,50 +15,33 @@
|
|||||||
// 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;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using ExifLib;
|
|
||||||
using ImageMagick;
|
using ImageMagick;
|
||||||
|
using QuickLook.Plugin.ImageViewer.Exiv2;
|
||||||
|
|
||||||
namespace QuickLook.Plugin.ImageViewer
|
namespace QuickLook.Plugin.ImageViewer
|
||||||
{
|
{
|
||||||
internal static class ImageFileHelper
|
internal static class ImageFileHelper
|
||||||
{
|
{
|
||||||
internal static Size? GetImageSize(string path)
|
internal static Size GetImageSize(string path, Meta meta)
|
||||||
{
|
{
|
||||||
var ori = GetOrientationFromExif(path);
|
var size = meta.GetSize();
|
||||||
|
|
||||||
|
if (!size.IsEmpty)
|
||||||
|
return size;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var info = new MagickImageInfo(path);
|
var info = new MagickImageInfo(path);
|
||||||
|
|
||||||
if (ori == OrientationType.RightTop || ori == OrientationType.LeftBotom)
|
if (meta.GetOrientation() == OrientationType.RightTop ||
|
||||||
|
meta.GetOrientation() == OrientationType.LeftBotom)
|
||||||
return new Size {Width = info.Height, Height = info.Width};
|
return new Size {Width = info.Height, Height = info.Width};
|
||||||
return new Size {Width = info.Width, Height = info.Height};
|
return new Size {Width = info.Width, Height = info.Height};
|
||||||
}
|
}
|
||||||
catch (MagickException)
|
catch (MagickException)
|
||||||
{
|
{
|
||||||
return null;
|
return Size.Empty;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OrientationType GetOrientationFromExif(string path)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var re = new ExifReader(path))
|
|
||||||
{
|
|
||||||
re.GetTagValue(ExifTags.Orientation, out ushort orientation);
|
|
||||||
|
|
||||||
if (orientation == 0)
|
|
||||||
return OrientationType.Undefined;
|
|
||||||
|
|
||||||
return (OrientationType) orientation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
return OrientationType.Undefined;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
</Rectangle>
|
</Rectangle>
|
||||||
<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">
|
||||||
<animatedImage:AnimatedImage x:Name="viewPanelImage" Stretch="None" Margin="0,32,0,0"
|
<animatedImage:AnimatedImage x:Name="viewPanelImage" Stretch="None" Meta="{Binding Meta, ElementName=imagePanel}"
|
||||||
RenderOptions.BitmapScalingMode="{Binding RenderMode, ElementName=imagePanel}"
|
RenderOptions.BitmapScalingMode="{Binding RenderMode, ElementName=imagePanel}"
|
||||||
AnimationUri="{Binding ImageUriSource, ElementName=imagePanel}" />
|
AnimationUri="{Binding ImageUriSource, ElementName=imagePanel}" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
@@ -29,6 +29,7 @@ using System.Windows.Media.Imaging;
|
|||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using QuickLook.Annotations;
|
using QuickLook.Annotations;
|
||||||
using QuickLook.Helpers;
|
using QuickLook.Helpers;
|
||||||
|
using QuickLook.Plugin.ImageViewer.Exiv2;
|
||||||
|
|
||||||
namespace QuickLook.Plugin.ImageViewer
|
namespace QuickLook.Plugin.ImageViewer
|
||||||
{
|
{
|
||||||
@@ -42,6 +43,7 @@ namespace QuickLook.Plugin.ImageViewer
|
|||||||
private Uri _imageSource;
|
private Uri _imageSource;
|
||||||
private DateTime _lastZoomTime = DateTime.MinValue;
|
private DateTime _lastZoomTime = DateTime.MinValue;
|
||||||
private double _maxZoomFactor = 3d;
|
private double _maxZoomFactor = 3d;
|
||||||
|
private Meta _meta;
|
||||||
private double _minZoomFactor = 0.1d;
|
private double _minZoomFactor = 0.1d;
|
||||||
private BitmapScalingMode _renderMode = BitmapScalingMode.HighQuality;
|
private BitmapScalingMode _renderMode = BitmapScalingMode.HighQuality;
|
||||||
private BitmapSource _source;
|
private BitmapSource _source;
|
||||||
@@ -70,6 +72,11 @@ namespace QuickLook.Plugin.ImageViewer
|
|||||||
viewPanel.ManipulationDelta += ViewPanel_ManipulationDelta;
|
viewPanel.ManipulationDelta += ViewPanel_ManipulationDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal ImagePanel(Meta meta) : this()
|
||||||
|
{
|
||||||
|
Meta = meta;
|
||||||
|
}
|
||||||
|
|
||||||
public BitmapScalingMode RenderMode
|
public BitmapScalingMode RenderMode
|
||||||
{
|
{
|
||||||
get => _renderMode;
|
get => _renderMode;
|
||||||
@@ -163,6 +170,17 @@ namespace QuickLook.Plugin.ImageViewer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Meta Meta
|
||||||
|
{
|
||||||
|
get => _meta;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (Equals(value, _meta)) return;
|
||||||
|
_meta = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
viewPanelImage?.Dispose();
|
viewPanelImage?.Dispose();
|
||||||
|
@@ -20,6 +20,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using ImageMagick;
|
using ImageMagick;
|
||||||
|
using QuickLook.Plugin.ImageViewer.Exiv2;
|
||||||
|
|
||||||
namespace QuickLook.Plugin.ImageViewer
|
namespace QuickLook.Plugin.ImageViewer
|
||||||
{
|
{
|
||||||
@@ -28,18 +29,18 @@ namespace QuickLook.Plugin.ImageViewer
|
|||||||
private static readonly string[] Formats =
|
private static readonly string[] Formats =
|
||||||
{
|
{
|
||||||
// camera raw
|
// camera raw
|
||||||
".3fr", ".ari", ".arw", ".bay", ".crw", ".cr2", ".cap", ".data", ".dcs", ".dcr", ".dng", ".drf", ".eip",
|
".ari", ".arw", ".bay", ".crw", ".cr2", ".cap", ".dcs", ".dcr", ".dng", ".drf", ".eip", ".erf", ".fff",
|
||||||
".erf", ".fff", ".gpr", ".iiq", ".k25", ".kdc", ".mdc", ".mef", ".mos", ".mrw", ".nef", ".nrw", ".obm",
|
".iiq", ".k25", ".kdc", ".mdc", ".mef", ".mos", ".mrw", ".nef", ".nrw", ".obm", ".orf", ".pef", ".ptx",
|
||||||
".orf", ".pef", ".ptx", ".pxn", ".r3d", ".raf", ".raw", ".rwl", ".rw2", ".rwz", ".sr2", ".srf", ".srw",
|
".pxn", ".r3d", ".raf", ".raw", ".rwl", ".rw2", ".rwz", ".sr2", ".srf", ".srw", ".x3f",
|
||||||
".tif", ".x3f",
|
|
||||||
// normal
|
// normal
|
||||||
".bmp", ".ico", ".icon", ".jpg", ".jpeg", ".psd", ".svg", ".wdp", ".tif", ".tiff", ".tga",
|
".bmp", ".ico", ".icon", ".jpg", ".jpeg", ".psd", ".svg", ".wdp", ".tif", ".tiff", ".tga", ".webp", ".pbm",
|
||||||
".webp", ".pbm", ".pgm", ".ppm", ".pnm",
|
".pgm", ".ppm", ".pnm",
|
||||||
// animated
|
// animated
|
||||||
".png", ".apng", ".gif"
|
".png", ".apng", ".gif"
|
||||||
};
|
};
|
||||||
private Size _imageSize;
|
|
||||||
private ImagePanel _ip;
|
private ImagePanel _ip;
|
||||||
|
private Meta _meta;
|
||||||
|
private Size _imageSize;
|
||||||
|
|
||||||
public int Priority => int.MaxValue;
|
public int Priority => int.MaxValue;
|
||||||
|
|
||||||
@@ -55,26 +56,19 @@ namespace QuickLook.Plugin.ImageViewer
|
|||||||
|
|
||||||
public void Prepare(string path, ContextObject context)
|
public void Prepare(string path, ContextObject context)
|
||||||
{
|
{
|
||||||
_imageSize = ImageFileHelper.GetImageSize(path) ?? Size.Empty;
|
_imageSize = ImageFileHelper.GetImageSize(path, _meta = new Meta(path));
|
||||||
|
|
||||||
if (!_imageSize.IsEmpty)
|
if (!_imageSize.IsEmpty)
|
||||||
context.SetPreferredSizeFit(_imageSize, 0.6);
|
context.SetPreferredSizeFit(_imageSize, 0.8);
|
||||||
else
|
else
|
||||||
context.PreferredSize = new Size(800, 600);
|
context.PreferredSize = new Size(800, 600);
|
||||||
|
|
||||||
context.PreferredSize = new Size(context.PreferredSize.Width, context.PreferredSize.Height + 32);
|
|
||||||
|
|
||||||
Directory.SetCurrentDirectory(App.AppPath);
|
|
||||||
|
|
||||||
context.TitlebarBlurVisibility = true;
|
|
||||||
context.TitlebarOverlap = true;
|
|
||||||
context.TitlebarAutoHide = false;
|
|
||||||
context.UseDarkTheme = true;
|
context.UseDarkTheme = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ContextObject context)
|
public void View(string path, ContextObject context)
|
||||||
{
|
{
|
||||||
_ip = new ImagePanel();
|
_ip = new ImagePanel(_meta);
|
||||||
|
|
||||||
context.ViewerContent = _ip;
|
context.ViewerContent = _ip;
|
||||||
context.Title = _imageSize.IsEmpty
|
context.Title = _imageSize.IsEmpty
|
||||||
|
@@ -58,9 +58,6 @@
|
|||||||
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<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>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="LibAPNG">
|
<Reference Include="LibAPNG">
|
||||||
<HintPath>.\LibAPNG.dll</HintPath>
|
<HintPath>.\LibAPNG.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -84,6 +81,7 @@
|
|||||||
<Compile Include="AnimatedImage\GIFAnimationProvider.cs" />
|
<Compile Include="AnimatedImage\GIFAnimationProvider.cs" />
|
||||||
<Compile Include="AnimatedImage\IAnimationProvider.cs" />
|
<Compile Include="AnimatedImage\IAnimationProvider.cs" />
|
||||||
<Compile Include="AnimatedImage\ImageMagickProvider.cs" />
|
<Compile Include="AnimatedImage\ImageMagickProvider.cs" />
|
||||||
|
<Compile Include="exiv2\Meta.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>
|
||||||
@@ -109,11 +107,22 @@
|
|||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="dcraw.exe">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Resource Include="Resources\background-b.png" />
|
<Resource Include="Resources\background-b.png" />
|
||||||
<Resource Include="Resources\background.png" />
|
<Resource Include="Resources\background.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="exiv2\exiv2.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="exiv2\exiv2.exe">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="exiv2\expat.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="exiv2\zlib.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
Binary file not shown.
176
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/Meta.cs
Normal file
176
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/Meta.cs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using ImageMagick;
|
||||||
|
using QuickLook.ExtensionMethods;
|
||||||
|
|
||||||
|
namespace QuickLook.Plugin.ImageViewer.Exiv2
|
||||||
|
{
|
||||||
|
public class Meta
|
||||||
|
{
|
||||||
|
private static readonly string ExivPath =
|
||||||
|
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "exiv2\\exiv2.exe");
|
||||||
|
private readonly string _path;
|
||||||
|
|
||||||
|
private OrientationType _orientation = OrientationType.Undefined;
|
||||||
|
private Dictionary<string, string> _summary;
|
||||||
|
|
||||||
|
public Meta(string path)
|
||||||
|
{
|
||||||
|
_path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, string> GetSummary()
|
||||||
|
{
|
||||||
|
if (_summary != null)
|
||||||
|
return _summary;
|
||||||
|
|
||||||
|
return _summary = Run($"\"{_path}\"", ":");
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitmapSource GetThumbnail(bool autoZoom = false)
|
||||||
|
{
|
||||||
|
GetOrientation();
|
||||||
|
|
||||||
|
var count = Run($"-pp \"{_path}\"", ",").Count;
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var suc = Run($"-f -ep{count} -l \"{Path.GetTempPath().TrimEnd('\\')}\" \"{_path}\"", ",");
|
||||||
|
if (suc.Count != 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var image = new MagickImage(Path.Combine(Path.GetTempPath(),
|
||||||
|
$"{Path.GetFileNameWithoutExtension(_path)}-preview{count}.jpg")))
|
||||||
|
{
|
||||||
|
File.Delete(image.FileName);
|
||||||
|
|
||||||
|
if (_orientation == OrientationType.RightTop)
|
||||||
|
image.Rotate(90);
|
||||||
|
else if (_orientation == OrientationType.BottomRight)
|
||||||
|
image.Rotate(180);
|
||||||
|
else if (_orientation == OrientationType.LeftBotom)
|
||||||
|
image.Rotate(270);
|
||||||
|
if (!autoZoom)
|
||||||
|
return image.ToBitmapSource();
|
||||||
|
|
||||||
|
var size = GetSize();
|
||||||
|
return new TransformedBitmap(image.ToBitmapSource(),
|
||||||
|
new ScaleTransform(size.Width / image.Width, size.Height / image.Height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Size GetSize()
|
||||||
|
{
|
||||||
|
if (_summary == null)
|
||||||
|
GetSummary();
|
||||||
|
|
||||||
|
if (!_summary.ContainsKey("Image size"))
|
||||||
|
return Size.Empty;
|
||||||
|
|
||||||
|
var width = int.Parse(_summary["Image size"].Split('x')[0].Trim());
|
||||||
|
var height = int.Parse(_summary["Image size"].Split('x')[1].Trim());
|
||||||
|
|
||||||
|
switch (GetOrientation())
|
||||||
|
{
|
||||||
|
case OrientationType.RightTop:
|
||||||
|
case OrientationType.LeftBotom:
|
||||||
|
return new Size(height, width);
|
||||||
|
default:
|
||||||
|
return new Size(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrientationType GetOrientation()
|
||||||
|
{
|
||||||
|
if (_orientation != OrientationType.Undefined)
|
||||||
|
return _orientation;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ori = Run($"-g Exif.Image.Orientation -Pkv \"{_path}\"", "\\s");
|
||||||
|
|
||||||
|
if (ori?.ContainsKey("Exif.Image.Orientation") == true)
|
||||||
|
_orientation = (OrientationType) int.Parse(ori["Exif.Image.Orientation"]);
|
||||||
|
else
|
||||||
|
_orientation = OrientationType.TopLeft;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_orientation = OrientationType.TopLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, string> Run(string arg, string regexSplit)
|
||||||
|
{
|
||||||
|
string result;
|
||||||
|
|
||||||
|
using (var p = new Process())
|
||||||
|
{
|
||||||
|
p.StartInfo.UseShellExecute = false;
|
||||||
|
p.StartInfo.CreateNoWindow = true;
|
||||||
|
p.StartInfo.RedirectStandardOutput = true;
|
||||||
|
p.StartInfo.FileName = ExivPath;
|
||||||
|
p.StartInfo.Arguments = arg;
|
||||||
|
p.StartInfo.StandardOutputEncoding = Encoding.UTF8;
|
||||||
|
p.Start();
|
||||||
|
p.WaitForExit();
|
||||||
|
|
||||||
|
result = p.StandardOutput.ReadToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.IsNullOrWhiteSpace(result)
|
||||||
|
? new Dictionary<string, string>()
|
||||||
|
: ParseResult(result, regexSplit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, string> ParseResult(string result, string regexSplit)
|
||||||
|
{
|
||||||
|
var res = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
result.Replace("\r\n", "\n").Split('\n').ForEach(l =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(l))
|
||||||
|
return;
|
||||||
|
var eles = Regex.Split(l, regexSplit + "{1,}");
|
||||||
|
res.Add(eles[0].Trim(), eles[1].Trim());
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/exiv2.dll
Normal file
BIN
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/exiv2.dll
Normal file
Binary file not shown.
BIN
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/exiv2.exe
Normal file
BIN
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/exiv2.exe
Normal file
Binary file not shown.
BIN
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/expat.dll
Normal file
BIN
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/expat.dll
Normal file
Binary file not shown.
BIN
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/zlib.dll
Normal file
BIN
QuickLook.Plugin/QuickLook.Plugin.ImageViewer/exiv2/zlib.dll
Normal file
Binary file not shown.
@@ -1,5 +1,4 @@
|
|||||||
<?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="Magick.NET-Q8-AnyCPU" version="7.0.7.900" targetFramework="net462" />
|
<package id="Magick.NET-Q8-AnyCPU" version="7.0.7.900" targetFramework="net462" />
|
||||||
</packages>
|
</packages>
|
@@ -27,7 +27,6 @@
|
|||||||
VirtualizingPanel.IsVirtualizing="True" Width="150"
|
VirtualizingPanel.IsVirtualizing="True" Width="150"
|
||||||
SelectedIndex="0"
|
SelectedIndex="0"
|
||||||
Focusable="False"
|
Focusable="False"
|
||||||
Margin="0,32,0,0"
|
|
||||||
Background="#00FFFFFF"
|
Background="#00FFFFFF"
|
||||||
ItemsSource="{Binding PageIds, ElementName=thisPdfViewer}"
|
ItemsSource="{Binding PageIds, ElementName=thisPdfViewer}"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0,0,1,0"
|
ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0,0,1,0"
|
||||||
|
@@ -60,9 +60,6 @@ namespace QuickLook.Plugin.PDFViewer
|
|||||||
context.SetPreferredSizeFit(desiredSize, 0.6);
|
context.SetPreferredSizeFit(desiredSize, 0.6);
|
||||||
|
|
||||||
context.PreferredSize = new Size(context.PreferredSize.Width, context.PreferredSize.Height + 32);
|
context.PreferredSize = new Size(context.PreferredSize.Width, context.PreferredSize.Height + 32);
|
||||||
|
|
||||||
context.TitlebarBlurVisibility = true;
|
|
||||||
context.TitlebarOverlap = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void View(string path, ContextObject context)
|
public void View(string path, ContextObject context)
|
||||||
|
@@ -22,7 +22,7 @@ using QuickLook.NativeMethods;
|
|||||||
|
|
||||||
namespace QuickLook.Helpers
|
namespace QuickLook.Helpers
|
||||||
{
|
{
|
||||||
internal class ProcessHelper
|
public class ProcessHelper
|
||||||
{
|
{
|
||||||
private const int ErrorInsufficientBuffer = 0x7A;
|
private const int ErrorInsufficientBuffer = 0x7A;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user