mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 18:26:39 +02:00
SvgPreviewControl: Add Background so that white .svg are visible (#25397)
* SvgPreviewControl: Add checkered background so that white .svg are visible * SvgPreviewControl: Move preview generation logic into own class * SvgPreviewControl: Add possibility to configure background of svg preview pane via the settings ui * SvgPreviewControl: Take user configuration into consideration when generating svg preview * SvgPreviewControl: Do not generate preview file, if the actual size is under the 2mb limiation of WebView2 * SvgPreviewControl: Introduce SvgPreviewColorMode enumeration instead of using magic values * SvgPreviewControl: Add additional checkered pattern shades * SvgPreviewControl: Use newly introduced enums as default values
This commit is contained in:
74
src/modules/previewpane/SvgPreviewHandler/Settings.cs
Normal file
74
src/modules/previewpane/SvgPreviewHandler/Settings.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
|
||||
namespace SvgPreviewHandler
|
||||
{
|
||||
internal sealed class Settings
|
||||
{
|
||||
private static readonly SettingsUtils ModuleSettings = new SettingsUtils();
|
||||
|
||||
public int ColorMode
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return ModuleSettings.GetSettings<PowerPreviewSettings>(PowerPreviewSettings.ModuleName).Properties.SvgBackgroundColorMode.Value;
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
return PowerPreviewProperties.DefaultSvgBackgroundColorMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Color SolidColor
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
var colorString = ModuleSettings.GetSettings<PowerPreviewSettings>(PowerPreviewSettings.ModuleName).Properties.SvgBackgroundSolidColor.Value;
|
||||
return ColorTranslator.FromHtml(colorString);
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
return ColorTranslator.FromHtml(PowerPreviewProperties.DefaultSvgBackgroundSolidColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Color ThemeColor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Common.UI.ThemeManager.GetWindowsBaseColor().ToLowerInvariant() == "dark")
|
||||
{
|
||||
return ColorTranslator.FromHtml("#1e1e1e");
|
||||
}
|
||||
else
|
||||
{
|
||||
return Color.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int CheckeredShade
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return ModuleSettings.GetSettings<PowerPreviewSettings>(PowerPreviewSettings.ModuleName).Properties.SvgBackgroundCheckeredShade.Value;
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
{
|
||||
return PowerPreviewProperties.DefaultSvgBackgroundCheckeredShade;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Globalization;
|
||||
using Settings.UI.Library.Enumerations;
|
||||
|
||||
namespace SvgPreviewHandler
|
||||
{
|
||||
internal sealed class SvgHTMLPreviewGenerator
|
||||
{
|
||||
private const string CheckeredBackgroundShadeLight = """
|
||||
url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV/TiiIVBzOIOGSogmBBVMRRqlgEC6Wt0KqDyaVf0KQhSXFxFFwLDn4sVh1cnHV1cBUEwQ8QVxcnRRcp8X9JoUWMB8f9eHfvcfcOEBoVplmhCUDTbTMVj0nZ3KrU/YoQRIQxBlFmlpFIL2bgO77uEeDrXZRn+Z/7c/SpeYsBAYl4jhmmTbxBPLNpG5z3iUVWklXic+Jxky5I/Mh1xeM3zkWXBZ4pmpnUPLFILBU7WOlgVjI14mniiKrplC9kPVY5b3HWKjXWuid/YTivr6S5TnMYcSwhgSQkKKihjApsRGnVSbGQov2Yj3/I9SfJpZCrDEaOBVShQXb94H/wu1urMDXpJYVjQNeL43yMAN27QLPuON/HjtM8AYLPwJXe9lcbwOwn6fW2FjkC+reBi+u2puwBlzvA4JMhm7IrBWkKhQLwfkbflAMGboHeNa+31j5OH4AMdbV8AxwcAqNFyl73eXdPZ2//nmn19wOEPHKuuso0oQAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+cEFAwrEI+z8/sAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAL0lEQVQoz2O8e/cuAwzcv38fzlZUVMQqzsRAIqC9BhZi3I0sPhj9QIy7R+OB5hoACxUaWr81wGUAAAAASUVORK5CYII=');
|
||||
""";
|
||||
|
||||
private const string CheckeredBackgroundShadeMedium = """
|
||||
url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV/TiiIVBzOIOGSogmBBVMRRqlgEC6Wt0KqDyaVf0KQhSXFxFFwLDn4sVh1cnHV1cBUEwQ8QVxcnRRcp8X9JoUWMB8f9eHfvcfcOEBoVplmhCUDTbTMVj0nZ3KrU/YoQRIQxBlFmlpFIL2bgO77uEeDrXZRn+Z/7c/SpeYsBAYl4jhmmTbxBPLNpG5z3iUVWklXic+Jxky5I/Mh1xeM3zkWXBZ4pmpnUPLFILBU7WOlgVjI14mniiKrplC9kPVY5b3HWKjXWuid/YTivr6S5TnMYcSwhgSQkKKihjApsRGnVSbGQov2Yj3/I9SfJpZCrDEaOBVShQXb94H/wu1urMDXpJYVjQNeL43yMAN27QLPuON/HjtM8AYLPwJXe9lcbwOwn6fW2FjkC+reBi+u2puwBlzvA4JMhm7IrBWkKhQLwfkbflAMGboHeNa+31j5OH4AMdbV8AxwcAqNFyl73eXdPZ2//nmn19wOEPHKuuso0oQAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+cEFA0AJje78TwAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAALklEQVQoz2O8e/cuAwwsX74czo6MjMQqzsRAIqC9BhZi3I0sPgj9wDgaD4PCDwBglRs7Q+IL6QAAAABJRU5ErkJggg==');
|
||||
""";
|
||||
|
||||
private const string CheckeredBackgroundShadeDark = """
|
||||
url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABhGlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV/TiiIVBzOIOGSogmBBVMRRqlgEC6Wt0KqDyaVf0KQhSXFxFFwLDn4sVh1cnHV1cBUEwQ8QVxcnRRcp8X9JoUWMB8f9eHfvcfcOEBoVplmhCUDTbTMVj0nZ3KrU/YoQRIQxBlFmlpFIL2bgO77uEeDrXZRn+Z/7c/SpeYsBAYl4jhmmTbxBPLNpG5z3iUVWklXic+Jxky5I/Mh1xeM3zkWXBZ4pmpnUPLFILBU7WOlgVjI14mniiKrplC9kPVY5b3HWKjXWuid/YTivr6S5TnMYcSwhgSQkKKihjApsRGnVSbGQov2Yj3/I9SfJpZCrDEaOBVShQXb94H/wu1urMDXpJYVjQNeL43yMAN27QLPuON/HjtM8AYLPwJXe9lcbwOwn6fW2FjkC+reBi+u2puwBlzvA4JMhm7IrBWkKhQLwfkbflAMGboHeNa+31j5OH4AMdbV8AxwcAqNFyl73eXdPZ2//nmn19wOEPHKuuso0oQAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+cEFA0CCa5crucAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAL0lEQVQoz2NsaWlhgIETJ07A2RYWFljFmRhIBLTXwEKMu5HFB6MfiHH3aDzQXAMACHkZChhWp4QAAAAASUVORK5CYII=');
|
||||
""";
|
||||
|
||||
private const string HtmlTemplateSolidColor = """
|
||||
<html>
|
||||
<body style="background-color: {0}">
|
||||
{1}
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
private const string HtmlTemplateCheckered = """
|
||||
<html>
|
||||
<body style="background-image: {0}">
|
||||
{1}
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
private readonly Settings settings = new();
|
||||
|
||||
public string GeneratePreview(string svgData)
|
||||
{
|
||||
var colorMode = (SvgPreviewColorMode)settings.ColorMode;
|
||||
return colorMode switch
|
||||
{
|
||||
SvgPreviewColorMode.SolidColor => string.Format(CultureInfo.InvariantCulture, HtmlTemplateSolidColor, ColorTranslator.ToHtml(settings.SolidColor), svgData),
|
||||
SvgPreviewColorMode.Checkered => string.Format(CultureInfo.InvariantCulture, HtmlTemplateCheckered, GetConfiguredCheckeredShadeImage(), svgData),
|
||||
SvgPreviewColorMode.Default or _ => string.Format(CultureInfo.InvariantCulture, HtmlTemplateSolidColor, ColorTranslator.ToHtml(settings.ThemeColor), svgData),
|
||||
};
|
||||
}
|
||||
|
||||
private string GetConfiguredCheckeredShadeImage()
|
||||
{
|
||||
var checkeredShade = (SvgPreviewCheckeredShade)settings.CheckeredShade;
|
||||
return checkeredShade switch
|
||||
{
|
||||
SvgPreviewCheckeredShade.Light=> CheckeredBackgroundShadeLight,
|
||||
SvgPreviewCheckeredShade.Medium => CheckeredBackgroundShadeMedium,
|
||||
SvgPreviewCheckeredShade.Dark or _ => CheckeredBackgroundShadeDark,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Common;
|
||||
@@ -10,6 +11,7 @@ using Microsoft.PowerToys.PreviewHandler.Svg.Telemetry.Events;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Microsoft.Web.WebView2.WinForms;
|
||||
using SvgPreviewHandler;
|
||||
|
||||
namespace Microsoft.PowerToys.PreviewHandler.Svg
|
||||
{
|
||||
@@ -18,6 +20,11 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
|
||||
/// </summary>
|
||||
public class SvgPreviewControl : FormHandlerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Generator for the actual preview file
|
||||
/// </summary>
|
||||
private readonly SvgHTMLPreviewGenerator _previewGenerator = new();
|
||||
|
||||
/// <summary>
|
||||
/// WebView2 Control to display Svg.
|
||||
/// </summary>
|
||||
@@ -220,19 +227,21 @@ namespace Microsoft.PowerToys.PreviewHandler.Svg
|
||||
_browser.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.All);
|
||||
_browser.CoreWebView2.WebResourceRequested += CoreWebView2_BlockExternalResources;
|
||||
|
||||
string generatedPreview = _previewGenerator.GeneratePreview(svgData);
|
||||
|
||||
// WebView2.NavigateToString() limitation
|
||||
// See https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks
|
||||
// While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes
|
||||
if (svgData.Length > 1_500_000)
|
||||
if (generatedPreview.Length > 1_500_000)
|
||||
{
|
||||
string filename = _webView2UserDataFolder + "\\" + Guid.NewGuid().ToString() + ".html";
|
||||
File.WriteAllText(filename, svgData);
|
||||
File.WriteAllText(filename, generatedPreview);
|
||||
_localFileURI = new Uri(filename);
|
||||
_browser.Source = _localFileURI;
|
||||
}
|
||||
else
|
||||
{
|
||||
_browser.NavigateToString(svgData);
|
||||
_browser.NavigateToString(generatedPreview);
|
||||
}
|
||||
|
||||
Controls.Add(_browser);
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
<ProjectReference Include="..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
<ProjectReference Include="..\common\PreviewHandlerCommon.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user