Created
August 18, 2015 17:54
-
-
Save anaisbetts/3c6aedc9f0cd39a77c37 to your computer and use it in GitHub Desktop.
Render the accent background of a Windows Store-style icon
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Windows; | |
using System.Windows.Media; | |
// https://raw.githubusercontent.com/maxtruxa/AccentColors/master/AccentColors/AccentColor.cs | |
namespace SlackNotifier | |
{ | |
// TODO: Add a listener for WM_SETTINGCHANGE to detect changes of the active color scheme automatically. | |
// Add a listener for WM_SETTINGCHANGE and trigger an event, like ActiveSetChanged. | |
class AccentColorSet | |
{ | |
public static AccentColorSet[] AllSets { | |
get { | |
if (_allSets == null) { | |
UInt32 colorSetCount = UXTheme.GetImmersiveColorSetCount(); | |
List<AccentColorSet> colorSets = new List<AccentColorSet>(); | |
for (UInt32 i = 0; i < colorSetCount; i++) { | |
colorSets.Add(new AccentColorSet(i, false)); | |
} | |
AllSets = colorSets.ToArray(); | |
} | |
return _allSets; | |
} | |
private set { | |
_allSets = value; | |
} | |
} | |
public static AccentColorSet ActiveSet { | |
get { | |
UInt32 activeSet = UXTheme.GetImmersiveUserColorSetPreference(false, false); | |
ActiveSet = AllSets[Math.Min(activeSet, AllSets.Length - 1)]; | |
return _activeSet; | |
} | |
private set { | |
if (_activeSet != null) _activeSet.Active = false; | |
value.Active = true; | |
_activeSet = value; | |
} | |
} | |
public Boolean Active { get; private set; } | |
public Color this[String colorName] { | |
get { | |
IntPtr name = IntPtr.Zero; | |
UInt32 colorType; | |
try { | |
name = Marshal.StringToHGlobalUni("Immersive" + colorName); | |
colorType = UXTheme.GetImmersiveColorTypeFromName(name); | |
if (colorType == 0xFFFFFFFF) throw new InvalidOperationException(); | |
} finally { | |
if (name != IntPtr.Zero) { | |
Marshal.FreeHGlobal(name); | |
name = IntPtr.Zero; | |
} | |
} | |
return this[colorType]; | |
} | |
} | |
public Color this[UInt32 colorType] { | |
get { | |
UInt32 nativeColor = UXTheme.GetImmersiveColorFromColorSetEx(this._colorSet, colorType, false, 0); | |
//if (nativeColor == 0) | |
// throw new InvalidOperationException(); | |
return Color.FromArgb( | |
(Byte)((0xFF000000 & nativeColor) >> 24), | |
(Byte)((0x000000FF & nativeColor) >> 0), | |
(Byte)((0x0000FF00 & nativeColor) >> 8), | |
(Byte)((0x00FF0000 & nativeColor) >> 16) | |
); | |
} | |
} | |
AccentColorSet(UInt32 colorSet, Boolean active) | |
{ | |
this._colorSet = colorSet; | |
this.Active = active; | |
} | |
static AccentColorSet[] _allSets; | |
static AccentColorSet _activeSet; | |
UInt32 _colorSet; | |
// HACK: GetAllColorNames collects the available color names by brute forcing the OS function. | |
// Since there is currently no known way to retrieve all possible color names, | |
// the method below just tries all indices from 0 to 0xFFF ignoring errors. | |
public List<String> GetAllColorNames() | |
{ | |
List<String> allColorNames = new List<String>(); | |
for (UInt32 i = 0; i < 0xFFF; i++) { | |
IntPtr typeNamePtr = UXTheme.GetImmersiveColorNamedTypeByIndex(i); | |
if (typeNamePtr != IntPtr.Zero) { | |
IntPtr typeName = (IntPtr)Marshal.PtrToStructure(typeNamePtr, typeof(IntPtr)); | |
allColorNames.Add(Marshal.PtrToStringUni(typeName)); | |
} | |
} | |
return allColorNames; | |
} | |
static class UXTheme | |
{ | |
[DllImport("uxtheme.dll", EntryPoint = "#98", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] | |
public static extern UInt32 GetImmersiveUserColorSetPreference(Boolean forceCheckRegistry, Boolean skipCheckOnFail); | |
[DllImport("uxtheme.dll", EntryPoint = "#94", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] | |
public static extern UInt32 GetImmersiveColorSetCount(); | |
[DllImport("uxtheme.dll", EntryPoint = "#95", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] | |
public static extern UInt32 GetImmersiveColorFromColorSetEx(UInt32 immersiveColorSet, UInt32 immersiveColorType, | |
Boolean ignoreHighContrast, UInt32 highContrastCacheMode); | |
[DllImport("uxtheme.dll", EntryPoint = "#96", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] | |
public static extern UInt32 GetImmersiveColorTypeFromName(IntPtr name); | |
[DllImport("uxtheme.dll", EntryPoint = "#100", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] | |
public static extern IntPtr GetImmersiveColorNamedTypeByIndex(UInt32 index); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Reflection; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Windows; | |
using System.Windows.Media; | |
using System.Windows.Media.Imaging; | |
using System.IO; | |
namespace SlackNotifier | |
{ | |
public static class RenderWin10Icon | |
{ | |
public static Task<string> Render(string originalIconPath) | |
{ | |
return Task.Run(() => { | |
var dpiProp = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static); | |
var dpi = (int)dpiProp.GetValue(null, null); | |
var bi = new BitmapImage(new Uri(originalIconPath)); | |
var accentColor = new SolidColorBrush(AccentColorSet.ActiveSet["SystemAccent"]); | |
var visual = new DrawingVisual(); | |
var dc = visual.RenderOpen(); | |
var targetRect = new Rect(0.0, 0.0, bi.PixelWidth, bi.PixelHeight); | |
dc.DrawRectangle(accentColor, null, targetRect); | |
dc.DrawImage(bi, targetRect); | |
dc.Close(); | |
var output = new RenderTargetBitmap(bi.PixelWidth, bi.PixelHeight, dpi, dpi, PixelFormats.Pbgra32); | |
output.Render(visual); | |
var targetPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Slack", "accent_icon.png"); | |
using (var fi = File.Open(targetPath, FileMode.Create, FileAccess.Write, FileShare.None)) { | |
var encoder = new PngBitmapEncoder(); | |
encoder.Frames.Add(BitmapFrame.Create(output)); | |
encoder.Save(fi); | |
} | |
return targetPath; | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment