mirror of
https://github.com/QL-Win/QuickLook.git
synced 2025-09-11 17:59:17 +00:00
Code Cleanup
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
// Copyright © 2018 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/>.
|
||||
|
||||
@@ -21,42 +21,41 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace QuickLook.Plugin.PDFViewer
|
||||
namespace QuickLook.Plugin.PDFViewer;
|
||||
|
||||
internal class AsyncPageToThumbnailConverter : IMultiValueConverter
|
||||
{
|
||||
internal class AsyncPageToThumbnailConverter : IMultiValueConverter
|
||||
private static readonly BitmapImage Loading =
|
||||
new BitmapImage(
|
||||
new Uri("pack://application:,,,/QuickLook.Plugin.PdfViewer;component/Resources/loading.png"));
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
private static readonly BitmapImage Loading =
|
||||
new BitmapImage(
|
||||
new Uri("pack://application:,,,/QuickLook.Plugin.PdfViewer;component/Resources/loading.png"));
|
||||
if (values.Length < 2)
|
||||
throw new Exception("PageIdToImageConverter");
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
if (values[0] is not PdfDocumentWrapper handle) return null;
|
||||
|
||||
var pageId = (int)values[1];
|
||||
if (pageId < 0) return null;
|
||||
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
if (values.Length < 2)
|
||||
throw new Exception("PageIdToImageConverter");
|
||||
|
||||
if (!(values[0] is PdfDocumentWrapper handle)) return null;
|
||||
|
||||
var pageId = (int) values[1];
|
||||
if (pageId < 0) return null;
|
||||
|
||||
var task = Task.Run(() =>
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return handle.RenderThumbnail(pageId);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Loading;
|
||||
}
|
||||
});
|
||||
return handle.RenderThumbnail(pageId);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Loading;
|
||||
}
|
||||
});
|
||||
|
||||
return new NotifyTaskCompletion<BitmapSource>(task, Loading);
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
return new NotifyTaskCompletion<BitmapSource>(task, Loading);
|
||||
}
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
@@ -1,48 +1,48 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style x:Key="ListBoxItemStyleNoFocusedBorder" TargetType="{x:Type ListBoxItem}">
|
||||
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ListBoxItem}">
|
||||
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}"
|
||||
<Border x:Name="Bd"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"
|
||||
SnapsToDevicePixels="True">
|
||||
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentStringFormat="{TemplateBinding ContentStringFormat}"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Background" TargetName="Bd" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" TargetName="Bd" Value="Transparent" />
|
||||
<Setter TargetName="Bd" Property="Background" Value="Transparent" />
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="Transparent" />
|
||||
</MultiTrigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="Selector.IsSelectionActive" Value="False" />
|
||||
<Condition Property="IsSelected" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Background" TargetName="Bd" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" TargetName="Bd" Value="Transparent" />
|
||||
<Setter TargetName="Bd" Property="Background" Value="Transparent" />
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="Transparent" />
|
||||
</MultiTrigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="Selector.IsSelectionActive" Value="True" />
|
||||
<Condition Property="IsSelected" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter Property="Background" TargetName="Bd" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" TargetName="Bd" Value="Transparent" />
|
||||
<Setter TargetName="Bd" Property="Background" Value="Transparent" />
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="Transparent" />
|
||||
</MultiTrigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="TextElement.Foreground" TargetName="Bd"
|
||||
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
|
||||
<Setter TargetName="Bd" Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
@@ -1,17 +1,17 @@
|
||||
// Copyright © 2018 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/>.
|
||||
|
||||
@@ -19,71 +19,73 @@ using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace QuickLook.Plugin.PDFViewer
|
||||
namespace QuickLook.Plugin.PDFViewer;
|
||||
|
||||
public sealed class NotifyTaskCompletion<TResult> : INotifyPropertyChanged
|
||||
{
|
||||
public sealed class NotifyTaskCompletion<TResult> : INotifyPropertyChanged
|
||||
private readonly TResult _loading;
|
||||
|
||||
public NotifyTaskCompletion(Task<TResult> task, TResult loading = default(TResult))
|
||||
{
|
||||
private readonly TResult _loading;
|
||||
|
||||
public NotifyTaskCompletion(Task<TResult> task, TResult loading = default(TResult))
|
||||
Task = task;
|
||||
_loading = loading;
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
Task = task;
|
||||
_loading = loading;
|
||||
if (!task.IsCompleted)
|
||||
{
|
||||
var _ = WatchTaskAsync(task);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<TResult> Task { get; }
|
||||
public TResult Result => Task.Status == TaskStatus.RanToCompletion ? Task.Result : _loading;
|
||||
public TaskStatus Status => Task.Status;
|
||||
public bool IsCompleted => Task.IsCompleted;
|
||||
public bool IsNotCompleted => !Task.IsCompleted;
|
||||
public bool IsSuccessfullyCompleted => Task.Status ==
|
||||
TaskStatus.RanToCompletion;
|
||||
public bool IsCanceled => Task.IsCanceled;
|
||||
public bool IsFaulted => Task.IsFaulted;
|
||||
public AggregateException Exception => Task.Exception;
|
||||
public Exception InnerException => Exception?.InnerException;
|
||||
public string ErrorMessage => InnerException?.Message;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private async Task WatchTaskAsync(Task task)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
var propertyChanged = PropertyChanged;
|
||||
if (propertyChanged == null)
|
||||
return;
|
||||
propertyChanged(this, new PropertyChangedEventArgs("Status"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("IsCompleted"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("IsNotCompleted"));
|
||||
if (task.IsCanceled)
|
||||
{
|
||||
propertyChanged(this, new PropertyChangedEventArgs("IsCanceled"));
|
||||
}
|
||||
else if (task.IsFaulted)
|
||||
{
|
||||
propertyChanged(this, new PropertyChangedEventArgs("IsFaulted"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("Exception"));
|
||||
propertyChanged(this,
|
||||
new PropertyChangedEventArgs("InnerException"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("ErrorMessage"));
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyChanged(this,
|
||||
new PropertyChangedEventArgs("IsSuccessfullyCompleted"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("Result"));
|
||||
}
|
||||
var _ = WatchTaskAsync(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task<TResult> Task { get; }
|
||||
public TResult Result => Task.Status == TaskStatus.RanToCompletion ? Task.Result : _loading;
|
||||
public TaskStatus Status => Task.Status;
|
||||
public bool IsCompleted => Task.IsCompleted;
|
||||
public bool IsNotCompleted => !Task.IsCompleted;
|
||||
|
||||
public bool IsSuccessfullyCompleted => Task.Status ==
|
||||
TaskStatus.RanToCompletion;
|
||||
|
||||
public bool IsCanceled => Task.IsCanceled;
|
||||
public bool IsFaulted => Task.IsFaulted;
|
||||
public AggregateException Exception => Task.Exception;
|
||||
public Exception InnerException => Exception?.InnerException;
|
||||
public string ErrorMessage => InnerException?.Message;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private async Task WatchTaskAsync(Task task)
|
||||
{
|
||||
try
|
||||
{
|
||||
await task;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
var propertyChanged = PropertyChanged;
|
||||
if (propertyChanged == null)
|
||||
return;
|
||||
propertyChanged(this, new PropertyChangedEventArgs("Status"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("IsCompleted"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("IsNotCompleted"));
|
||||
if (task.IsCanceled)
|
||||
{
|
||||
propertyChanged(this, new PropertyChangedEventArgs("IsCanceled"));
|
||||
}
|
||||
else if (task.IsFaulted)
|
||||
{
|
||||
propertyChanged(this, new PropertyChangedEventArgs("IsFaulted"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("Exception"));
|
||||
propertyChanged(this,
|
||||
new PropertyChangedEventArgs("InnerException"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("ErrorMessage"));
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyChanged(this,
|
||||
new PropertyChangedEventArgs("IsSuccessfullyCompleted"));
|
||||
propertyChanged(this, new PropertyChangedEventArgs("Result"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,17 @@
|
||||
// Copyright © 2018 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/>.
|
||||
|
||||
@@ -19,40 +19,39 @@ using System;
|
||||
using System.IO;
|
||||
using PdfiumViewer;
|
||||
|
||||
namespace QuickLook.Plugin.PDFViewer
|
||||
namespace QuickLook.Plugin.PDFViewer;
|
||||
|
||||
public class PdfDocumentWrapper : IDisposable
|
||||
{
|
||||
public class PdfDocumentWrapper : IDisposable
|
||||
public PdfDocumentWrapper(Stream stream)
|
||||
{
|
||||
public PdfDocumentWrapper(Stream stream)
|
||||
{
|
||||
PdfStream = new MemoryStream((int) stream.Length);
|
||||
stream.CopyTo(PdfStream);
|
||||
PdfStream = new MemoryStream((int)stream.Length);
|
||||
stream.CopyTo(PdfStream);
|
||||
|
||||
PdfDocument = PdfDocument.Load(PdfStream);
|
||||
}
|
||||
|
||||
public PdfDocument PdfDocument { get; private set; }
|
||||
|
||||
public MemoryStream PdfStream { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PdfDocument.Dispose();
|
||||
PdfDocument = null;
|
||||
PdfStream.Dispose();
|
||||
PdfStream = null;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
var oldD = PdfDocument;
|
||||
|
||||
PdfStream.Position = 0;
|
||||
var newObj = new PdfDocumentWrapper(PdfStream);
|
||||
PdfDocument = newObj.PdfDocument;
|
||||
PdfStream = newObj.PdfStream;
|
||||
|
||||
oldD.Dispose();
|
||||
}
|
||||
PdfDocument = PdfDocument.Load(PdfStream);
|
||||
}
|
||||
}
|
||||
|
||||
public PdfDocument PdfDocument { get; private set; }
|
||||
|
||||
public MemoryStream PdfStream { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PdfDocument.Dispose();
|
||||
PdfDocument = null;
|
||||
PdfStream.Dispose();
|
||||
PdfStream = null;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
var oldD = PdfDocument;
|
||||
|
||||
PdfStream.Position = 0;
|
||||
var newObj = new PdfDocumentWrapper(PdfStream);
|
||||
PdfDocument = newObj.PdfDocument;
|
||||
PdfStream = newObj.PdfStream;
|
||||
|
||||
oldD.Dispose();
|
||||
}
|
||||
}
|
||||
|
@@ -1,76 +1,75 @@
|
||||
// Copyright © 2018 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.Drawing;
|
||||
using System.Windows.Media.Imaging;
|
||||
using PdfiumViewer;
|
||||
using QuickLook.Common.ExtensionMethods;
|
||||
using QuickLook.Common.Helpers;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace QuickLook.Plugin.PDFViewer
|
||||
namespace QuickLook.Plugin.PDFViewer;
|
||||
|
||||
internal static class PdfPageExtension
|
||||
{
|
||||
internal static class PdfPageExtension
|
||||
private static int _renderCount;
|
||||
private static readonly object LockObj = new object();
|
||||
|
||||
public static BitmapSource RenderThumbnail(this PdfDocumentWrapper doc, int page)
|
||||
{
|
||||
private static int _renderCount;
|
||||
private static readonly object LockObj = new object();
|
||||
|
||||
public static BitmapSource RenderThumbnail(this PdfDocumentWrapper doc, int page)
|
||||
lock (LockObj)
|
||||
{
|
||||
lock (LockObj)
|
||||
if (_renderCount++ == 50)
|
||||
{
|
||||
if (_renderCount++ == 50)
|
||||
{
|
||||
doc.Refresh();
|
||||
_renderCount = 0;
|
||||
}
|
||||
doc.Refresh();
|
||||
_renderCount = 0;
|
||||
}
|
||||
|
||||
var size = doc.PdfDocument.PageSizes[page];
|
||||
var factorX = 60d / size.Width;
|
||||
var factorY = 120d / size.Height;
|
||||
|
||||
return doc.Render(page, Math.Min(factorX, factorY), false);
|
||||
}
|
||||
|
||||
public static BitmapSource Render(this PdfDocumentWrapper doc, int page, double factor, bool fixDpi = true)
|
||||
{
|
||||
var scale = DisplayDeviceHelper.GetCurrentScaleFactor();
|
||||
var dpiX = fixDpi ? scale.Horizontal * DisplayDeviceHelper.DefaultDpi : 96;
|
||||
var dpiY = fixDpi ? scale.Vertical * DisplayDeviceHelper.DefaultDpi : 96;
|
||||
var size = doc.PdfDocument.PageSizes[page];
|
||||
var factorX = 60d / size.Width;
|
||||
var factorY = 120d / size.Height;
|
||||
|
||||
Bitmap bitmap;
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
var size = doc.PdfDocument.PageSizes[page];
|
||||
var realWidth = (int) Math.Round(size.Width * scale.Horizontal * factor);
|
||||
var realHeight = (int) Math.Round(size.Height * scale.Vertical * factor);
|
||||
|
||||
bitmap = doc.PdfDocument.Render(page, realWidth, realHeight, dpiX, dpiY, PdfRotation.Rotate0,
|
||||
PdfRenderFlags.LimitImageCacheSize | PdfRenderFlags.LcdText | PdfRenderFlags.Annotations |
|
||||
PdfRenderFlags.ForPrinting, true) as Bitmap;
|
||||
}
|
||||
|
||||
var bs = bitmap?.ToBitmapSource();
|
||||
bitmap?.Dispose();
|
||||
|
||||
bs?.Freeze();
|
||||
return bs;
|
||||
}
|
||||
return doc.Render(page, Math.Min(factorX, factorY), false);
|
||||
}
|
||||
}
|
||||
|
||||
public static BitmapSource Render(this PdfDocumentWrapper doc, int page, double factor, bool fixDpi = true)
|
||||
{
|
||||
var scale = DisplayDeviceHelper.GetCurrentScaleFactor();
|
||||
var dpiX = fixDpi ? scale.Horizontal * DisplayDeviceHelper.DefaultDpi : 96;
|
||||
var dpiY = fixDpi ? scale.Vertical * DisplayDeviceHelper.DefaultDpi : 96;
|
||||
|
||||
Bitmap bitmap;
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
var size = doc.PdfDocument.PageSizes[page];
|
||||
var realWidth = (int)Math.Round(size.Width * scale.Horizontal * factor);
|
||||
var realHeight = (int)Math.Round(size.Height * scale.Vertical * factor);
|
||||
|
||||
bitmap = doc.PdfDocument.Render(page, realWidth, realHeight, dpiX, dpiY, PdfRotation.Rotate0,
|
||||
PdfRenderFlags.LimitImageCacheSize | PdfRenderFlags.LcdText | PdfRenderFlags.Annotations |
|
||||
PdfRenderFlags.ForPrinting, true) as Bitmap;
|
||||
}
|
||||
|
||||
var bs = bitmap?.ToBitmapSource();
|
||||
bitmap?.Dispose();
|
||||
|
||||
bs?.Freeze();
|
||||
return bs;
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,15 @@
|
||||
<UserControl x:Class="QuickLook.Plugin.PDFViewer.PdfViewerControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:QuickLook.Plugin.PDFViewer"
|
||||
xmlns:imageViewer="clr-namespace:QuickLook.Plugin.ImageViewer;assembly=QuickLook.Plugin.ImageViewer"
|
||||
mc:Ignorable="d"
|
||||
xmlns:local="clr-namespace:QuickLook.Plugin.PDFViewer"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Name="thisPdfViewer"
|
||||
UseLayoutRounding="True"
|
||||
d:DesignHeight="476.974"
|
||||
d:DesignWidth="720.29">
|
||||
d:DesignWidth="720.29"
|
||||
UseLayoutRounding="True"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<local:AsyncPageToThumbnailConverter x:Key="AsyncPageToThumbnailConverter" />
|
||||
@@ -24,16 +24,19 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ListBox x:Name="listThumbnails" Grid.Column="0" Width="150"
|
||||
SelectedIndex="0"
|
||||
Focusable="False"
|
||||
<ListBox x:Name="listThumbnails"
|
||||
Grid.Column="0"
|
||||
Width="150"
|
||||
HorizontalContentAlignment="Center"
|
||||
VirtualizingStackPanel.IsVirtualizing="True"
|
||||
VirtualizingStackPanel.VirtualizationMode="Recycling"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Focusable="False"
|
||||
ItemContainerStyle="{Binding Mode=OneWay, Source={StaticResource ListBoxItemStyleNoFocusedBorder}}"
|
||||
ItemsSource="{Binding ElementName=thisPdfViewer, Path=PageThumbnails}"
|
||||
ItemContainerStyle="{Binding Mode=OneWay, Source={StaticResource ListBoxItemStyleNoFocusedBorder}}">
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
SelectedIndex="0"
|
||||
VirtualizingStackPanel.IsVirtualizing="True"
|
||||
VirtualizingStackPanel.VirtualizationMode="Recycling">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Height="150"
|
||||
@@ -49,11 +52,15 @@
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="10" />
|
||||
</Grid.RowDefinitions>
|
||||
<Border x:Name="bbd" Grid.Row="1" Grid.Column="1" BorderThickness="1" BorderBrush="Gray">
|
||||
<Border x:Name="bbd"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1">
|
||||
<Image Source="{Binding Path=Result}">
|
||||
<Image.DataContext>
|
||||
<MultiBinding Converter="{StaticResource AsyncPageToThumbnailConverter}">
|
||||
<Binding Path="PdfDocumentWrapper" ElementName="thisPdfViewer" />
|
||||
<Binding ElementName="thisPdfViewer" Path="PdfDocumentWrapper" />
|
||||
<Binding />
|
||||
</MultiBinding>
|
||||
</Image.DataContext>
|
||||
@@ -64,9 +71,7 @@
|
||||
-->
|
||||
</Grid>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger
|
||||
Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"
|
||||
Value="True">
|
||||
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True">
|
||||
<Setter TargetName="bbd" Property="BorderBrush" Value="#DD0027FF" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
@@ -74,8 +79,12 @@
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Grid Grid.Column="1" Background="#33FFFFFF">
|
||||
<imageViewer:ImagePanel x:Name="pagePanel" RenderMode="NearestNeighbor" ShowZoomLevelInfo="False"
|
||||
ZoomWithControlKey="True" BackgroundVisibility="Collapsed" MetaIconVisibility="Collapsed" />
|
||||
<imageViewer:ImagePanel x:Name="pagePanel"
|
||||
BackgroundVisibility="Collapsed"
|
||||
MetaIconVisibility="Collapsed"
|
||||
RenderMode="NearestNeighbor"
|
||||
ShowZoomLevelInfo="False"
|
||||
ZoomWithControlKey="True" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
@@ -1,20 +1,22 @@
|
||||
// Copyright © 2018 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 PdfiumViewer;
|
||||
using QuickLook.Common.ExtensionMethods;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
@@ -24,250 +26,247 @@ using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using PdfiumViewer;
|
||||
using QuickLook.Common.ExtensionMethods;
|
||||
|
||||
namespace QuickLook.Plugin.PDFViewer
|
||||
namespace QuickLook.Plugin.PDFViewer;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for PdfViewer.xaml
|
||||
/// </summary>
|
||||
public partial class PdfViewerControl : UserControl, INotifyPropertyChanged, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for PdfViewer.xaml
|
||||
/// </summary>
|
||||
public partial class PdfViewerControl : UserControl, INotifyPropertyChanged, IDisposable
|
||||
private int _changePageDeltaSum;
|
||||
private bool _initPage = true;
|
||||
private double _maxZoomFactor = double.NaN;
|
||||
private double _minZoomFactor = double.NaN;
|
||||
|
||||
private bool _pdfLoaded;
|
||||
private double _viewRenderFactor = double.NaN;
|
||||
|
||||
public PdfViewerControl()
|
||||
{
|
||||
private int _changePageDeltaSum;
|
||||
private bool _initPage = true;
|
||||
private double _maxZoomFactor = double.NaN;
|
||||
private double _minZoomFactor = double.NaN;
|
||||
InitializeComponent();
|
||||
|
||||
private bool _pdfLoaded;
|
||||
private double _viewRenderFactor = double.NaN;
|
||||
// remove theme used in designer
|
||||
Resources.MergedDictionaries.RemoveAt(0);
|
||||
|
||||
public PdfViewerControl()
|
||||
listThumbnails.SelectionChanged += UpdatePageViewWhenSelectionChanged;
|
||||
|
||||
pagePanel.ZoomChanged += ReRenderCurrentPageDelayed;
|
||||
pagePanel.ImageScrolled += NavigatePage;
|
||||
}
|
||||
|
||||
public ObservableCollection<int> PageThumbnails { get; set; } = new ObservableCollection<int>();
|
||||
|
||||
public int TotalPages => PdfDocumentWrapper.PdfDocument.PageCount;
|
||||
|
||||
public int CurrentPage
|
||||
{
|
||||
get => listThumbnails.SelectedIndex;
|
||||
set
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// remove theme used in designer
|
||||
Resources.MergedDictionaries.RemoveAt(0);
|
||||
|
||||
listThumbnails.SelectionChanged += UpdatePageViewWhenSelectionChanged;
|
||||
|
||||
pagePanel.ZoomChanged += ReRenderCurrentPageDelayed;
|
||||
pagePanel.ImageScrolled += NavigatePage;
|
||||
}
|
||||
|
||||
public ObservableCollection<int> PageThumbnails { get; set; } = new ObservableCollection<int>();
|
||||
|
||||
public int TotalPages => PdfDocumentWrapper.PdfDocument.PageCount;
|
||||
|
||||
public int CurrentPage
|
||||
{
|
||||
get => listThumbnails.SelectedIndex;
|
||||
set
|
||||
{
|
||||
listThumbnails.SelectedIndex = value;
|
||||
listThumbnails.ScrollIntoView(listThumbnails.SelectedItem);
|
||||
|
||||
CurrentPageChanged?.Invoke(this, new EventArgs());
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public PdfDocumentWrapper PdfDocumentWrapper { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
if (pagePanel != null)
|
||||
{
|
||||
pagePanel.ZoomChanged -= ReRenderCurrentPageDelayed;
|
||||
pagePanel.ImageScrolled -= NavigatePage;
|
||||
}
|
||||
|
||||
_pdfLoaded = false;
|
||||
PdfDocumentWrapper?.Dispose();
|
||||
PdfDocumentWrapper = null;
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private void ReRenderCurrentPageDelayed(object sender, EventArgs e)
|
||||
{
|
||||
ReRenderCurrentPage();
|
||||
}
|
||||
|
||||
public event EventHandler CurrentPageChanged;
|
||||
|
||||
private void NavigatePage(object sender, int delta)
|
||||
{
|
||||
if (!_pdfLoaded)
|
||||
return;
|
||||
|
||||
var pos = pagePanel.GetScrollPosition();
|
||||
var size = pagePanel.GetScrollSize();
|
||||
|
||||
const double tolerance = 0.0001d;
|
||||
if (Math.Abs(pos.Y) < tolerance && delta > 0)
|
||||
{
|
||||
_changePageDeltaSum += delta;
|
||||
if (Math.Abs(_changePageDeltaSum) < 20)
|
||||
return;
|
||||
|
||||
PrevPage();
|
||||
_changePageDeltaSum = 0;
|
||||
}
|
||||
else if (Math.Abs(pos.Y - size.Height) < tolerance && delta < -0)
|
||||
{
|
||||
_changePageDeltaSum += delta;
|
||||
if (Math.Abs(_changePageDeltaSum) < 20)
|
||||
return;
|
||||
|
||||
NextPage();
|
||||
_changePageDeltaSum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void NextPage()
|
||||
{
|
||||
if (CurrentPage < TotalPages - 1)
|
||||
{
|
||||
CurrentPage++;
|
||||
pagePanel.ScrollToTop();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrevPage()
|
||||
{
|
||||
if (CurrentPage > 0)
|
||||
{
|
||||
CurrentPage--;
|
||||
pagePanel.ScrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReRenderCurrentPage()
|
||||
{
|
||||
if (!_pdfLoaded)
|
||||
return;
|
||||
|
||||
if (CurrentPage < 0 || CurrentPage >= TotalPages)
|
||||
return;
|
||||
|
||||
Debug.WriteLine($"Re-rendering page {CurrentPage}");
|
||||
|
||||
var pos = pagePanel.GetScrollPosition();
|
||||
|
||||
double factor;
|
||||
|
||||
// First time showing. Set thresholds here.
|
||||
if (double.IsNaN(_minZoomFactor) || double.IsNaN(_maxZoomFactor))
|
||||
{
|
||||
factor = Math.Min(pagePanel.ActualHeight / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Height,
|
||||
pagePanel.ActualWidth / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Width);
|
||||
_viewRenderFactor = factor;
|
||||
_minZoomFactor = 0.1 * factor;
|
||||
_maxZoomFactor = 5 * factor;
|
||||
}
|
||||
else if (pagePanel.ZoomToFit)
|
||||
{
|
||||
factor = Math.Min(pagePanel.ActualHeight / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Height,
|
||||
pagePanel.ActualWidth / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Width);
|
||||
}
|
||||
else
|
||||
{
|
||||
factor = pagePanel.ZoomFactor * _viewRenderFactor;
|
||||
factor = Math.Max(factor, _minZoomFactor);
|
||||
factor = Math.Min(factor, _maxZoomFactor);
|
||||
pagePanel.MinZoomFactor = _minZoomFactor / factor;
|
||||
pagePanel.MaxZoomFactor = _maxZoomFactor / factor;
|
||||
}
|
||||
|
||||
var image = PdfDocumentWrapper.Render(CurrentPage, factor);
|
||||
|
||||
pagePanel.Source = image;
|
||||
pagePanel.ResetZoom();
|
||||
|
||||
_viewRenderFactor = factor;
|
||||
|
||||
pagePanel.SetScrollPosition(pos);
|
||||
|
||||
Dispatcher.Delay(500, t => GC.Collect());
|
||||
}
|
||||
|
||||
private void UpdatePageViewWhenSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (!_pdfLoaded)
|
||||
return;
|
||||
|
||||
if (CurrentPage == -1)
|
||||
return;
|
||||
listThumbnails.SelectedIndex = value;
|
||||
listThumbnails.ScrollIntoView(listThumbnails.SelectedItem);
|
||||
|
||||
CurrentPageChanged?.Invoke(this, new EventArgs());
|
||||
|
||||
ReRenderCurrentPage();
|
||||
|
||||
if (_initPage)
|
||||
{
|
||||
_initPage = false;
|
||||
pagePanel.DoZoomToFit();
|
||||
}
|
||||
}
|
||||
|
||||
public static Size GetDesiredControlSizeByFirstPage(string path)
|
||||
{
|
||||
Size size;
|
||||
|
||||
using (var s = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
using (var tempHandle = PdfDocument.Load(s))
|
||||
{
|
||||
size = new Size(0, 0);
|
||||
tempHandle.PageSizes.Take(5).ForEach(p =>
|
||||
{
|
||||
size.Width = Math.Max(size.Width, p.Width);
|
||||
size.Height = Math.Max(size.Height, p.Height);
|
||||
});
|
||||
|
||||
if (tempHandle.PageCount > 1)
|
||||
size.Width += /*listThumbnails.ActualWidth*/ 150;
|
||||
}
|
||||
}
|
||||
|
||||
return new Size(size.Width * 3, size.Height * 3);
|
||||
}
|
||||
|
||||
public void LoadPdf(string path)
|
||||
{
|
||||
var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
PdfDocumentWrapper = new PdfDocumentWrapper(stream);
|
||||
_pdfLoaded = true;
|
||||
|
||||
if (PdfDocumentWrapper.PdfDocument.PageCount < 2)
|
||||
listThumbnails.Visibility = Visibility.Collapsed;
|
||||
|
||||
BeginLoadThumbnails();
|
||||
}
|
||||
|
||||
public void LoadPdf(MemoryStream stream)
|
||||
{
|
||||
stream.Position = 0;
|
||||
PdfDocumentWrapper = new PdfDocumentWrapper(stream);
|
||||
_pdfLoaded = true;
|
||||
|
||||
if (PdfDocumentWrapper.PdfDocument.PageCount < 2)
|
||||
listThumbnails.Visibility = Visibility.Collapsed;
|
||||
|
||||
BeginLoadThumbnails();
|
||||
}
|
||||
|
||||
private void BeginLoadThumbnails()
|
||||
{
|
||||
Enumerable.Range(0, PdfDocumentWrapper.PdfDocument.PageCount).ForEach(PageThumbnails.Add);
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PdfDocumentWrapper PdfDocumentWrapper { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
if (pagePanel != null)
|
||||
{
|
||||
pagePanel.ZoomChanged -= ReRenderCurrentPageDelayed;
|
||||
pagePanel.ImageScrolled -= NavigatePage;
|
||||
}
|
||||
|
||||
_pdfLoaded = false;
|
||||
PdfDocumentWrapper?.Dispose();
|
||||
PdfDocumentWrapper = null;
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private void ReRenderCurrentPageDelayed(object sender, EventArgs e)
|
||||
{
|
||||
ReRenderCurrentPage();
|
||||
}
|
||||
|
||||
public event EventHandler CurrentPageChanged;
|
||||
|
||||
private void NavigatePage(object sender, int delta)
|
||||
{
|
||||
if (!_pdfLoaded)
|
||||
return;
|
||||
|
||||
var pos = pagePanel.GetScrollPosition();
|
||||
var size = pagePanel.GetScrollSize();
|
||||
|
||||
const double tolerance = 0.0001d;
|
||||
if (Math.Abs(pos.Y) < tolerance && delta > 0)
|
||||
{
|
||||
_changePageDeltaSum += delta;
|
||||
if (Math.Abs(_changePageDeltaSum) < 20)
|
||||
return;
|
||||
|
||||
PrevPage();
|
||||
_changePageDeltaSum = 0;
|
||||
}
|
||||
else if (Math.Abs(pos.Y - size.Height) < tolerance && delta < -0)
|
||||
{
|
||||
_changePageDeltaSum += delta;
|
||||
if (Math.Abs(_changePageDeltaSum) < 20)
|
||||
return;
|
||||
|
||||
NextPage();
|
||||
_changePageDeltaSum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void NextPage()
|
||||
{
|
||||
if (CurrentPage < TotalPages - 1)
|
||||
{
|
||||
CurrentPage++;
|
||||
pagePanel.ScrollToTop();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrevPage()
|
||||
{
|
||||
if (CurrentPage > 0)
|
||||
{
|
||||
CurrentPage--;
|
||||
pagePanel.ScrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReRenderCurrentPage()
|
||||
{
|
||||
if (!_pdfLoaded)
|
||||
return;
|
||||
|
||||
if (CurrentPage < 0 || CurrentPage >= TotalPages)
|
||||
return;
|
||||
|
||||
Debug.WriteLine($"Re-rendering page {CurrentPage}");
|
||||
|
||||
var pos = pagePanel.GetScrollPosition();
|
||||
|
||||
double factor;
|
||||
|
||||
// First time showing. Set thresholds here.
|
||||
if (double.IsNaN(_minZoomFactor) || double.IsNaN(_maxZoomFactor))
|
||||
{
|
||||
factor = Math.Min(pagePanel.ActualHeight / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Height,
|
||||
pagePanel.ActualWidth / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Width);
|
||||
_viewRenderFactor = factor;
|
||||
_minZoomFactor = 0.1 * factor;
|
||||
_maxZoomFactor = 5 * factor;
|
||||
}
|
||||
else if (pagePanel.ZoomToFit)
|
||||
{
|
||||
factor = Math.Min(pagePanel.ActualHeight / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Height,
|
||||
pagePanel.ActualWidth / PdfDocumentWrapper.PdfDocument.PageSizes[CurrentPage].Width);
|
||||
}
|
||||
else
|
||||
{
|
||||
factor = pagePanel.ZoomFactor * _viewRenderFactor;
|
||||
factor = Math.Max(factor, _minZoomFactor);
|
||||
factor = Math.Min(factor, _maxZoomFactor);
|
||||
pagePanel.MinZoomFactor = _minZoomFactor / factor;
|
||||
pagePanel.MaxZoomFactor = _maxZoomFactor / factor;
|
||||
}
|
||||
|
||||
var image = PdfDocumentWrapper.Render(CurrentPage, factor);
|
||||
|
||||
pagePanel.Source = image;
|
||||
pagePanel.ResetZoom();
|
||||
|
||||
_viewRenderFactor = factor;
|
||||
|
||||
pagePanel.SetScrollPosition(pos);
|
||||
|
||||
Dispatcher.Delay(500, t => GC.Collect());
|
||||
}
|
||||
|
||||
private void UpdatePageViewWhenSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (!_pdfLoaded)
|
||||
return;
|
||||
|
||||
if (CurrentPage == -1)
|
||||
return;
|
||||
|
||||
CurrentPageChanged?.Invoke(this, new EventArgs());
|
||||
|
||||
ReRenderCurrentPage();
|
||||
|
||||
if (_initPage)
|
||||
{
|
||||
_initPage = false;
|
||||
pagePanel.DoZoomToFit();
|
||||
}
|
||||
}
|
||||
|
||||
public static Size GetDesiredControlSizeByFirstPage(string path)
|
||||
{
|
||||
Size size;
|
||||
|
||||
using (var s = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
using (var tempHandle = PdfDocument.Load(s))
|
||||
{
|
||||
size = new Size(0, 0);
|
||||
tempHandle.PageSizes.Take(5).ForEach(p =>
|
||||
{
|
||||
size.Width = Math.Max(size.Width, p.Width);
|
||||
size.Height = Math.Max(size.Height, p.Height);
|
||||
});
|
||||
|
||||
if (tempHandle.PageCount > 1)
|
||||
size.Width += /*listThumbnails.ActualWidth*/ 150;
|
||||
}
|
||||
}
|
||||
|
||||
return new Size(size.Width * 3, size.Height * 3);
|
||||
}
|
||||
|
||||
public void LoadPdf(string path)
|
||||
{
|
||||
var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
PdfDocumentWrapper = new PdfDocumentWrapper(stream);
|
||||
_pdfLoaded = true;
|
||||
|
||||
if (PdfDocumentWrapper.PdfDocument.PageCount < 2)
|
||||
listThumbnails.Visibility = Visibility.Collapsed;
|
||||
|
||||
BeginLoadThumbnails();
|
||||
}
|
||||
|
||||
public void LoadPdf(MemoryStream stream)
|
||||
{
|
||||
stream.Position = 0;
|
||||
PdfDocumentWrapper = new PdfDocumentWrapper(stream);
|
||||
_pdfLoaded = true;
|
||||
|
||||
if (PdfDocumentWrapper.PdfDocument.PageCount < 2)
|
||||
listThumbnails.Visibility = Visibility.Collapsed;
|
||||
|
||||
BeginLoadThumbnails();
|
||||
}
|
||||
|
||||
private void BeginLoadThumbnails()
|
||||
{
|
||||
Enumerable.Range(0, PdfDocumentWrapper.PdfDocument.PageCount).ForEach(PageThumbnails.Add);
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
|
@@ -1,106 +1,105 @@
|
||||
// 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 QuickLook.Common.Plugin;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Text;
|
||||
using System.Windows.Threading;
|
||||
using QuickLook.Common.Plugin;
|
||||
|
||||
namespace QuickLook.Plugin.PDFViewer
|
||||
namespace QuickLook.Plugin.PDFViewer;
|
||||
|
||||
public class Plugin : IViewer
|
||||
{
|
||||
public class Plugin : IViewer
|
||||
private ContextObject _context;
|
||||
private string _path;
|
||||
private PdfViewerControl _pdfControl;
|
||||
|
||||
public int Priority => 0;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
private ContextObject _context;
|
||||
private string _path;
|
||||
private PdfViewerControl _pdfControl;
|
||||
}
|
||||
|
||||
public int Priority => 0;
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
return false;
|
||||
|
||||
public void Init()
|
||||
if (File.Exists(path) && Path.GetExtension(path).ToLower() == ".pdf")
|
||||
return true;
|
||||
|
||||
using (var br = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)))
|
||||
{
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
return false;
|
||||
|
||||
if (File.Exists(path) && Path.GetExtension(path).ToLower() == ".pdf")
|
||||
return true;
|
||||
|
||||
using (var br = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)))
|
||||
{
|
||||
return Encoding.ASCII.GetString(br.ReadBytes(4)) == "%PDF";
|
||||
}
|
||||
}
|
||||
|
||||
public void Prepare(string path, ContextObject context)
|
||||
{
|
||||
_context = context;
|
||||
_path = path;
|
||||
|
||||
var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(path);
|
||||
|
||||
context.SetPreferredSizeFit(desiredSize, 0.9);
|
||||
}
|
||||
|
||||
public void View(string path, ContextObject context)
|
||||
{
|
||||
_pdfControl = new PdfViewerControl();
|
||||
context.ViewerContent = _pdfControl;
|
||||
|
||||
Exception exception = null;
|
||||
|
||||
_pdfControl.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_pdfControl.LoadPdf(path);
|
||||
|
||||
context.Title = $"1 / {_pdfControl.TotalPages}: {Path.GetFileName(path)}";
|
||||
|
||||
_pdfControl.CurrentPageChanged += UpdateWindowCaption;
|
||||
context.IsBusy = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exception = e;
|
||||
}
|
||||
}), DispatcherPriority.Loaded).Wait();
|
||||
|
||||
if (exception != null)
|
||||
ExceptionDispatchInfo.Capture(exception).Throw();
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
_pdfControl?.Dispose();
|
||||
_pdfControl = null;
|
||||
|
||||
_context = null;
|
||||
}
|
||||
|
||||
private void UpdateWindowCaption(object sender, EventArgs e2)
|
||||
{
|
||||
_context.Title = $"{_pdfControl.CurrentPage + 1} / {_pdfControl.TotalPages}: {Path.GetFileName(_path)}";
|
||||
return Encoding.ASCII.GetString(br.ReadBytes(4)) == "%PDF";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Prepare(string path, ContextObject context)
|
||||
{
|
||||
_context = context;
|
||||
_path = path;
|
||||
|
||||
var desiredSize = PdfViewerControl.GetDesiredControlSizeByFirstPage(path);
|
||||
|
||||
context.SetPreferredSizeFit(desiredSize, 0.9);
|
||||
}
|
||||
|
||||
public void View(string path, ContextObject context)
|
||||
{
|
||||
_pdfControl = new PdfViewerControl();
|
||||
context.ViewerContent = _pdfControl;
|
||||
|
||||
Exception exception = null;
|
||||
|
||||
_pdfControl.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_pdfControl.LoadPdf(path);
|
||||
|
||||
context.Title = $"1 / {_pdfControl.TotalPages}: {Path.GetFileName(path)}";
|
||||
|
||||
_pdfControl.CurrentPageChanged += UpdateWindowCaption;
|
||||
context.IsBusy = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exception = e;
|
||||
}
|
||||
}), DispatcherPriority.Loaded).Wait();
|
||||
|
||||
if (exception != null)
|
||||
ExceptionDispatchInfo.Capture(exception).Throw();
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
_pdfControl?.Dispose();
|
||||
_pdfControl = null;
|
||||
|
||||
_context = null;
|
||||
}
|
||||
|
||||
private void UpdateWindowCaption(object sender, EventArgs e2)
|
||||
{
|
||||
_context.Title = $"{_pdfControl.CurrentPage + 1} / {_pdfControl.TotalPages}: {Path.GetFileName(_path)}";
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user