colortool: add support for fg/bg color slot designation
This commit is contained in:
parent
e0248749eb
commit
22dd8a8e01
83
tools/ColorTool/ColorTool/ColorScheme.cs
Normal file
83
tools/ColorTool/ColorTool/ColorScheme.cs
Normal file
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// Copyright (C) Microsoft. All rights reserved.
|
||||
// Licensed under the terms described in the LICENSE file in the root of this project.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace ColorTool
|
||||
{
|
||||
public class ColorScheme
|
||||
{
|
||||
public uint[] colorTable = null;
|
||||
public uint? foreground = null;
|
||||
public uint? background = null;
|
||||
|
||||
public int CalculateIndex(uint value) =>
|
||||
colorTable.Select((color, idx) => Tuple.Create(color, idx))
|
||||
.OrderBy(Difference(value))
|
||||
.First().Item2;
|
||||
|
||||
private static Func<Tuple<uint, int>, double> Difference(uint c1) =>
|
||||
// heuristic 1: nearest neighbor in RGB space
|
||||
// tup => Distance(RGB(c1), RGB(tup.Item1));
|
||||
// heuristic 2: nearest neighbor in RGB space
|
||||
tup => Distance(HSV(c1), HSV(tup.Item1));
|
||||
|
||||
private static double Distance(uint[] c1c, uint[] c2c)
|
||||
=> Math.Sqrt(c1c.Zip(c2c, (a, b) => Math.Pow((int)a - (int)b, 2)).Sum());
|
||||
|
||||
internal static uint[] RGB(uint c) => new[] { c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF };
|
||||
|
||||
internal static uint[] HSV(uint c)
|
||||
{
|
||||
var rgb = RGB(c).Select(_ => (int)_).ToArray();
|
||||
int max = rgb.Max();
|
||||
int min = rgb.Min();
|
||||
|
||||
int d = max - min;
|
||||
int h = 0;
|
||||
int s = (int)(255 * ((max == 0) ? 0 : d / (double)max));
|
||||
int v = max;
|
||||
|
||||
if (d != 0)
|
||||
{
|
||||
double dh;
|
||||
if (rgb[0] == max) dh = ((rgb[1] - rgb[2]) / (double)d);
|
||||
else if (rgb[1] == max) dh = 2.0 + ((rgb[2] - rgb[0]) / (double)d);
|
||||
else /* if (rgb[2] == max) */ dh = 4.0 + ((rgb[0] - rgb[1]) / (double)d);
|
||||
dh *= 60;
|
||||
if (dh < 0) dh += 360.0;
|
||||
h = (int)(dh * 255.0 / 360.0);
|
||||
}
|
||||
|
||||
return new[] { (uint)h, (uint)s, (uint)v };
|
||||
}
|
||||
|
||||
internal void Dump()
|
||||
{
|
||||
Action<string, uint> _dump = (str, c) =>
|
||||
{
|
||||
var rgb = RGB(c);
|
||||
var hsv = HSV(c);
|
||||
Console.WriteLine($"{str} =\tRGB({rgb[0]}, {rgb[1]}, {rgb[2]}),\tHSV({hsv[0]}, {hsv[1]}, {hsv[2]})");
|
||||
};
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
_dump($"Color[{i}]", colorTable[i]);
|
||||
}
|
||||
|
||||
if (foreground != null)
|
||||
{
|
||||
_dump("FG ", foreground.Value);
|
||||
}
|
||||
|
||||
if (background != null)
|
||||
{
|
||||
_dump("BG ", background.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ColorScheme.cs" />
|
||||
<Compile Include="ConsoleAPI.cs" />
|
||||
<Compile Include="IniSchemeParser.cs" />
|
||||
<Compile Include="ISchemeParser.cs" />
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace ColorTool
|
|||
public uint cbSize;
|
||||
public COORD dwSize;
|
||||
public COORD dwCursorPosition;
|
||||
public short wAttributes;
|
||||
public ushort wAttributes;
|
||||
public SMALL_RECT srWindow;
|
||||
public COORD dwMaximumWindowSize;
|
||||
|
||||
|
@ -56,6 +56,7 @@ namespace ColorTool
|
|||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool SetConsoleScreenBufferInfoEx(IntPtr ConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO_EX ConsoleScreenBufferInfoEx);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static uint RGB(int r, int g, int b)
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace ColorTool
|
|||
{
|
||||
interface ISchemeParser
|
||||
{
|
||||
uint[] ParseScheme(string schemeName);
|
||||
ColorScheme ParseScheme(string schemeName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ namespace ColorTool
|
|||
return null;
|
||||
}
|
||||
|
||||
public uint[] ParseScheme(string schemeName)
|
||||
public ColorScheme ParseScheme(string schemeName)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
|
@ -147,7 +147,7 @@ namespace ColorTool
|
|||
}
|
||||
}
|
||||
|
||||
return colorTable;
|
||||
return new ColorScheme { colorTable = colorTable };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ namespace ColorTool
|
|||
Console.BackgroundColor = currentBackground;
|
||||
}
|
||||
|
||||
static bool SetProperties(uint[] colorTable)
|
||||
static bool SetProperties(ColorScheme colorScheme)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO_EX csbiex = CONSOLE_SCREEN_BUFFER_INFO_EX.Create();
|
||||
int STD_OUTPUT_HANDLE = -11;
|
||||
|
@ -187,7 +187,13 @@ namespace ColorTool
|
|||
csbiex.srWindow.Bottom++;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
csbiex.ColorTable[i] = colorTable[i];
|
||||
csbiex.ColorTable[i] = colorScheme.colorTable[i];
|
||||
}
|
||||
if(colorScheme.background != null && colorScheme.foreground != null)
|
||||
{
|
||||
int fgidx = colorScheme.CalculateIndex(colorScheme.foreground.Value);
|
||||
int bgidx = colorScheme.CalculateIndex(colorScheme.background.Value);
|
||||
csbiex.wAttributes = (ushort)(fgidx | (bgidx << 4));
|
||||
}
|
||||
SetConsoleScreenBufferInfoEx(hOut, ref csbiex);
|
||||
}
|
||||
|
@ -200,19 +206,20 @@ namespace ColorTool
|
|||
}
|
||||
return success;
|
||||
}
|
||||
static bool SetDefaults(uint[] colorTable)
|
||||
|
||||
static bool SetDefaults(ColorScheme colorScheme)
|
||||
{
|
||||
//TODO
|
||||
RegistryKey consoleKey = Registry.CurrentUser.OpenSubKey("Console", true);
|
||||
for (int i = 0; i < colorTable.Length; i++)
|
||||
for (int i = 0; i < colorScheme.colorTable.Length; i++)
|
||||
{
|
||||
string valueName = "ColorTable" + (i < 10 ? "0" : "") + i;
|
||||
consoleKey.SetValue(valueName, colorTable[i], RegistryValueKind.DWord);
|
||||
consoleKey.SetValue(valueName, colorScheme.colorTable[i], RegistryValueKind.DWord);
|
||||
}
|
||||
Console.WriteLine(Resources.WroteToDefaults);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
|
@ -258,19 +265,19 @@ namespace ColorTool
|
|||
|
||||
string schemeName = args[args.Length - 1];
|
||||
|
||||
uint[] colorTable = null;
|
||||
ColorScheme colorScheme = null;
|
||||
ISchemeParser[] parsers = { new XmlSchemeParser(), new IniSchemeParser() };
|
||||
foreach (var parser in parsers)
|
||||
{
|
||||
uint[] table = parser.ParseScheme(schemeName);
|
||||
if (table != null)
|
||||
var scheme = parser.ParseScheme(schemeName);
|
||||
if (scheme != null)
|
||||
{
|
||||
colorTable = table;
|
||||
colorScheme = scheme;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (colorTable == null)
|
||||
if (colorScheme == null)
|
||||
{
|
||||
Console.WriteLine(string.Format(Resources.SchemeNotFound, schemeName));
|
||||
return;
|
||||
|
@ -278,11 +285,11 @@ namespace ColorTool
|
|||
|
||||
if (setDefaults)
|
||||
{
|
||||
SetDefaults(colorTable);
|
||||
SetDefaults(colorScheme);
|
||||
}
|
||||
if (setProperties)
|
||||
{
|
||||
SetProperties(colorTable);
|
||||
SetProperties(colorScheme);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
//
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Xml;
|
||||
using static ColorTool.ConsoleAPI;
|
||||
|
||||
|
@ -30,6 +32,8 @@ namespace ColorTool
|
|||
"Ansi 11 Color", // BRIGHT_YELLOW
|
||||
"Ansi 15 Color" // BRIGHT_WHITE
|
||||
};
|
||||
static string FG_KEY = "Foreground Color";
|
||||
static string BG_KEY = "Background Color";
|
||||
static string RED_KEY = "Red Component";
|
||||
static string GREEN_KEY = "Green Component";
|
||||
static string BLUE_KEY = "Blue Component";
|
||||
|
@ -121,7 +125,7 @@ namespace ColorTool
|
|||
}
|
||||
|
||||
|
||||
public uint[] ParseScheme(string schemeName)
|
||||
public ColorScheme ParseScheme(string schemeName)
|
||||
{
|
||||
XmlDocument xmlDoc = loadXmlScheme(schemeName); // Create an XML document object
|
||||
if (xmlDoc == null) return null;
|
||||
|
@ -129,39 +133,20 @@ namespace ColorTool
|
|||
XmlNodeList children = root.ChildNodes;
|
||||
|
||||
uint[] colorTable = new uint[COLOR_TABLE_SIZE];
|
||||
uint? fgColor = null, bgColor = null;
|
||||
int colorsFound = 0;
|
||||
bool success = false;
|
||||
foreach (XmlNode tableEntry in children)
|
||||
foreach (var tableEntry in children.OfType<XmlNode>().Where(_ => _.Name == "key"))
|
||||
{
|
||||
if (tableEntry.Name == "key")
|
||||
{
|
||||
int index = -1;
|
||||
for (int i = 0; i < COLOR_TABLE_SIZE; i++)
|
||||
{
|
||||
if (PLIST_COLOR_NAMES[i] == tableEntry.InnerText)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint rgb = 0; ;
|
||||
XmlNode components = tableEntry.NextSibling;
|
||||
success = parseRgbFromXml(components, ref rgb);
|
||||
if (!success)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
colorTable[index] = rgb;
|
||||
colorsFound++;
|
||||
}
|
||||
}
|
||||
|
||||
uint rgb = 0;
|
||||
int index = -1;
|
||||
XmlNode components = tableEntry.NextSibling;
|
||||
success = parseRgbFromXml(components, ref rgb);
|
||||
if (!success) { break; }
|
||||
else if (tableEntry.InnerText == FG_KEY) { fgColor = rgb; }
|
||||
else if (tableEntry.InnerText == BG_KEY) { bgColor = rgb; }
|
||||
else if (-1 != (index = Array.IndexOf(PLIST_COLOR_NAMES, tableEntry.InnerText)))
|
||||
{ colorTable[index] = rgb; colorsFound++; }
|
||||
}
|
||||
if (colorsFound < COLOR_TABLE_SIZE)
|
||||
{
|
||||
|
@ -172,8 +157,8 @@ namespace ColorTool
|
|||
{
|
||||
return null;
|
||||
}
|
||||
return colorTable;
|
||||
|
||||
return new ColorScheme { colorTable = colorTable, foreground = fgColor, background = bgColor };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue