SvgColourConverter.cs 12 KB
Newer Older
davescriven's avatar
davescriven committed
1
2
using System;
using System.Collections.Generic;
3
4
using System.Drawing;
using System.Globalization;
5
6
7
using System.Linq;
using System.Text;
using System.Threading;
davescriven's avatar
davescriven committed
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

namespace Svg
{
    /// <summary>
    /// Converts string representations of colours into <see cref="Color"/> objects.
    /// </summary>
    public class SvgColourConverter : System.Drawing.ColorConverter
    {
        /// <summary>
        /// Converts the given object to the converter's native type.
        /// </summary>
        /// <param name="context">A <see cref="T:System.ComponentModel.TypeDescriptor"/> that provides a format context. You can use this object to get additional information about the environment from which this converter is being invoked.</param>
        /// <param name="culture">A <see cref="T:System.Globalization.CultureInfo"/> that specifies the culture to represent the color.</param>
        /// <param name="value">The object to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> representing the converted value.
        /// </returns>
        /// <exception cref="T:System.ArgumentException">The conversion cannot be performed.</exception>
        /// <PermissionSet>
        /// 	<IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/>
        /// </PermissionSet>
        public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            string colour = value as string;

            if (colour != null)
            {
mkb137's avatar
mkb137 committed
35
36
37
                var oldCulture = Thread.CurrentThread.CurrentCulture;
                Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;
                
davescriven's avatar
davescriven committed
38
39
40
41
42
43
44
                colour = colour.Trim();

                if (colour.StartsWith("rgb"))
                {
                    try
                    {
                        int start = colour.IndexOf("(") + 1;
Mark Johnson's avatar
Mark Johnson committed
45
                        
mkb137's avatar
mkb137 committed
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
                        //get the values from the RGB string
                        string[] values = colour.Substring(start, colour.IndexOf(")") - start).Split(new char[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries);

                        //determine the alpha value if this is an RGBA (it will be the 4th value if there is one)
                        int alphaValue = 255;
                        if (values.Length > 3)
                        {
                            //the alpha portion of the rgba is not an int 0-255 it is a decimal between 0 and 1
                            //so we have to determine the corosponding byte value
                            var alphastring = values[3];
                            if(alphastring.StartsWith("."))
                            {
                                alphastring = "0" + alphastring;
                            }

                            var alphaDecimal = decimal.Parse(alphastring);

                            if(alphaDecimal <= 1)
                            {
                                alphaValue = (int)(alphaDecimal * 255);
                            }
                            else
                            {
                                alphaValue = (int)alphaDecimal;
                            }
                        }
Eric Domke's avatar
Eric Domke committed
72
73
74
75
76
77
78
79
80
81
82
83

                        Color colorpart;
                        if (values[0].Trim().EndsWith("%"))
                        {
                            colorpart = System.Drawing.Color.FromArgb(alphaValue, (int)(255 * float.Parse(values[0].Trim().TrimEnd('%')) / 100f),
                                                                                  (int)(255 * float.Parse(values[1].Trim().TrimEnd('%')) / 100f),
                                                                                  (int)(255 * float.Parse(values[2].Trim().TrimEnd('%')) / 100f));
                        }
                        else
                        {
                            colorpart = System.Drawing.Color.FromArgb(alphaValue, int.Parse(values[0]), int.Parse(values[1]), int.Parse(values[2]));
                        }
Mark Johnson's avatar
Mark Johnson committed
84

mkb137's avatar
mkb137 committed
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
                        return colorpart;
                    }
                    catch
                    {
                        throw new SvgException("Colour is in an invalid format: '" + colour + "'");
                    }
                }
                // HSL support
                else if ( colour.StartsWith( "hsl" ) ) {
                    try
                    {
                        int start = colour.IndexOf("(") + 1;
                        
                        //get the values from the RGB string
                        string[] values = colour.Substring(start, colour.IndexOf(")") - start).Split(new char[]{',', ' '}, StringSplitOptions.RemoveEmptyEntries);
                        if ( values[1].EndsWith( "%" ) )
                        {
                            values[1] = values[1].TrimEnd( '%' );
                        }
                        if ( values[2].EndsWith( "%" ) ) 
                        {
                            values[2] = values[2].TrimEnd( '%' );
                        }
                        // Get the HSL values in a range from 0 to 1.
                        double h = double.Parse( values[0] ) / 360.0;
                        double s = double.Parse( values[1] ) / 100.0;
                        double l = double.Parse( values[2] ) / 100.0;
                        // Convert the HSL color to an RGB color
                        Color colorpart = Hsl2Rgb( h, s, l );
                        return colorpart;                    
davescriven's avatar
davescriven committed
115
116
117
118
119
120
121
122
123
124
125
                    }
                    catch
                    {
                        throw new SvgException("Colour is in an invalid format: '" + colour + "'");
                    }
                }
                else if (colour.StartsWith("#") && colour.Length == 4)
                {
                    colour = string.Format(culture, "#{0}{0}{1}{1}{2}{2}", colour[1], colour[2], colour[3]);
                    return base.ConvertFrom(context, culture, colour);
                }
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
                switch (colour.ToLowerInvariant())
                {
                    case "activeborder": return SystemColors.ActiveBorder;
                    case "activecaption": return SystemColors.ActiveCaption;
                    case "appworkspace": return SystemColors.AppWorkspace;
                    case "background": return SystemColors.Desktop;
                    case "buttonface": return SystemColors.Control;
                    case "buttonhighlight": return SystemColors.ControlLightLight;
                    case "buttonshadow": return SystemColors.ControlDark;
                    case "buttontext": return SystemColors.ControlText;
                    case "captiontext": return SystemColors.ActiveCaptionText;
                    case "graytext": return SystemColors.GrayText;
                    case "highlight": return SystemColors.Highlight;
                    case "highlighttext": return SystemColors.HighlightText;
                    case "inactiveborder": return SystemColors.InactiveBorder;
                    case "inactivecaption": return SystemColors.InactiveCaption;
                    case "inactivecaptiontext": return SystemColors.InactiveCaptionText;
                    case "infobackground": return SystemColors.Info;
                    case "infotext": return SystemColors.InfoText;
                    case "menu": return SystemColors.Menu;
                    case "menutext": return SystemColors.MenuText;
                    case "scrollbar": return SystemColors.ScrollBar;
                    case "threeddarkshadow": return SystemColors.ControlDarkDark;
                    case "threedface": return SystemColors.Control;
                    case "threedhighlight": return SystemColors.ControlLight;
                    case "threedlightshadow": return SystemColors.ControlLightLight;
                    case "window": return SystemColors.Window;
                    case "windowframe": return SystemColors.WindowFrame;
                    case "windowtext": return SystemColors.WindowText;
                }

mkb137's avatar
mkb137 committed
158
                Thread.CurrentThread.CurrentCulture = oldCulture;
davescriven's avatar
davescriven committed
159
160
161
162
            }

            return base.ConvertFrom(context, culture, value);
        }
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

        public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
            {
                return true;
            }

            return base.CanConvertFrom(context, sourceType);
        }

        public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                return true;
            }

            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                var colour = (Color)value;
189
                return "#" + colour.R.ToString("X2", null) + colour.G.ToString("X2", null) + colour.B.ToString("X2", null);
190
191
192
193
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }
mkb137's avatar
mkb137 committed
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

        /// <summary>
        /// Converts HSL color (with HSL specified from 0 to 1) to RGB color.
        /// Taken from http://www.geekymonkey.com/Programming/CSharp/RGB2HSL_HSL2RGB.htm
        /// </summary>
        /// <param name="h"></param>
        /// <param name="sl"></param>
        /// <param name="l"></param>
        /// <returns></returns>
        private static Color Hsl2Rgb( double h, double sl, double l ) {
            double r = l;   // default to gray
            double g = l;
            double b = l;
            double v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
            if (v > 0)
            {
                  double m;
                  double sv;
                  int sextant;
                  double fract, vsf, mid1, mid2;
 
                  m = l + l - v;
                  sv = (v - m ) / v;
                  h *= 6.0;
                  sextant = (int)h;
                  fract = h - sextant;
                  vsf = v * sv * fract;
                  mid1 = m + vsf;
                  mid2 = v - vsf;
                  switch (sextant)
                  {
                        case 0:
                              r = v;
                              g = mid1;
                              b = m;
                              break;
                        case 1:
                              r = mid2;
                              g = v;
                              b = m;
                              break;
                        case 2:
                              r = m;
                              g = v;
                              b = mid1;
                              break;
                        case 3:
                              r = m;
                              g = mid2;
                              b = v;
                              break;
                        case 4:
                              r = mid1;
                              g = m;
                              b = v;
                              break;
                        case 5:
                              r = v;
                              g = m;
                              b = mid2;
                              break;
                  }
            }
            Color rgb = Color.FromArgb( (int)( r * 255.0 ), (int)( g * 255.0 ), (int)( b * 255.0f ) );
            return rgb;        
        }

davescriven's avatar
davescriven committed
261
262
    }
}