ANSI colors and writing directly to console output C#
Asked Answered
S

3

0

how can I use more colors in console while using WriteConsoleOutput and WriteConsoleOutputAttribute?
I found you can write ANSI colors using Console.Write, but how can I do this using those two methods?

Snaggy answered 13/5, 2020 at 16:31 Comment(6)
Why are you using Win32 functions from a C# program?Elaterid
I like to use Console.ForegroundColor = ConsoleColor.Red for example red. Then reset with `Console. ResetColor()' ... if that is what you were looking to do.Belmonte
Does this answer your question? Custom text color in C# console application?Belmonte
Or perhaps Converting Color to ConsoleColor?Belmonte
@Belmonte even though you can set custom colors to ConsoleColor, it's still only limited to 16 colors. I want to use more colors (preferably 256 colors), but I can't find a way to use ANSI colors(256 colors support on some new Windows 10 update) with WriteConsoleOutput.Snaggy
Looks you cannot learn.microsoft.com/en-us/windows/console/writeconsoleLaddie
S
1

In C# is works like in C. I use it in C# some minutes ago and it works fine. Here is the Color table: https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit

C# Example:

    Console.Write("\x1B[38;5;{0}m", runtime.Register[2]);

C Example:

    printf ( "\x1B[38;5;%dm", color );
Sartre answered 18/4, 2021 at 7:49 Comment(4)
This doesnt work in the build however. It only works in the VS Debug Terminal, for some god damn reason.Bridwell
It works fine in Windows Terminal (Cmd and Powershell) and Linux. but youre right in the normal cmd its not workSoleure
I think it has somthing to do with the encoding, the new Windows Terminal works fine with utf8, but the old cmd.exe .... yeah funSoleure
#16755642Soleure
C
0

You have to opt-in on Windows to use ANSI color codes. It's not enabled by default.

using System.Runtime.InteropServices;

public static class ConsoleColor {
  private const int STD_OUTPUT_HANDLE = -11;
  private const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004;

  [DllImport("kernel32.dll", SetLastError = true)]
  private static extern IntPtr GetStdHandle(int nStdHandle);

  [DllImport("kernel32.dll", SetLastError = true)]
  private static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

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

  public static void Initialize() {
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
      EnableAnsiEscapeSequencesOnWindows();
    }
  }

  private static void EnableAnsiEscapeSequencesOnWindows() {
    IntPtr handle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (handle == IntPtr.Zero) {
      throw new Exception("Cannot get standard output handle");
    }

    if (!GetConsoleMode(handle, out uint mode)) {
      throw new Exception("Cannot get console mode");
    }

    mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(handle, mode)) {
      throw new Exception("Cannot set console mode");
    }
  }
}

It doesn't matter that we just initialize stdout. It colors work on stderr to once virtual terminal processing is enabled.

static int Main(string[] args) {
  ConsoleColor.Initialize();
  const string AnsiError = "\x1b[38;5;161m";
  const string AnsiReset = "\x1b[0m";
  Console.Error.WriteLine(AnsiError + "One or more tests failed!" + AnsiReset);
}
Contraposition answered 7/4, 2023 at 12:5 Comment(0)
S
0

You can used Ansi escape codes to color console text as it was possible with python I tried and have created a small extension on string to format & color the console text.

But unlike other answers it is a color mixed that works with RGB(255,255,255) and Css Hex Colors so it's not limited to the standard set of colors

Extension: Holi.cs

//Holi.cs
public static class Holi
{
    const int STD_OUTPUT_HANDLE = -11;
    const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4;

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetStdHandle(int nStdHandle);

    [DllImport("kernel32.dll")]
    static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);

    [DllImport("kernel32.dll")]
    static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);

    public const string RESET = "\x1B[0m";
    public const string UNDERLINE = "\x1B[4m";
    public const string BOLD = "\x1B[1m";
    public const string ITALIC = "\x1B[3m";
    public const string BLINK = "\x1B[5m";
    public const string BLINKRAPID = "\x1B[6m";
    public const string DEFAULTFORE = "\x1B[39m";
    public const string DEFAULTBACK = "\x1B[49m";

    static Holi()
    {
        var handle = GetStdHandle(STD_OUTPUT_HANDLE);
        uint mode;
        GetConsoleMode(handle, out mode);
        mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
        SetConsoleMode(handle, mode);
    }

    public static byte[] HexToRgb(string hexcolor)
    {
        hexcolor = hexcolor.Remove(0, 1);

        if (hexcolor.Length != 6)
            throw new Exception("Not a valid hex color");

        string[] rgb = hexcolor.Select((obj, index) => new { obj, index })
            .GroupBy(o => o.index / 2)
            .Select(g => new string(g.Select(a => a.obj)
            .ToArray())).ToArray<string>();

        return new byte[] { Convert.ToByte(rgb[0], 16), Convert.ToByte(rgb[1], 16), Convert.ToByte(rgb[2], 16) };
    }
    public static string ForeColor(this string text,byte red, byte green, byte blue)
    {
        return $"\x1B[38;2;{red};{green};{blue}m{text}";
    }

    public static string ForeColor(this string text, string hexrgb)
    {
        byte[] rgb = HexToRgb(hexrgb);

        return ForeColor(text, rgb[0], rgb[1], rgb[2]);
    }

    public static string BackColor(this string text, byte red, byte green, byte blue)
    {
        return $"\x1B[48;2;{red};{green};{blue}m{text}";
    }

    public static string BackColor(this string text, string hexrgb)
    {
        byte[] rgb = HexToRgb(hexrgb);

        return BackColor(text, rgb[0], rgb[1], rgb[2]);
    }

    public static string ResetColor(this string text)
    {
        return $"{RESET}{text}";
    }

    public static string Bold(this string text)
    {
        return $"{BOLD}{text}";
    }

    public static string Italic(this string text)
    {
        return $"{ITALIC}{text}";
    }

    public static string Underline(this string text)
    {
        return $"{UNDERLINE}{text}";
    }

    public static string Add(this string text,string addText)
    {
        return $"{text}{RESET}{addText}";
    }

    public static void Print(this string text,string prefix=null)
    {
        Console.WriteLine($"{prefix}{text}{RESET}");
    }

    public static void Printf(this string text, byte red=0, byte green=0, byte blue = 0)
    {
        Console.Write($"{ForeColor(red,green,blue)}{text}{RESET}");
    }

    public static void Printf(this string text, string hexColor)
    {
        byte[] rgb = HexToRgb(hexColor);

        Console.Write($"{ForeColor(rgb[0], rgb[1], rgb[2])}{text}{RESET}");
    }



    public static string ForeColor(params byte[] rgb)
    {
        if (rgb == null || rgb.Length == 0)
            return "\x1B[0m";

        if (rgb.Length == 3)
            return $"\x1B[38;2;{rgb[0]};{rgb[1]};{rgb[2]}m";

        if (rgb.Length == 2)
            return $"\x1B[38;2;{rgb[0]};{rgb[1]};0m";
        if (rgb.Length == 2)
            return $"\x1B[38;2;{rgb[0]};0;0m";

        return "\x1B[0m";

    }

    public static string BackColor(params byte[] rgb)
    {
        if (rgb == null || rgb.Length == 0)
            return "\x1B[0m";

        if (rgb.Length == 3)
            return $"\x1B[48;2;{rgb[0]};{rgb[1]};{rgb[2]}m";

        if (rgb.Length == 2)
            return $"\x1B[48;2;{rgb[0]};{rgb[1]};0m";
        if (rgb.Length == 2)
            return $"\x1B[48;2;{rgb[0]};0;0m";

        return "\x1B[0m";
    }

}

Example

Which can be used as:

//printf
"Printf Example\n".Printf(200, 255, 0);

//print
"#FFAAEE\n".ForeColor("#C8FF00").Print();

//format + print 
"\n RGB colored text".ForeColor(255,200,0).Print();
"\n HEX colored text".ForeColor("#FFC800").Print();
"\n RGB back colored text".BackColor(50, 0, 0).ResetColor().Add(" no background color ").Print();
"\n HEX back colored text".BackColor("#320000").Print();
"\n Bold Text".Bold().Print();
"\n Underline text".Underline().Add(" no underline ").Print();

//writline
var c = ForeColor(200, 255, 0);
Console.WriteLine($"Same {c}" + UNDERLINE + "underlined green" + RESET + " text");

Output

To get the following output in Microsoft Windows [Version 10.0.19044.2728]

enter image description here

Shannashannah answered 13/4, 2023 at 11:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.