high contrast.xml (31.0 KB)
The default “Blender Dark” lacks contrast on my monitor, so I had searched for a theme with more contrast, but without weird modifications. I could not find one. So, I created one myself. This theme is generated by modifying the “Blender Dark” using the C# code below. It did not modify anything unnecessary but just increasing the contrast of grey colours. Editing the colours in the Preference dialogue was humanly-impossible, so I wrote C# code to modify the theme XML file. The code makes dark grey colours darker by 30, and light grey colours lighter by 30. If you do not like those values, you can edit those values and run the C# code yourself.
If you want to do it yourself,
- In the Preferences -> Themes, select “Blender Dark”, and save it by another name (by pressing the [+] button).
- Edit the
ThemeFile
constant in the C# code to the theme XML file’s path. - Edit the code to change the values.
- Run the code.
- Select the new theme in Preferences -> Themes.
Default “Blender Dark”
After increasing the contrast
C# code to increase the contrast.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
namespace HigherContrast
{
class Program
{
const string ThemeFile = @"C:\Users\name\AppData\Roaming\Blender Foundation\Blender\2.83\scripts\presets\interface_theme\high contrast.xml";
const string DebugHtml = @"debug.html";
static StreamWriter DebugOutput;
static Regex RegexColour = new Regex(@"#([\da-f]{2}){3,4}$"); //2*3=6 and 2*4=8.
static void Main(string[] args)
{
var doc = new XmlDocument();
doc.Load(ThemeFile);
//InitDebugOutput();
//PrintAllColours(doc.DocumentElement);
//Get all grey-ish (tolerance 10) colours whose brightness is below 100.
var darkColours = GetAllGreyAttributes(doc.DocumentElement, 100, -1, 10);
foreach (var a in darkColours)
{
var original = a.Value;
a.Value = ChangeColour(original, -30); //darken by 30
}
//Get all grey-ish (tolerance 10) colours whose brightness is above 200.
var lightColours = GetAllGreyAttributes(doc.DocumentElement, -1, 200, 10);
foreach (var a in lightColours)
{
var original = a.Value;
a.Value = ChangeColour(original, 30); //lighten by 30
}
//Save the theme file with a new name (increasing number)
int num = 1;
var saveFileName = string.Empty;
do
{
num++;
var dir = Path.GetDirectoryName(ThemeFile);
var name = Path.GetFileNameWithoutExtension(ThemeFile);
var ext = Path.GetExtension(ThemeFile);
saveFileName = Path.Combine(dir, name) + num + ext;
} while (File.Exists(saveFileName));
doc.Save(saveFileName);
//CloseOutput();
//ShowDebugOutput();
}
static string ChangeColour(string colourString, int value)
{
Colour c = ParseARGBString(colourString);
c.R = normalise(c.R + value);
c.G = normalise(c.G + value);
c.B = normalise(c.B + value);
return c.ToHexString();
int normalise(int value)
{
if (value > 255) return 255;
else if (value < 0) return 0;
else return value;
}
}
static Colour ParseARGBString(string raw)
{
int a=255, r, g, b;
bool alphaExists = false;
int redPosition = 1;
if (raw.Length == 9)//argb
{
alphaExists = true;
a = int.Parse(raw.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
redPosition = 3;
}
else if (raw.Length != 7)//rgb
{
Debug.Fail("length");
}
r = int.Parse(raw.Substring(redPosition, 2), System.Globalization.NumberStyles.HexNumber);
g = int.Parse(raw.Substring(redPosition + 2, 2), System.Globalization.NumberStyles.HexNumber);
b = int.Parse(raw.Substring(redPosition + 4, 2), System.Globalization.NumberStyles.HexNumber);
if(alphaExists)
return new Colour(r, g, b, a);
else
return new Colour(r, g, b);
}
static IEnumerable<XmlAttribute> GetAllColourAttributes(XmlNode node)
{
foreach (XmlNode n in node.ChildNodes)
{
foreach (XmlAttribute a in n.Attributes)
{
var m = RegexColour.Match(a.Value);
if (m.Success)
{
yield return a;
}
}
foreach (XmlNode c in n.ChildNodes)
{
foreach (XmlAttribute a in GetAllColourAttributes(c))
yield return a;
}
}
}
static IEnumerable<XmlAttribute> GetAllGreyAttributes(XmlNode node, int maximumBrightness, int minimumBrightness, int tolerance)
{
foreach (XmlAttribute a in GetAllColourAttributes(node))
{
var c = ParseARGBString(a.Value);
int[] values = { c.R, c.G, c.B };
var avg = values.Average();
if ( (maximumBrightness >-1 && avg <= maximumBrightness) ||
(minimumBrightness >-1 && avg >= minimumBrightness) )
{
var deviation = Math.Sqrt(values.Average(v => Math.Pow(v - avg, 2)));
if( deviation <= tolerance )
yield return a;
}
}
}
#region Debug features
static void InitDebugOutput()
{
DebugOutput = File.CreateText(DebugHtml);
DebugOutput.Write("<html><body>");
}
static void CloseDebugOutput()
{
DebugOutput.Write(DebugHtml, "</body></html>");
DebugOutput.Dispose();
}
static void ShowDebugOutput()
{
Process.Start(@"cmd.exe ", @"/c " + DebugHtml);
}
static void PrintColourAttributes(IEnumerable<XmlAttribute> attributes)
{
foreach (var a in attributes)
{
var fullName = a.Name;
XmlNode p = a.OwnerElement;
while(p!=null)
{
fullName = p.Name + "." + fullName;
p = p.ParentNode;
if (p?.Name == "Theme")
break;
}
var htmlColour = a.Value;
if(a.Value.Length == 9)
{
htmlColour = htmlColour.Remove(1, 2);//remove alpha
}
DebugOutput.WriteLine($"<div>{fullName}: {a.Value} <span style=\"display:inline-block;width:30px;height:30px;background:{htmlColour};border:1px solid\"></span></div>");
}
}
#endregion
}
class Colour
{
public int A, R, G, B;
public Colour(int r, int g, int b, int a = -1)
{
R = r; G = g; B = b; A = a;
}
public string ToHexString()
{
var sb = new StringBuilder();
sb.Append("#");
if (A != -1)
{
sb.AppendFormat("{0:x2}", A);
}
sb.AppendFormat("{0:x2}{1:x2}{2:x2}", R, G, B);
return sb.ToString();
}
}
}