-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathPalette.cs
145 lines (118 loc) · 4.65 KB
/
Palette.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO;
namespace DyeAtlas
{
public class Palette
{
public static Palette LoadFromCSV(Stream s)
{
Palette pal = new Palette();
StreamReader sr = new StreamReader(s);
while (!sr.EndOfStream)
{
string[] parts = sr.ReadLine().Split(',');
PaletteEntry pe = new PaletteEntry();
pe.index = int.Parse(parts[0]);
pe.name = parts[1];
pe.color = Color.FromArgb(
int.Parse(parts[2].Substring(1, 2), System.Globalization.NumberStyles.HexNumber),
int.Parse(parts[2].Substring(3, 2), System.Globalization.NumberStyles.HexNumber),
int.Parse(parts[2].Substring(5, 2), System.Globalization.NumberStyles.HexNumber)
);
DyeAtlas.ColorConversion.ColorToHSV(pe.color, out pe.h, out pe.s, out pe.v);
pal.entries.Add(pe);
}
return pal;
}
public List<PaletteEntry> entries = new List<PaletteEntry>();
public class PaletteEntry
{
public int index;
public string name;
public Color color;
// HSV color
public double h, s, v;//precached for performance
}
public Color? Get(int index)
{
if (index == 0)
return Color.FromArgb(0, 0, 0, 0);
foreach (PaletteEntry pe in entries)
if (pe.index == index)
return pe.color;
return null;
}
// cheating with statics
public static double HueImportance = 0.0;
public static double SaturationImportance = 0.0;
public static double ValueImportance = 0.0;
private void RegenerateHSVCache()
{
foreach (PaletteEntry pe in entries)
{
double aHue, aSat, aVal;
DyeAtlas.ColorConversion.ColorToHSV(pe.color, out aHue, out aSat, out aVal);
}
}
public int FindClosestIndex(Color clr, bool hsvCompare)
{
if (clr.A == 0)
return 0;
int closestIndex = -1;
int closestDiff = 99999;
foreach (PaletteEntry pe in entries)
{
int diff;
if (hsvCompare)
{
double bHue, bSat, bVal;
DyeAtlas.ColorConversion.ColorToHSV(clr, out bHue, out bSat, out bVal);
double hueDiff = DyeAtlas.AngleDiff.distance(pe.h, bHue) / 180.0;
double satDiff = Math.Abs(pe.s - bSat);
double valDiff = Math.Abs(pe.v - bVal);
#if false
// just use our HSV comparison directly later
diff = 0;
// weights
hueDiff *= HueImportance;
satDiff *= SaturationImportance;
valDiff *= ValueImportance;
#else
// RGB compare; seems to be a good baseline
diff = Math.Abs(pe.color.R - clr.R) + Math.Abs(pe.color.G - clr.G) + Math.Abs(pe.color.B - clr.B);
// weights (based around 0 because we have a RGB already)
double weightScale = 6.0;
hueDiff *= HueImportance * weightScale;
satDiff *= SaturationImportance * weightScale;
valDiff *= ValueImportance * weightScale;
#endif
// influence with HSV diffs
diff += (int)Math.Round(hueDiff * 100.0) +
(int)Math.Round(satDiff * 100.0) +
(int)Math.Round(valDiff * 100.0);
}
else
{
// RGB compare
diff = Math.Abs(pe.color.R - clr.R) + Math.Abs(pe.color.G - clr.G) + Math.Abs(pe.color.B - clr.B);
}
if (diff < closestDiff)
{
// blacklist?
/*if (pe.name.Equals("magenta", StringComparison.InvariantCultureIgnoreCase) ||
pe.name.Equals("dark pink", StringComparison.InvariantCultureIgnoreCase) ||
pe.name.Equals("pink", StringComparison.InvariantCultureIgnoreCase))
continue;*/
closestDiff = diff;
closestIndex = pe.index;
}
}
return closestIndex;
}
}
}