Skip to content

Commit

Permalink
Merge pull request #418 from waf/fix-parser-and-registry-bugs-with-re…
Browse files Browse the repository at this point in the history
…factor

Fix ColorTool parser and registry bugs, and refactor
  • Loading branch information
miniksa authored Apr 29, 2019
2 parents 2d1055d + f8f4f26 commit 723efc7
Show file tree
Hide file tree
Showing 17 changed files with 883 additions and 774 deletions.
76 changes: 58 additions & 18 deletions tools/ColorTool/ColorTool/ColorScheme.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,74 @@
//
// Copyright (C) Microsoft. All rights reserved.
// 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.Drawing;
using System.Linq;

namespace ColorTool
{
/// <summary>
/// Represents a colorscheme that can be applied to a console.
/// </summary>
public class ColorScheme
{
public uint[] colorTable = null;
public ConsoleAttributes consoleAttributes;
public ColorScheme(uint[] colorTable, ConsoleAttributes consoleAttributes)
{
ColorTable = colorTable;
ConsoleAttributes = consoleAttributes;
}

public uint[] ColorTable { get; }
public ConsoleAttributes ConsoleAttributes { get; }

public ushort? ScreenColorAttributes =>
CalculateBackgroundForegroundAttributes(
this.ConsoleAttributes.Background,
this.ConsoleAttributes.Foreground
);

public ushort? PopupColorAttributes =>
CalculateBackgroundForegroundAttributes(
this.ConsoleAttributes.PopupBackground,
this.ConsoleAttributes.PopupForeground
);

public Color this[int index] => UIntToColor(ColorTable[index]);

private static Color UIntToColor(uint color)
{
byte r = (byte)(color >> 0);
byte g = (byte)(color >> 8);
byte b = (byte)(color >> 16);
return Color.FromArgb(r, g, b);
}

private ushort? CalculateBackgroundForegroundAttributes(uint? background, uint? foreground)
{
if(!(background.HasValue && foreground.HasValue))
{
return null;
}
int fgidx = this.CalculateIndex(foreground.Value);
int bgidx = this.CalculateIndex(background.Value);
var attributes = (ushort)(fgidx | (bgidx << 4));
return attributes;
}

public int CalculateIndex(uint value) =>
colorTable.Select((color, idx) => Tuple.Create(color, idx))
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));
// heuristic 3: weighted RGB L2 distance
tup => WeightedRGBSimilarity(c1, tup.Item1);
// 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));
// heuristic 3: weighted RGB L2 distance
tup => WeightedRGBSimilarity(c1, tup.Item1);

private static double WeightedRGBSimilarity(uint c1, uint c2)
{
Expand All @@ -36,9 +79,6 @@ private static double WeightedRGBSimilarity(uint c1, uint c2)
return Math.Sqrt(dist[0] * (2 + rbar / 256.0) + dist[1] * 4 + dist[2] * (2 + (255 - rbar) / 256.0));
}

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)
Expand Down Expand Up @@ -77,17 +117,17 @@ internal void Dump()

for (int i = 0; i < 16; ++i)
{
_dump($"Color[{i}]", colorTable[i]);
_dump($"Color[{i}]", ColorTable[i]);
}

if (consoleAttributes.foreground != null)
if (ConsoleAttributes.Foreground != null)
{
_dump("FG ", consoleAttributes.foreground.Value);
_dump("FG ", ConsoleAttributes.Foreground.Value);
}

if (consoleAttributes.background != null)
if (ConsoleAttributes.Background != null)
{
_dump("BG ", consoleAttributes.background.Value);
_dump("BG ", ConsoleAttributes.Background.Value);
}
}
}
Expand Down
205 changes: 205 additions & 0 deletions tools/ColorTool/ColorTool/ColorTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
//
// 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.Collections.Generic;

namespace ColorTool
{
/// <summary>
/// Displays the color table that demonstrates the current colorscheme.
/// </summary>
static class ColorTable
{
private const int DarkBlack = 0;
private const int DarkBlue = 1;
private const int DarkGreen = 2;
private const int DarkCyan = 3;
private const int DarkRed = 4;
private const int DarkMagenta = 5;
private const int DarkYellow = 6;
private const int DarkWhite = 7;
private const int BrightBlack = 8;
private const int BrightBlue = 9;
private const int BrightGreen = 10;
private const int BrightCyan = 11;
private const int BrightRed = 12;
private const int BrightMagenta = 13;
private const int BrightYellow = 14;
private const int BrightWhite = 15;

// This is the order of colors when output by the table.
private static readonly IReadOnlyList<int> Foregrounds = new[]
{
BrightWhite,
DarkBlack,
BrightBlack,
DarkRed,
BrightRed,
DarkGreen,
BrightGreen,
DarkYellow,
BrightYellow,
DarkBlue,
BrightBlue,
DarkMagenta,
BrightMagenta,
DarkCyan,
BrightCyan,
DarkWhite,
BrightWhite
};

private static readonly IReadOnlyList<int> Backgrounds = new[]
{
DarkBlack,
DarkRed,
DarkGreen,
DarkYellow,
DarkBlue,
DarkMagenta,
DarkCyan,
DarkWhite
};

private const string TestText = " gYw ";

private static readonly IReadOnlyList<string> AnsiForegroundSequences = new[]
{
"m",
"1m",
"30m",
"1;30m",
"31m",
"1;31m",
"32m",
"1;32m",
"33m",
"1;33m",
"34m",
"1;34m",
"35m",
"1;35m",
"36m",
"1;36m",
"37m",
"1;37m"
};

private static readonly IReadOnlyList<string> AnsiBackgroundSequences = new[]
{
"m",
"40m",
"41m",
"42m",
"43m",
"44m",
"45m",
"46m",
"47m"
};

public static void PrintTable()
{
ConsoleColor[] colors = (ConsoleColor[])ConsoleColor.GetValues(typeof(ConsoleColor));
// Save the current background and foreground colors.
ConsoleColor currentBackground = Console.BackgroundColor;
ConsoleColor currentForeground = Console.ForegroundColor;

Console.Write("\t");
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
{
if (bg > 0) Console.Write(" ");
Console.Write(" ");
Console.Write(bg == 0 ? " " : AnsiBackgroundSequences[bg]);
Console.Write(" ");
}
Console.WriteLine();

for (int fg = 0; fg < AnsiForegroundSequences.Count; fg++)
{
Console.ForegroundColor = currentForeground;
Console.BackgroundColor = currentBackground;

if (fg >= 0) Console.Write(AnsiForegroundSequences[fg] + "\t");

if (fg == 0) Console.ForegroundColor = currentForeground;
else Console.ForegroundColor = colors[Foregrounds[fg - 1]];

for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
{
if (bg > 0) Console.Write(" ");
if (bg == 0)
Console.BackgroundColor = currentBackground;
else Console.BackgroundColor = colors[Backgrounds[bg - 1]];
Console.Write(TestText);
Console.BackgroundColor = currentBackground;
}
Console.Write("\n");
}
Console.Write("\n");

// Reset foreground and background colors
Console.ForegroundColor = currentForeground;
Console.BackgroundColor = currentBackground;
}

public static void PrintTableWithVt()
{
Console.Write("\t");
for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
{
if (bg > 0) Console.Write(" ");
Console.Write(" ");
Console.Write(bg == 0 ? " " : AnsiBackgroundSequences[bg]);
Console.Write(" ");
}
Console.WriteLine();

for (int fg = 0; fg < AnsiForegroundSequences.Count; fg++)
{
Console.Write("\x1b[m");

if (fg >= 0)
{
Console.Write(AnsiForegroundSequences[fg] + "\t");
}

if (fg == 0)
{
Console.Write("\x1b[39m");
}
else
{
Console.Write("\x1b[" + AnsiForegroundSequences[fg]);
}

for (int bg = 0; bg < AnsiBackgroundSequences.Count; bg++)
{
if (bg > 0)
{
Console.Write(" ");
}
if (bg == 0)
{
Console.Write("\x1b[49m");
}
else
{
Console.Write("\x1b[" + AnsiBackgroundSequences[bg]);
}

Console.Write(TestText);
Console.Write("\x1b[49m");
}
Console.Write("\n");
}
Console.Write("\n");

// Reset foreground and background colors
Console.Write("\x1b[m");
}
}
}
3 changes: 2 additions & 1 deletion tools/ColorTool/ColorTool/ColorTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net46</TargetFramework>
<TargetFramework>net461</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<LangVersion>latest</LangVersion>
</PropertyGroup>
</Project>
13 changes: 6 additions & 7 deletions tools/ColorTool/ColorTool/ConsoleAPI.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//

Expand All @@ -8,9 +8,11 @@

namespace ColorTool
{
class ConsoleAPI
static class ConsoleAPI
{
////////////////////////////////////////////////////////////////////////
private const int StdOutputHandle = -11;
public const int ColorTableSize = 16;

[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
Expand Down Expand Up @@ -58,7 +60,7 @@ public static CONSOLE_SCREEN_BUFFER_INFO_EX Create()
}
}

public static int STD_OUTPUT_HANDLE = -11;
public static IntPtr GetStdOutputHandle() => GetStdHandle(StdOutputHandle);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
Expand All @@ -83,13 +85,10 @@ IntPtr lpReserved

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
////////////////////////////////////////////////////////////////////////

public static uint RGB(int r, int g, int b)
{
return (uint)r + (((uint)g) << 8) + (((uint)b) << 16);
}

public const int COLOR_TABLE_SIZE = 16;
}
}
Loading

0 comments on commit 723efc7

Please sign in to comment.