From a6c077fbbb2ee568b0ea9cfaa264b9683580725b Mon Sep 17 00:00:00 2001 From: ema Date: Tue, 8 Jul 2025 22:28:08 +0800 Subject: [PATCH] Add Pixso (.pip, .pix) support to ThumbnailViewer --- .../QuickLook.Plugin.TextViewer/Plugin.cs | 4 +- .../Handler.cs | 40 +++++++++++++++++++ .../Plugin.cs | 1 + 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/QuickLook.Plugin/QuickLook.Plugin.TextViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.TextViewer/Plugin.cs index 0668e65..87d6bb1 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.TextViewer/Plugin.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.TextViewer/Plugin.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Controls; @@ -48,7 +49,7 @@ public class Plugin : IViewer if (WellKnownExtensions.Any(ext => path.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return true; - // Read the first 16KB, check if we can get something. + // Read the first 16KB, check if we can get something using var s = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); const int bufferLength = 16 * 1024; var buffer = new byte[bufferLength]; @@ -91,6 +92,7 @@ public class Plugin : IViewer _tvp = null; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsText(IReadOnlyList buffer, int size) { for (var i = 1; i < size; i++) diff --git a/QuickLook.Plugin/QuickLook.Plugin.ThumbnailViewer/Handler.cs b/QuickLook.Plugin/QuickLook.Plugin.ThumbnailViewer/Handler.cs index b9649bc..a32af81 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ThumbnailViewer/Handler.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ThumbnailViewer/Handler.cs @@ -60,6 +60,20 @@ internal static class Handler context.PreferredSize = new Size { Width = 100, Height = 100 }; } } + else if (path.EndsWith(".pip", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".pix", StringComparison.OrdinalIgnoreCase)) + { + try + { + using Stream imageData = ViewImage(path); + BitmapImage bitmap = imageData.ReadAsBitmapImage(); + context.SetPreferredSizeFit(new Size(bitmap.PixelWidth, bitmap.PixelHeight), 0.8d); + } + catch (Exception e) + { + _ = e; + context.PreferredSize = new Size { Width = 100, Height = 100 }; + } + } else if (path.EndsWith(".xmind", StringComparison.OrdinalIgnoreCase)) { try @@ -155,6 +169,32 @@ internal static class Handler StreamResourceInfo info = Application.GetResourceStream(new Uri("pack://application:,,,/QuickLook.Plugin.ThumbnailViewer;component/Resources/broken.png")); return info?.Stream; } + else if (path.EndsWith(".pip", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".pix", StringComparison.OrdinalIgnoreCase)) + { + 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 + { + /// + } + + StreamResourceInfo info = Application.GetResourceStream(new Uri("pack://application:,,,/QuickLook.Plugin.ThumbnailViewer;component/Resources/broken.png")); + return info?.Stream; + } else if (path.EndsWith(".xmind", StringComparison.OrdinalIgnoreCase)) { using ZipArchive archive = ZipArchive.Open(path, new()); diff --git a/QuickLook.Plugin/QuickLook.Plugin.ThumbnailViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.ThumbnailViewer/Plugin.cs index 617f6f1..f1ec99b 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ThumbnailViewer/Plugin.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ThumbnailViewer/Plugin.cs @@ -33,6 +33,7 @@ public class Plugin : IViewer ".cdr", // CorelDraw ".fig", // Figma ".kra", // Krita + ".pip", ".pix", // Pixso ".xd", // AdobeXD ".xmind", // XMind ]);