-
Notifications
You must be signed in to change notification settings - Fork 0
/
NamiconGenerator.cs
241 lines (196 loc) · 7.56 KB
/
NamiconGenerator.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Namicon
{
public class NamiconGenerator
{
private const int DefaultRenderSizeFactor = 4;
private const float DefaultFontToRenderSizeFactor = 2.5f;
private static readonly Color DefaultTextColor = Color.Black;
private static readonly StringFormat GenericTypo = StringFormat.GenericTypographic;
private static readonly Regex SplitRegex = new Regex(@"\s+|['`´]", RegexOptions.ExplicitCapture);
public NamiconGenerator(int outputSize = 100)
{
SetDefaultSize(outputSize);
// more defaults
FontFamily = "Consolas";
Lightness = 0.7f;
Saturation = 1.0f;
Round = true;
FallbackText = "";
}
public bool Round { get; set; }
public int OutputSize { get; set; }
public int RenderSize { get; set; }
public float FontSize { get; set; }
public string FontFamily { get; set; }
public float Lightness { get; set; }
public float Saturation { get; set; }
public string FallbackText { get; set; }
public virtual uint Hasher(string text)
{
return (uint) text.GetHashCode();
}
public void SetDefaultSize(int outputSize)
{
SetDefaultSize(outputSize, DefaultRenderSizeFactor*outputSize);
}
public void SetDefaultSize(int outputSize, int renderSize)
{
SetDefaultSize(outputSize, renderSize, renderSize/DefaultFontToRenderSizeFactor);
}
public void SetDefaultSize(int outputSize, int renderSize, float fontSize)
{
OutputSize = outputSize;
RenderSize = renderSize;
FontSize = fontSize;
}
public Color GetColorFromText(string text)
{
const float max = uint.MaxValue;
uint hash = Hasher(text);
float hue = hash/max;
return HslToRgba(hue, Saturation, Lightness);
}
public Bitmap CreateImage(string name)
{
return CreateImageRaw(GetInitials(name), DefaultTextColor, GetColorFromText(name));
}
public Bitmap CreateImageRaw(string text)
{
return CreateImageRaw(text, DefaultTextColor, GetColorFromText(text));
}
public Bitmap CreateImageRaw(string text, Color textColor, Color backgroundColor)
{
if (text == null)
{
text = FallbackText;
}
var image = new Bitmap(RenderSize, RenderSize);
using (Graphics g = CreateGraphics(image))
{
if (Round)
{
using (var b = new SolidBrush(backgroundColor))
{
g.FillEllipse(b, 0, 0, image.Width, image.Height);
}
}
else
{
g.Clear(backgroundColor);
}
using (var b = new SolidBrush(textColor))
using (var f = new Font(FontFamily, FontSize))
{
SizeF size = g.MeasureString(text, f, 0, GenericTypo);
float x = (image.Width - size.Width)/2;
float y = (image.Height - size.Height)/2;
g.DrawString(text, f, b, x, y, GenericTypo);
}
}
return ResizeImage(image, OutputSize, OutputSize);
}
private Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (Graphics graphics = CreateGraphics(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
public static string GetInitials(string name)
{
if (name == null) throw new ArgumentNullException("name");
name = name.Trim();
if (name == string.Empty)
{
return null;
}
string[] parts = SplitRegex
.Split(name)
.Select(Clean)
.Where(x => x.Length > 0)
.ToArray();
string initials;
if (parts.Length == 0)
{
return null;
}
if (parts.Length == 1)
{
initials = parts[0].Substring(0, Math.Min(parts[0].Length, 2));
}
else
{
initials = "" + parts.First()[0] + parts.Last()[0];
}
return initials.ToUpperInvariant();
}
private static string Clean(string str)
{
var sb = new StringBuilder();
foreach (char c in str)
{
UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(c);
if (uc == UnicodeCategory.LowercaseLetter ||
uc == UnicodeCategory.UppercaseLetter ||
uc == UnicodeCategory.DecimalDigitNumber)
sb.Append(c);
}
return sb.ToString().Trim();
}
private static Graphics CreateGraphics(Image image)
{
Graphics graphics = Graphics.FromImage(image);
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
return graphics;
}
private static Color HslToRgba(float h, float s, float l, float a = 1.0f)
{
float r, g, b;
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (s == 0.0f)
{
r = g = b = l;
}
else
{
float q = l < 0.5f ? l*(1.0f + s) : l + s - l*s;
float p = 2.0f*l - q;
r = HueToRgb(p, q, h + 1.0f/3.0f);
g = HueToRgb(p, q, h);
b = HueToRgb(p, q, h - 1.0f/3.0f);
}
return Color.FromArgb((int) (a*255), (int) (r*255), (int) (g*255), (int) (b*255));
}
private static float HueToRgb(float p, float q, float t)
{
if (t < 0.0f) t += 1.0f;
if (t > 1.0f) t -= 1.0f;
if (t < 1.0f/6.0f) return p + (q - p)*6.0f*t;
if (t < 1.0f/2.0f) return q;
if (t < 2.0f/3.0f) return p + (q - p)*(2.0f/3.0f - t)*6.0f;
return p;
}
}
}