diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Plugin.cs index 9e05d8e..1bbefc8 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Plugin.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Plugin.cs @@ -48,7 +48,7 @@ public class Plugin : IViewer ".pbm", ".pcx", ".pef", ".pgm", ".png", ".pnm", ".ppm", ".psb", ".psd", ".ptx", ".pxn", ".qoi", ".r3d", ".raf", ".raw", ".rw2", ".rwl", ".rwz", - ".sr2", ".srf", ".srw", ".svg", ".svgz", + ".sr2", ".srf", ".srw", ".svg", ".svga", ".svgz", ".tga", ".tif", ".tiff", ".wdp", ".webp", ".wmf", ".x3f", ".xcf", ".xbm", ".xpm", @@ -114,7 +114,8 @@ public class Plugin : IViewer public void Prepare(string path, ContextObject context) { - if (path.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)) + if (path.EndsWith(".svg", StringComparison.OrdinalIgnoreCase) + || path.EndsWith(".svga", StringComparison.OrdinalIgnoreCase)) { if (SettingHelper.Get("RenderSvgWeb", true, "QuickLook.Plugin.ImageViewer")) { @@ -145,7 +146,8 @@ public class Plugin : IViewer public void View(string path, ContextObject context) { - if (path.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)) + if (path.EndsWith(".svg", StringComparison.OrdinalIgnoreCase) + || path.EndsWith(".svga", StringComparison.OrdinalIgnoreCase)) { if (SettingHelper.Get("RenderSvgWeb", true, "QuickLook.Plugin.ImageViewer")) { diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/QuickLook.Plugin.ImageViewer.csproj b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/QuickLook.Plugin.ImageViewer.csproj index 9d7f868..1f347fb 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/QuickLook.Plugin.ImageViewer.csproj +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/QuickLook.Plugin.ImageViewer.csproj @@ -91,7 +91,7 @@ - + QuickLook.Plugin.ImageViewer.Resources.%(RecursiveDir)%(Filename)%(Extension) diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Resources/svga2html.html b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Resources/svga2html.html new file mode 100644 index 0000000..22349b2 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Resources/svga2html.html @@ -0,0 +1,24 @@ + + + + + + SVGA Preview + + + + + + + + diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Resources/svga2html.js b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Resources/svga2html.js new file mode 100644 index 0000000..8e6bcfa --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/Resources/svga2html.js @@ -0,0 +1,39 @@ +/** + * SvgaViewer: Provides SVGA animation preview with the following features. + * + * Requirements: + * - Requires the following HTML structure: + * + * + * - SVGA file path is obtained via chrome.webview.hostObjects.external.GetPath() + * + * Features: + * - Loads and plays SVGA animation files + * - Uses SVGA.js library for parsing and playback + * - Automatically starts playback after loading + * - Handles asynchronous loading and mounting of SVGA files +*/ +class SvgaViewer { + constructor() { + } + + /** + * Play SVGA file. + * @async + */ + async play() { + const path = await chrome.webview.hostObjects.external.GetPath(); + const parser = new SVGA.Parser(); + + // Because the path is a local file, we need to convert it to a URL format + parser.load('https://' + path).then(svga => { + const player = new SVGA.Player(document.getElementById('canvas')); + player.mount(svga).then(() => { + player.start(); + }); + }); + } +} + +// Create the SVGA viewer and play +new SvgaViewer().play(); diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/SvgImagePanel.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/SvgImagePanel.cs index aece289..3a79700 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/SvgImagePanel.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/SvgImagePanel.cs @@ -99,7 +99,7 @@ public class SvgImagePanel : WebpagePanel ObjectForScripting ??= new ScriptHandler(path); - _homePage = _resources["/svg2html.html"]; + _homePage = _resources[path.EndsWith(".svga", StringComparison.OrdinalIgnoreCase) ? "/svga2html.html" : "/svg2html.html"]; NavigateToUri(new Uri("file://quicklook/")); } @@ -145,6 +145,21 @@ public class SvgImagePanel : WebpagePanel } } } + else if (requestedUri.Scheme == "https") + { + var localPath = $"{requestedUri.Authority}:{requestedUri.AbsolutePath}".Replace('/', '\\'); + + if (localPath.StartsWith(_fallbackPath, StringComparison.OrdinalIgnoreCase)) + { + if (File.Exists(localPath)) + { + var fileStream = File.OpenRead(localPath); + var response = _webView.CoreWebView2.Environment.CreateWebResourceResponse( + fileStream, 200, "OK", MimeTypes.GetContentType() + "\r\nAccess-Control-Allow-Origin: *"); + args.Response = response; + } + } + } } catch (Exception e) { @@ -197,6 +212,16 @@ public sealed class ScriptHandler(string path) { public string Path { get; } = path; + public async Task GetPath() + { + return await Task.FromResult(new Uri(Path).AbsolutePath); + } + + public async Task GetUri() + { + return await Task.FromResult(new Uri(Path).AbsoluteUri); + } + public async Task GetSvgContent() { if (File.Exists(Path)) diff --git a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/SvgMetaProvider.cs b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/SvgMetaProvider.cs index 8e11179..20060e8 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/SvgMetaProvider.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.ImageViewer/SvgMetaProvider.cs @@ -23,38 +23,42 @@ public class SvgMetaProvider(string path) { return _size; } - try + + if (_path.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)) { - var svgContent = File.ReadAllText(_path); - var svg = XElement.Parse(svgContent); - XNamespace ns = svg.Name.Namespace; - - string widthAttr = svg.Attribute("width")?.Value; - string heightAttr = svg.Attribute("height")?.Value; - - float? width = TryParseSvgLength(widthAttr); - float? height = TryParseSvgLength(heightAttr); - - if (width.HasValue && height.HasValue) + try { - _size = new Size { Width = width.Value, Height = height.Value }; - } + var svgContent = File.ReadAllText(_path); + var svg = XElement.Parse(svgContent); + XNamespace ns = svg.Name.Namespace; - string viewBoxAttr = svg.Attribute("viewBox")?.Value; - if (!string.IsNullOrEmpty(viewBoxAttr)) - { - var parts = viewBoxAttr.Split([' ', ','], StringSplitOptions.RemoveEmptyEntries); - if (parts.Length == 4 && - float.TryParse(parts[2], out float vbWidth) && - float.TryParse(parts[3], out float vbHeight)) + string widthAttr = svg.Attribute("width")?.Value; + string heightAttr = svg.Attribute("height")?.Value; + + float? width = TryParseSvgLength(widthAttr); + float? height = TryParseSvgLength(heightAttr); + + if (width.HasValue && height.HasValue) { - _size = new Size { Width = vbWidth, Height = vbHeight }; + _size = new Size { Width = width.Value, Height = height.Value }; + } + + string viewBoxAttr = svg.Attribute("viewBox")?.Value; + if (!string.IsNullOrEmpty(viewBoxAttr)) + { + var parts = viewBoxAttr.Split([' ', ','], StringSplitOptions.RemoveEmptyEntries); + if (parts.Length == 4 && + float.TryParse(parts[2], out float vbWidth) && + float.TryParse(parts[3], out float vbHeight)) + { + _size = new Size { Width = vbWidth, Height = vbHeight }; + } } } - } - catch (Exception e) - { - Debug.WriteLine(e); + catch (Exception e) + { + Debug.WriteLine(e); + } } return _size;