Compare commits

..

4 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
f79422e795 Fix Mermaid diagram rendering by updating markdown-it highlight function
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
2025-08-01 18:05:19 +00:00
ema
e5fc61c795 Replace the mermaid.min.js
https://cdn.jsdelivr.net/npm/mermaid@11.4.1/dist/mermaid.min.js
2025-08-02 01:56:08 +08:00
copilot-swe-agent[bot]
5bb15aee41 Implement Mermaid diagram support for MarkdownViewer
Co-authored-by: emako <24737061+emako@users.noreply.github.com>
2025-08-01 17:01:46 +00:00
copilot-swe-agent[bot]
079ecd5464 Initial plan 2025-08-01 16:50:42 +00:00
30 changed files with 347 additions and 1063 deletions

View File

@@ -36,7 +36,6 @@
"IsRefreshExplorer": true,
"IsInstallCertificate": false,
"IsEnableUninstallDelayUntilReboot": true,
"IsUseTempPathFork": false,
"IsEnvironmentVariable": false,
"OverlayInstallRemoveExt": "exe,dll,pdb,config,winmd,txt,bat,ax,manifest,xshd",
"UnpackingPassword": null,

View File

@@ -59,19 +59,21 @@ public class AnimatedImage : Image, IDisposable
return provider;
}
#region DependencyProperty
public static readonly DependencyProperty AnimationFrameIndexProperty =
DependencyProperty.Register(nameof(AnimationFrameIndex), typeof(int), typeof(AnimatedImage),
DependencyProperty.Register("AnimationFrameIndex", typeof(int), typeof(AnimatedImage),
new UIPropertyMetadata(-1, AnimationFrameIndexChanged));
public static readonly DependencyProperty AnimationUriProperty =
DependencyProperty.Register(nameof(AnimationUri), typeof(Uri), typeof(AnimatedImage),
DependencyProperty.Register("AnimationUri", typeof(Uri), typeof(AnimatedImage),
new UIPropertyMetadata(null, AnimationUriChanged));
public static readonly DependencyProperty MetaProperty =
DependencyProperty.Register(nameof(Meta), typeof(MetaProvider), typeof(AnimatedImage));
DependencyProperty.Register("Meta", typeof(MetaProvider), typeof(AnimatedImage));
public static readonly DependencyProperty ContextObjectProperty =
DependencyProperty.Register(nameof(ContextObject), typeof(ContextObject), typeof(AnimatedImage));
DependencyProperty.Register("ContextObject", typeof(ContextObject), typeof(AnimatedImage));
public int AnimationFrameIndex
{
@@ -102,6 +104,9 @@ public class AnimatedImage : Image, IDisposable
if (obj is not AnimatedImage instance)
return;
//var thumbnail = instance.Meta?.GetThumbnail(true);
//instance.Source = thumbnail;
instance._animation = InitAnimationProvider((Uri)ev.NewValue, instance.Meta, instance.ContextObject);
ShowThumbnailAndStartAnimation(instance);
}
@@ -156,4 +161,6 @@ public class AnimatedImage : Image, IDisposable
}));
task.Start();
}
#endregion DependencyProperty
}

View File

@@ -24,13 +24,20 @@ using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage;
internal abstract class AnimationProvider(Uri path, MetaProvider meta, ContextObject contextObject) : IDisposable
internal abstract class AnimationProvider : IDisposable
{
public Uri Path { get; } = path;
protected AnimationProvider(Uri path, MetaProvider meta, ContextObject contextObject)
{
Path = path;
Meta = meta;
ContextObject = contextObject;
}
public MetaProvider Meta { get; } = meta;
public Uri Path { get; }
public ContextObject ContextObject { get; } = contextObject;
public MetaProvider Meta { get; }
public ContextObject ContextObject { get; }
public Int32AnimationUsingKeyFrames Animator { get; protected set; }

View File

@@ -17,7 +17,6 @@
using LibAPNG;
using QuickLook.Common.ExtensionMethods;
using QuickLook.Common.Helpers;
using QuickLook.Common.Plugin;
using System;
using System.Collections.Generic;
@@ -31,28 +30,20 @@ using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage.Providers;
/// <summary>
/// This provider is only for Animated PNG.
/// The others will fall back to another provider.
/// </summary>
internal class APngProvider : AnimationProvider
{
private readonly Frame _baseFrame;
private readonly List<FrameInfo> _frames;
private readonly List<BitmapSource> _renderedFrames;
private int _lastEffectivePreviousPreviousFrameIndex;
private AnimationProvider _fallbackImageProvider;
private NativeProvider _nativeImageProvider;
public APngProvider(Uri path, MetaProvider meta, ContextObject contextObject) : base(path, meta, contextObject)
{
if (!IsAnimatedPng(path.LocalPath))
{
var useNativeProvider = SettingHelper.Get("UseNativeProvider", true, "QuickLook.Plugin.ImageViewer");
_fallbackImageProvider = useNativeProvider ?
new NativeProvider(path, meta, contextObject) :
new ImageMagickProvider(path, meta, contextObject);
Animator = _fallbackImageProvider.Animator;
_nativeImageProvider = new NativeProvider(path, meta, contextObject);
Animator = _nativeImageProvider.Animator;
return;
}
@@ -80,8 +71,8 @@ internal class APngProvider : AnimationProvider
public override Task<BitmapSource> GetThumbnail(Size renderSize)
{
if (_fallbackImageProvider != null)
return _fallbackImageProvider.GetThumbnail(renderSize);
if (_nativeImageProvider != null)
return _nativeImageProvider.GetThumbnail(renderSize);
return new Task<BitmapSource>(() =>
{
@@ -94,8 +85,8 @@ internal class APngProvider : AnimationProvider
public override Task<BitmapSource> GetRenderedFrame(int index)
{
if (_fallbackImageProvider != null)
return _fallbackImageProvider.GetRenderedFrame(index);
if (_nativeImageProvider != null)
return _nativeImageProvider.GetRenderedFrame(index);
if (_renderedFrames[index] != null)
return new Task<BitmapSource>(() => _renderedFrames[index]);
@@ -111,10 +102,10 @@ internal class APngProvider : AnimationProvider
public override void Dispose()
{
if (_fallbackImageProvider != null)
if (_nativeImageProvider != null)
{
_fallbackImageProvider.Dispose();
_fallbackImageProvider = null;
_nativeImageProvider.Dispose();
_nativeImageProvider = null;
return;
}
@@ -223,7 +214,7 @@ internal class APngProvider : AnimationProvider
return false;
}
static uint ToUInt32BE(byte[] data)
uint ToUInt32BE(byte[] data)
{
Array.Reverse(data);
return BitConverter.ToUInt32(data, 0);

View File

@@ -40,6 +40,11 @@ internal class NativeProvider : AnimationProvider
public override Task<BitmapSource> GetThumbnail(Size renderSize)
{
var fullSize = Meta.GetSize();
//var decodeWidth = (int) Math.Round(fullSize.Width *
// Math.Min(renderSize.Width / 2 / fullSize.Width,
// renderSize.Height / 2 / fullSize.Height));
//var decodeHeight = (int) Math.Round(fullSize.Height / fullSize.Width * decodeWidth);
var decodeWidth =
(int)Math.Round(Math.Min(Meta.GetSize().Width, Math.Max(1d, Math.Floor(renderSize.Width))));
var decodeHeight =

View File

@@ -0,0 +1,104 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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.Helpers;
using QuickLook.Common.Plugin;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Xml.Linq;
namespace QuickLook.Plugin.ImageViewer.AnimatedImage.Providers;
internal class PdnProvider : AnimationProvider
{
public PdnProvider(Uri path, MetaProvider meta, ContextObject contextObject) : base(path, meta, contextObject)
{
Animator = new Int32AnimationUsingKeyFrames();
Animator.KeyFrames.Add(new DiscreteInt32KeyFrame(0,
KeyTime.FromTimeSpan(TimeSpan.Zero)));
}
public override Task<BitmapSource> GetThumbnail(Size renderSize)
{
// Skip thumbnail
return new Task<BitmapSource>(() => null);
}
public override Task<BitmapSource> GetRenderedFrame(int index)
{
return new Task<BitmapSource>(() =>
{
try
{
using TextReader reader = new StreamReader(Path.LocalPath, Encoding.UTF8);
string line = reader.ReadLine();
if (!line.StartsWith("PDN"))
return null;
int indexOfStart = line.IndexOf("<");
int indexOfEnd = line.LastIndexOf(">");
if (indexOfStart < 0 || indexOfEnd < 0)
return null;
string xml = line.Substring(indexOfStart, indexOfEnd - indexOfStart + 1);
// <pdnImage>
// <custom>
// <thumb png="..." />
// </custom>
// </pdnImage>
XDocument doc = XDocument.Parse(xml);
var pngBase64 = doc.Root
?.Element("custom")
?.Element("thumb")
?.Attribute("png")
?.Value;
if (pngBase64 != null)
{
byte[] imageBytes = Convert.FromBase64String(pngBase64);
MemoryStream ms = new(imageBytes);
BitmapImage bitmap = new();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = ms;
bitmap.EndInit();
bitmap.Freeze();
return bitmap;
}
return null;
}
catch (Exception e)
{
ProcessHelper.WriteLog(e.ToString());
return null;
}
});
}
public override void Dispose()
{
}
}

View File

@@ -103,7 +103,9 @@ public partial class ImagePanel : UserControl, INotifyPropertyChanged, IDisposab
ContextObject = context;
Meta = meta;
_ = meta.GetSize();
var s = meta.GetSize();
//_minZoomFactor = Math.Min(200d / s.Height, 400d / s.Width);
//_maxZoomFactor = Math.Min(9000d / s.Height, 9000d / s.Width);
ShowMeta();
Theme = ContextObject.Theme;

View File

@@ -65,16 +65,8 @@ public class Plugin : IViewer
public void Init()
{
// Option of UseColorProfile:
// Default is False (disable color profile conversion)
// Note that enabling this feature will slow down image previewing, especially on large images.
var useColorProfile = SettingHelper.Get("UseColorProfile", false, "QuickLook.Plugin.ImageViewer");
// Option of UseNativeProvider:
// Default is True (disable precise colors and choose faster response)
// Note that disabling this feature may slightly slow down image previewing but you can get precise colors.
var useNativeProvider = SettingHelper.Get("UseNativeProvider", true, "QuickLook.Plugin.ImageViewer");
AnimatedImage.AnimatedImage.Providers.Add(
new KeyValuePair<string[], Type>(
useColorProfile ? [".apng"] : [".apng", ".png"],
@@ -84,7 +76,7 @@ public class Plugin : IViewer
typeof(GifProvider)));
AnimatedImage.AnimatedImage.Providers.Add(
new KeyValuePair<string[], Type>(
useColorProfile ? [] : (useNativeProvider ? [".bmp", ".jpg", ".jpeg", ".jfif", ".tif", ".tiff"] : []),
useColorProfile ? [] : [".bmp", ".jpg", ".jpeg", ".jfif", ".tif", ".tiff"],
typeof(NativeProvider)));
AnimatedImage.AnimatedImage.Providers.Add(
new KeyValuePair<string[], Type>([".jxr"],

View File

@@ -22,7 +22,6 @@ using QuickLook.Plugin.HtmlViewer;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -68,7 +67,6 @@ public class SvgImagePanel : WebpagePanel, IWebImagePanel
{
UserDataFolder = Path.Combine(SettingHelper.LocalDataPath, @"WebView2_Data\"),
},
DefaultBackgroundColor = Color.Transparent,
};
_webView.CoreWebView2InitializationCompleted += WebView_CoreWebView2InitializationCompleted;
Content = _webView;

View File

@@ -1,16 +0,0 @@
using MediaInfoLib;
using System.ComponentModel.Composition;
namespace QuickLook.Plugin.MediaInfoViewer;
[Export]
public static class Exporter
{
public static MediaInfo Open(string path)
{
MediaInfo lib = new MediaInfo()
.WithOpen(path);
return lib;
}
}

View File

@@ -1,109 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 MediaInfoLib;
using QuickLook.Common.Helpers;
using QuickLook.Common.Plugin;
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media;
namespace QuickLook.Plugin.MediaInfoViewer;
public class Plugin : IViewer
{
private TextViewerPanel _tvp;
public int Priority => 0;
public void Init()
{
}
public bool CanHandle(string path)
{
// We only handle files with specific caller
return false;
}
public void Prepare(string path, ContextObject context)
{
context.PreferredSize = new Size { Width = 800, Height = 600 };
}
public void View(string path, ContextObject context)
{
using MediaInfo lib = new MediaInfo()
.WithOpen(path);
_tvp = new TextViewerPanel(lib.Inform(), context);
AssignHighlightingManager(_tvp, context);
_tvp.Tag = context;
_tvp.Drop += OnDrop;
context.ViewerContent = _tvp;
context.Title = $"{Path.GetFileName(path)}";
context.IsBusy = false;
}
private void OnDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
if (e.Data.GetData(DataFormats.FileDrop) is string[] files
&& files.FirstOrDefault() is string path)
{
if (_tvp!.Tag is ContextObject context)
{
context.Title = $"{Path.GetFileName(path)}";
}
using MediaInfo lib = new MediaInfo()
.WithOpen(path);
_tvp!.Text = lib.Inform();
}
}
}
public void Cleanup()
{
GC.SuppressFinalize(this);
_tvp = null!;
}
private void AssignHighlightingManager(TextViewerPanel tvp, ContextObject context)
{
var isDark = OSThemeHelper.AppsUseDarkTheme();
if (isDark)
{
context.Theme = Themes.Dark;
tvp.Foreground = new BrushConverter().ConvertFromString("#FFEFEFEF") as SolidColorBrush;
tvp.Background = Brushes.Transparent;
}
else
{
context.Theme = Themes.Light;
tvp.Foreground = new BrushConverter().ConvertFromString("#BBFAFAFA") as SolidColorBrush;
tvp.Background = Brushes.Transparent;
}
}
}

View File

@@ -1,50 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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.MediaInfoViewer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("pooi.moe")]
[assembly: AssemblyProduct("QuickLook.Plugin.MediaInfoViewer")]
[assembly: AssemblyCopyright("Copyright © 2017-2025 QL-Win Contributors")]
[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("b0054a16-472e-44ac-ba40-349303e524ff")]
// 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

@@ -1,84 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net462</TargetFramework>
<RootNamespace>QuickLook.Plugin.MediaInfoViewer</RootNamespace>
<AssemblyName>QuickLook.Plugin.MediaInfoViewer</AssemblyName>
<FileAlignment>512</FileAlignment>
<SignAssembly>false</SignAssembly>
<UseWPF>true</UseWPF>
<LangVersion>latest</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<ProjectGuid>{B0054A16-472E-44AC-BA40-349303E524FF}</ProjectGuid>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<OutputPath>..\..\Build\Debug\QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>..\..\Build\Release\QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\QuickLook.Common\QuickLook.Common.csproj">
<Project>{85FDD6BA-871D-46C8-BD64-F6BB0CB5EA95}</Project>
<Name>QuickLook.Common</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\GitVersion.cs">
<Link>Properties\GitVersion.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System.ComponentModel.Composition" />
<PackageReference Include="MediaInfoDLL" Version="25.7.0" />
</ItemGroup>
<Target Name="ReduceReleasePackaging" AfterTargets="Build">
<!-- MediaInfoDLL will copy the MediaInfo.dll file according to the architecture, we do not use this usage so delete it manually -->
<Delete Files="$(OutputPath)\MediaInfo.dll" Condition="Exists('$(OutputPath)\MediaInfo.dll')" />
</Target>
<ItemGroup>
<None Update="Translations.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -1,100 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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.Helpers;
using QuickLook.Common.Plugin;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace QuickLook.Plugin.MediaInfoViewer;
public class TextViewerPanel : TextBox
{
public TextViewerPanel(string text, ContextObject context)
{
_ = context;
TextWrapping = TextWrapping.Wrap;
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
Margin = new Thickness(8d, 0d, 0d, 0d);
BorderThickness = new Thickness(0d);
FontSize = 14d;
IsReadOnly = true;
IsManipulationEnabled = true;
ContextMenu = new ContextMenu();
ContextMenu.Items.Add(new MenuItem
{
Header = TranslationHelper.Get("Editor_Copy", domain: "QuickLook.Plugin.TextViewer"),
Command = ApplicationCommands.Copy,
});
ContextMenu.Items.Add(new MenuItem
{
Header = TranslationHelper.Get("Editor_SelectAll",
domain: "QuickLook.Plugin.TextViewer"),
Command = ApplicationCommands.SelectAll,
});
ManipulationInertiaStarting += Viewer_ManipulationInertiaStarting;
ManipulationStarting += Viewer_ManipulationStarting;
ManipulationDelta += Viewer_ManipulationDelta;
PreviewMouseWheel += Viewer_MouseWheel;
FontFamily = new FontFamily("Consolas, " + TranslationHelper.Get("Editor_FontFamily",
domain: "QuickLook.Plugin.TextViewer"));
LoadTextAsync(text);
}
private void Viewer_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
{
e.TranslationBehavior = new InertiaTranslationBehavior
{
InitialVelocity = e.InitialVelocities.LinearVelocity,
DesiredDeceleration = 10d * 96d / (1000d * 1000d)
};
}
private void Viewer_MouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = true;
ScrollToVerticalOffset(VerticalOffset - e.Delta);
}
private void Viewer_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
e.Handled = true;
var delta = e.DeltaManipulation;
ScrollToVerticalOffset(VerticalOffset - delta.Translation.Y);
}
private void Viewer_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
{
e.Mode = ManipulationModes.Translate;
}
private void LoadTextAsync(string text)
{
Text = text;
}
}

View File

@@ -15,9 +15,16 @@
// 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using QuickLook.Common.Plugin;
using QuickLook.Plugin.ThumbnailViewer.Providors;
using System;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ThumbnailViewer;
@@ -25,33 +32,131 @@ internal static class Handler
{
public static void Prepare(string path, ContextObject context)
{
(Path.GetExtension(path).ToLower() switch
try
{
".cdr" => new CdrProvider(),
".fig" => new FigProvidor(),
".kra" => new KraProvidor(),
".pdn" => new PdnProvider(),
".pip" or ".pix" => new PixProvidor(),
".sketch" => new SketchProvidor(),
".xd" => new XdProvidor(),
".xmind" => new XmindProvidor(),
_ => (AbstractProvidor)null,
})?.Prepare(path, context);
using Stream imageData = ViewImage(path);
BitmapImage bitmap = imageData.ReadAsBitmapImage();
context.SetPreferredSizeFit(new Size(bitmap.PixelWidth, bitmap.PixelHeight), 0.8d);
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
context.PreferredSize = new Size { Width = 800, Height = 600 };
}
}
public static Stream ViewImage(string path)
{
return (Path.GetExtension(path).ToLower() switch
try
{
".cdr" => new CdrProvider(),
".fig" => new FigProvidor(),
".kra" => new KraProvidor(),
".pdn" => new PdnProvider(),
".pip" or ".pix" => new PixProvidor(),
".sketch" => new SketchProvidor(),
".xd" => new XdProvidor(),
".xmind" => new XmindProvidor(),
_ => (AbstractProvidor)null,
})?.ViewImage(path);
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
if (path.EndsWith(".xd", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("preview.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
else if (reader.Entry.Key!.Equals("thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".fig", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".pip", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".pix", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.EndsWith(".thumb.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".sketch", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.EndsWith("previews/preview.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".xmind", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("Thumbnails/thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".kra", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Contains("mergedimage"))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
else if (path.EndsWith(".cdr", StringComparison.OrdinalIgnoreCase))
{
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("previews/thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -34,7 +34,6 @@ public class Plugin : IViewer
".cdr", // CorelDraw
".fig", // Figma
".kra", // Krita
".pdn", // Paint.NET
".pip", ".pix", // Pixso
".sketch", // Sketch
".xd", // AdobeXD

View File

@@ -1,45 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal abstract class AbstractProvidor
{
public virtual void Prepare(string path, ContextObject context)
{
try
{
using Stream imageData = ViewImage(path);
BitmapImage bitmap = imageData.ReadAsBitmapImage();
context.SetPreferredSizeFit(new Size(bitmap.PixelWidth, bitmap.PixelHeight), 0.8d);
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
context.PreferredSize = new Size { Width = 800, Height = 600 };
}
}
public abstract Stream ViewImage(string path);
}

View File

@@ -1,56 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class CdrProvider : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("previews/thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -1,56 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class FigProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -1,56 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class KraProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Contains("mergedimage"))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -1,73 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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.Helpers;
using System;
using System.IO;
using System.Text;
using System.Xml.Linq;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class PdnProvider : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using TextReader reader = new StreamReader(path, Encoding.UTF8);
string line = reader.ReadLine();
if (!line.StartsWith("PDN"))
return null;
int indexOfStart = line.IndexOf("<");
int indexOfEnd = line.LastIndexOf(">");
if (indexOfStart < 0 || indexOfEnd < 0)
return null;
string xml = line.Substring(indexOfStart, indexOfEnd - indexOfStart + 1);
// <pdnImage>
// <custom>
// <thumb png="..." />
// </custom>
// </pdnImage>
XDocument doc = XDocument.Parse(xml);
var pngBase64 = doc.Root
?.Element("custom")
?.Element("thumb")
?.Attribute("png")
?.Value;
if (pngBase64 != null)
{
byte[] imageBytes = Convert.FromBase64String(pngBase64);
MemoryStream ms = new(imageBytes);
return ms;
}
return null;
}
catch (Exception e)
{
ProcessHelper.WriteLog(e.ToString());
return null;
}
}
}

View File

@@ -1,56 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class PixProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.EndsWith(".thumb.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -1,56 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class SketchProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.EndsWith("previews/preview.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -1,63 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class XdProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("preview.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
else if (reader.Entry.Key!.Equals("thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -1,56 +0,0 @@
// Copyright © 2017-2025 QL-Win Contributors
//
// 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 PureSharpCompress.Archives.Zip;
using PureSharpCompress.Common;
using PureSharpCompress.Readers;
using QuickLook.Common.Helpers;
using System;
using System.Diagnostics;
using System.IO;
namespace QuickLook.Plugin.ThumbnailViewer.Providors;
internal class XmindProvidor : AbstractProvidor
{
public override Stream ViewImage(string path)
{
try
{
using ZipArchive archive = ZipArchive.Open(path, new());
using IReader reader = archive.ExtractAllEntries();
while (reader.MoveToNextEntry())
{
if (reader.Entry.Key!.Equals("Thumbnails/thumbnail.png", StringComparison.OrdinalIgnoreCase))
{
MemoryStream ms = new();
using EntryStream stream = reader.OpenEntryStream();
stream.CopyTo(ms);
return ms;
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error reading thumbnail from {path}: {ex.Message}");
ProcessHelper.WriteLog(ex.ToString());
}
return null;
}
}

View File

@@ -41,7 +41,7 @@
<PackageReference Include="MediaInfo.Wrapper" Version="21.9.3">
<Aliases>MediaInfoWrapper</Aliases>
</PackageReference>
<PackageReference Include="MediaInfoDLL" Version="25.7.0">
<PackageReference Include="MediaInfoDLL" Version="25.4.0">
<Aliases>MediaInfoDLL</Aliases>
</PackageReference>
<Reference Include="WindowsBase" />
@@ -187,17 +187,17 @@
<DestinationFolder>$(OutDir)\LAVFilters-x86\</DestinationFolder>
<Link>LAVFilters-x86\swscale-lav-8.dll</Link>
</Content>
<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.7.0\lib\netstandard2.0\x64\MediaInfo.dll">
<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.4.0\lib\netstandard2.0\x64\MediaInfo.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DestinationFolder>$(OutDir)MediaInfo-x64\</DestinationFolder>
<Link>MediaInfo-x64\MediaInfo.dll</Link>
</Content>
<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.7.0\lib\netstandard2.0\x86\MediaInfo.dll">
<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.4.0\lib\netstandard2.0\x86\MediaInfo.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DestinationFolder>$(OutDir)MediaInfo-x86\</DestinationFolder>
<Link>MediaInfo-x86\MediaInfo.dll</Link>
</Content>
<!--<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.7.0\lib\netstandard2.0\arm64\MediaInfo.dll">
<!--<Content Include="$(NuGetPackageRoot)\MediaInfoDLL\25.4.0\lib\netstandard2.0\arm64\MediaInfo.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DestinationFolder>$(OutDir)MediaInfo-ARM64\</DestinationFolder>
<Link>MediaInfo-ARM64\MediaInfo.dll</Link>

View File

@@ -56,7 +56,6 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "QuickLook.Installer", "Quic
{63C00175-0FF3-42C7-8621-2F1959F26064} = {63C00175-0FF3-42C7-8621-2F1959F26064}
{B4F7C88D-C79D-49E7-A1FB-FB69CF72585F} = {B4F7C88D-C79D-49E7-A1FB-FB69CF72585F}
{311E6E78-3A5B-4E51-802A-5755BD5F9F97} = {311E6E78-3A5B-4E51-802A-5755BD5F9F97}
{B0054A16-472E-44AC-BA40-349303E524FF} = {B0054A16-472E-44AC-BA40-349303E524FF}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickLook.Native64", "QuickLook.Native\QuickLook.Native64\QuickLook.Native64.vcxproj", "{794E4DCF-F715-4836-9D30-ABD296586D23}"
@@ -87,8 +86,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.ThumbnailV
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.HelixViewer", "QuickLook.Plugin\QuickLook.Plugin.HelixViewer\QuickLook.Plugin.HelixViewer.csproj", "{311E6E78-3A5B-4E51-802A-5755BD5F9F97}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLook.Plugin.MediaInfoViewer", "QuickLook.Plugin\QuickLook.Plugin.MediaInfoViewer\QuickLook.Plugin.MediaInfoViewer.csproj", "{B0054A16-472E-44AC-BA40-349303E524FF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -281,14 +278,6 @@ Global
{311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|Any CPU.Build.0 = Release|Any CPU
{311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|x64.ActiveCfg = Release|Any CPU
{311E6E78-3A5B-4E51-802A-5755BD5F9F97}.Release|x64.Build.0 = Release|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Debug|x64.ActiveCfg = Debug|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Debug|x64.Build.0 = Debug|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Release|Any CPU.Build.0 = Release|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Release|x64.ActiveCfg = Release|Any CPU
{B0054A16-472E-44AC-BA40-349303E524FF}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -314,7 +303,6 @@ Global
{63C00175-0FF3-42C7-8621-2F1959F26064} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
{B4F7C88D-C79D-49E7-A1FB-FB69CF72585F} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
{311E6E78-3A5B-4E51-802A-5755BD5F9F97} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
{B0054A16-472E-44AC-BA40-349303E524FF} = {06EFDBE0-6408-4B37-BCF2-0CF9EBEA2E93}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D3761C32-8C5F-498A-892B-3B0882994B62}

View File

@@ -117,8 +117,22 @@ public partial class App : Application
// Exception handling events which are not caught in the Task thread
TaskScheduler.UnobservedTaskException += (_, e) =>
{
ProcessHelper.WriteLog(e.Exception.ToString());
e.SetObserved();
try
{
ProcessHelper.WriteLog(e.Exception.ToString());
Current?.Dispatcher?.BeginInvoke(() =>
{
Wpf.Ui.Violeta.Controls.ExceptionReport.Show(e.Exception);
});
}
catch (Exception ex)
{
ProcessHelper.WriteLog(ex.ToString());
}
finally
{
e.SetObserved();
}
};
// Exception handling events which are not caught in UI thread
@@ -196,9 +210,9 @@ public partial class App : Application
}
};
// We should improve the performance of the CLI application
// Therefore, the time-consuming initialization code can't be placed before `OnStartup`
base.OnStartup(e);
// Initialize MessageBox patching
bool modernMessageBox = SettingHelper.Get("ModernMessageBox", true, "QuickLook");
if (modernMessageBox) MessageBoxPatcher.Initialize();
// Set initial theme based on system settings
ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light);
@@ -206,15 +220,17 @@ public partial class App : Application
ThemeManager.Apply(OSThemeHelper.AppsUseDarkTheme() ? ApplicationTheme.Dark : ApplicationTheme.Light);
UxTheme.ApplyPreferredAppMode();
// Initialize MessageBox patching
MessageBoxPatcher.Initialize();
// Initialize TrayIcon
_ = TrayIconManager.GetInstance();
base.OnStartup(e);
}
private void Application_Startup(object sender, StartupEventArgs e)
{
if (!EnsureOSVersion()
|| !EnsureFirstInstance(e.Args)
|| !EnsureFolderWritable(SettingHelper.LocalDataPath))
|| !EnsureFirstInstance(e.Args)
|| !EnsureFolderWritable(SettingHelper.LocalDataPath))
{
_cleanExit = false;
Shutdown();
@@ -309,10 +325,8 @@ public partial class App : Application
}
// Second instance: duplicate
else
{
MessageBox.Show(TranslationHelper.Get("APP_SECOND_TEXT"), TranslationHelper.Get("APP_SECOND"),
MessageBoxButton.OK, MessageBoxImage.Information);
}
return false;
}

View File

@@ -1 +0,0 @@
global using MessageBox = Wpf.Ui.Violeta.Controls.MessageBox;

View File

@@ -58,114 +58,64 @@ public partial class InfoPanel : UserControl
Dispatcher.BeginInvoke(new Action(() => image.Source = source));
});
string name;
try
{
name = Path.GetFileName(path);
}
catch (ArgumentException)
{
// Handle invalid path characters gracefully
name = path;
}
catch (PathTooLongException)
{
// Handle path too long scenarios
name = path;
}
var name = Path.GetFileName(path);
filename.Text = string.IsNullOrEmpty(name) ? path : name;
try
{
var last = File.GetLastWriteTime(path);
modDate.Text = string.Format(TranslationHelper.Get("InfoPanel_LastModified"),
last.ToString(CultureInfo.CurrentCulture));
}
catch (ArgumentException)
{
// Handle invalid path characters gracefully
modDate.Text = TranslationHelper.Get("InfoPanel_LastModified_Unavailable") ?? "Last modified: Unavailable";
}
catch (UnauthorizedAccessException)
{
// Handle access denied scenarios
modDate.Text = TranslationHelper.Get("InfoPanel_LastModified_Unavailable") ?? "Last modified: Unavailable";
}
catch (PathTooLongException)
{
// Handle path too long scenarios
modDate.Text = TranslationHelper.Get("InfoPanel_LastModified_Unavailable") ?? "Last modified: Unavailable";
}
var last = File.GetLastWriteTime(path);
modDate.Text = string.Format(TranslationHelper.Get("InfoPanel_LastModified"),
last.ToString(CultureInfo.CurrentCulture));
Stop = false;
_ = Task.Run(() =>
{
try
if (File.Exists(path))
{
if (File.Exists(path))
{
var size = new FileInfo(path).Length;
var size = new FileInfo(path).Length;
Dispatcher.Invoke(() => { totalSize.Text = size.ToPrettySize(2); });
}
else if (Path.GetPathRoot(path) == path) // is this a drive?
{
FileHelper.GetDriveSpace(path, out var totalSpace, out var totalFreeSpace);
Dispatcher.Invoke(() => { totalSize.Text = size.ToPrettySize(2); });
}
else if (Path.GetPathRoot(path) == path) // is this a drive?
{
FileHelper.GetDriveSpace(path, out var totalSpace, out var totalFreeSpace);
Dispatcher.Invoke(() =>
{
totalSize.Text =
string.Format(TranslationHelper.Get("InfoPanel_DriveSize"),
totalSpace.ToPrettySize(2),
totalFreeSpace.ToPrettySize(2));
});
}
else if (Directory.Exists(path))
{
FileHelper.CountFolder(path, ref _stop,
out var totalDirsL, out var totalFilesL, out var totalSizeL);
if (!Stop)
Dispatcher.Invoke(() =>
{
string t;
var folders = totalDirsL == 0
? string.Empty
: string.Format(TranslationHelper.Get(
totalDirsL == 1 ? "InfoPanel_Folder" : "InfoPanel_Folders"), totalDirsL);
var files = totalFilesL == 0
? string.Empty
: string.Format(TranslationHelper.Get(
totalFilesL == 1 ? "InfoPanel_File" : "InfoPanel_Files"), totalFilesL);
if (!string.IsNullOrEmpty(folders) && !string.IsNullOrEmpty(files))
t = string.Format(
TranslationHelper.Get("InfoPanel_FolderAndFile"), folders, files);
else if (string.IsNullOrEmpty(folders) && string.IsNullOrEmpty(files))
t = string.Empty;
else
t = $"({folders}{files})";
totalSize.Text =
string.Format(TranslationHelper.Get("InfoPanel_DriveSize"),
totalSpace.ToPrettySize(2),
totalFreeSpace.ToPrettySize(2));
$"{totalSizeL.ToPrettySize(2)} {t}";
});
}
else if (Directory.Exists(path))
{
FileHelper.CountFolder(path, ref _stop,
out var totalDirsL, out var totalFilesL, out var totalSizeL);
if (!Stop)
Dispatcher.Invoke(() =>
{
string t;
var folders = totalDirsL == 0
? string.Empty
: string.Format(TranslationHelper.Get(
totalDirsL == 1 ? "InfoPanel_Folder" : "InfoPanel_Folders"), totalDirsL);
var files = totalFilesL == 0
? string.Empty
: string.Format(TranslationHelper.Get(
totalFilesL == 1 ? "InfoPanel_File" : "InfoPanel_Files"), totalFilesL);
if (!string.IsNullOrEmpty(folders) && !string.IsNullOrEmpty(files))
t = string.Format(
TranslationHelper.Get("InfoPanel_FolderAndFile"), folders, files);
else if (string.IsNullOrEmpty(folders) && string.IsNullOrEmpty(files))
t = string.Empty;
else
t = $"({folders}{files})";
totalSize.Text =
$"{totalSizeL.ToPrettySize(2)} {t}";
});
}
}
catch (ArgumentException)
{
// Handle invalid path characters gracefully
Dispatcher.Invoke(() => { totalSize.Text = "Size: Unavailable"; });
}
catch (UnauthorizedAccessException)
{
// Handle access denied scenarios
Dispatcher.Invoke(() => { totalSize.Text = "Size: Unavailable"; });
}
catch (PathTooLongException)
{
// Handle path too long scenarios
Dispatcher.Invoke(() => { totalSize.Text = "Size: Unavailable"; });
}
});
}