okay, so I'm trying to get the cell's font color as the program needs to do different things biased on the font color in the cell so I made a test file
and I tried to access it like so:
Range thrange = ws.UsedRange.Columns["A:A", Type.Missing].Rows;
foreach (Range r in thrange)
{
Style sy = r.Style;
Font font = sy.Font;
ColorFormat color = (ColorFormat)font.Color;
Console.WriteLine(" "+r.Value+" " + color.RGB);
}
I get
Can not convert type 'double' to 'Microsoft.Office.Interop.Excel.ColorFormat'
I saw people saying you set the color with a drawing object so I tried changing the last two lines to:
Color color =(System.Drawing.Color)font.Color;
Console.WriteLine(" "+r.Value+" " + color.ToArgb());
but that didn't work either
Can not convert type 'double' to 'System.Drawing.Color'
so I thought I'd see what this double is, then set the font to a known rgb value and work out how to convert the number I get back into that. but that didn't work either.
as while
Console.WriteLine(" "+r.Value+" "+r.style.font.color);
didn't throw an error it still didn't give me anything useful:
cyan 0
pink 0
blue 0
red 0
orange 0
purple 0
I thought maybe r.style.font.colorindex but that just gave me a 1 for everything instead of a 0
I was hopping for something like
blue 0000ff
red ff0000
I can't use a 3rd party libraries due to the rules set out by the project owner.
So how do I get the actual color value out?
Use the Font property of the Range not that of its Style. Then use the ColorTranslator class to convert the double value from Office to a .net Color.
foreach (Microsoft.Office.Interop.Excel.Range r in thrange)
{
// Get Color from Font from Range directly
int oleColor = Convert.ToInt32(r.Font.Color);
// Convert to C# Color type
System.Drawing.Color c = System.Drawing.ColorTranslator.FromOle(oleColor);
// Output
Console.WriteLine(r.Value + " " + c.ToString());
}
I am trying to convert a hex value to its corresponding color name, but the ColorConverter's ConvertFromString method is inserting extra characters:
string s1 = "#000000";
string s2 = "#ccff33";
string s3 = "#990000";
Color color;
ColorConverter converter = new ColorConverter();
color = (Color)converter.ConvertFromString(s1);
Console.Write(color.Name); // Outputs "Black"
color = (Color)converter.ConvertFromString(s2);
Console.Write(color.Name); // Outputs "ffccff33";
color = (Color)converter.ConvertFromString(s3);
Console.Write(color.Name); // Outputs "ff990000";
The extra "ff" inexplicably happens for every color but Black and White. Does anyone have any idea why this is happening?
We have similar functionality in one of our projects, you could use the following
(color)ColorTranslator.FromHtml(s1);
You can use ColorTranslator.FromHtml Method instead
That's because System.Drawing.Color stores color in ARGB format, which is Alpha + RGB.
To print out just the RGB values:
Console.Write(color.Name.Substring(2));
The extra "ff" represent the opacity of the color which in this case is 100% (as davenewza said).
A color in Hexa has 2 optional characters at the beginning for the Alpha or opacity, 2 chars for Red, 2 chars for Green and 2 more for Blue (# FF CC FF 33)
I can set a colors to object using Brush as follows:
Brushes.Red
How to apply the same using numbers,
say,
SetColor("#ffffff");
The above is an imaginary example.
You can use ColorTranslator.FromHtml
EDIT - In response to your comment, you can create a brush based on your colour:
SolidBrush brush = new SolidBrush(ColorTranslator.FromHtml("#ffffff"));
You can make Brushes with your own Color:
Color col = Color.FromArgb(255, 255, 255);
SolidBrush br = new SolidBrush(col);
Hope that helps.
In WPF:
var x = (Color)ColorConverter.ConvertFromString("#faffff");
Color color = Color.FromRgb(255, 255, 255);
i assume you know how to calculate the values?
I think you are looking for the Color.FromArgb method. It has an overload that allows specifying the color as an integer number.
Color c = (Color)((new ColorConverter()).ConvertFromString("#ffffff"));
How can I do this?
int blue = Color.Blue.ToArgb();
int yellow = Color.Yellow.ToArgb();
blue = (blue + yellow) / 2;
Color Blue = ConvertFromRGB(blue);
I think what you're looking for is this:
var blueColor = Color.FromArgb((blue + yellow) / 2);
However, I don't think it will give you the result you actually want.
You must be quite careful about mixing colours in this way. The int value representing a colour in ARGB form is fairly arbitrary as far as the coder is concerned. It's probably best to mix RGB components individually, like:
var color1 = Color.Blue;
var color2 = Color.Yellow;
var blueColor = Color.FromArgb((color1.R + color2.R) / 2,
(color1.G + color2.G) / 2, (color1.B + color2.B) / 2);
This interpolates (taking the centre point) between two colours, and should give you something that looks much more like the blend of the two colours.
(Note that I assume you're referring to the System.Drawing.Color type here.)
I think this is what you might be looking for:
int blue = Color.Blue.ToArgb();
int yellow = Color.Yellow.ToArgb();
blue = (blue + yellow)/2;
Color Blue = Color.FromArgb(blue);
Just average the colors component-wise, if that is what you are trying to do:
Color average = ConvertFromRGB((Color.Blue.R + Color.Yellow.R) / 2), (Color.Blue.G + Color.Yellow.G) / 2), (Color.Blue.B + Color.Yellow.B) / 2));
It would be useful to know what you're expecting from the second assign to 'blue' - you certainly won't be getting a shade of blue (more like red).
The problem is that the Color class keeps its ARGB values as Int32 because each of the 4 bytes represents one of the Alpha, Red, Blue and Green values.
Asking to add together two colours in their Int32 form is going to cause unexpected values, as one byte 'overflows' into the next (what happens when you add 255 and 1?)
Color.Blue, for example, is -16776961. That's because it has 4 bytes that look like this:
0: 255
1: 0
2: 0
3: 255
Or:
11111111 00000000 00000000 11111111
You'll find it much clearer to break the ARGB components down into individual bytes, System.Drawing.Color allows you to do this via its instance properties:
blue.A
blue.R
blue.G
blue.B
You can safely manipulate these, but remember that they're an instance of Byte, so you can't assign a value out of the range 0-255. To create a colour from the component bytes, use:
Color.FromArgb(a, r, g, b);
Where a, r, g, b are bytes.
Somewhat confusingly, Color.FromArgb accepts int parameters, rather than bytes. I'm afraid I've no idea why, someone better than me will have to answer that, but casting a byte to an int with produce an int with a value between 0 and 255, so it's safe to use this. Color also has a private CheckByte class that it passes each argument into so you'll get an ArgumentException rather than an unexpected color (that you'll likely get with your non-component approach).
Given a source color of any hue by the system or user, I'd like a simple algorithm I can use to work out a lighter or darker variants of the selected color. Similar to effects used on Windows Live Messenger for styling the user interface.
Language is C# with .net 3.5.
Responding to comment: Color format is (Alpha)RGB. With values as bytes or floats.
Marking answer: For the context of my use (a few simple UI effects), the answer I'm marking as accepted is actually the most simple for this context. However, I've given up votes to the more complex and accurate answers too. Anyone doing more advanced color operations and finding this thread in future should definitely check those out. Thanks SO. :)
In XNA there is the Color.Lerp static method that does this as the difference between two colours.
Lerp is a mathematical operation between two floats that changes the value of the first by a ratio of the difference between them.
Here's an extension method to do it to a float:
public static float Lerp( this float start, float end, float amount)
{
float difference = end - start;
float adjusted = difference * amount;
return start + adjusted;
}
So then a simple lerp operation between two colours using RGB would be:
public static Color Lerp(this Color colour, Color to, float amount)
{
// start colours as lerp-able floats
float sr = colour.R, sg = colour.G, sb = colour.B;
// end colours as lerp-able floats
float er = to.R, eg = to.G, eb = to.B;
// lerp the colours to get the difference
byte r = (byte) sr.Lerp(er, amount),
g = (byte) sg.Lerp(eg, amount),
b = (byte) sb.Lerp(eb, amount);
// return the new colour
return Color.FromArgb(r, g, b);
}
An example of applying this would be something like:
// make red 50% lighter:
Color.Red.Lerp( Color.White, 0.5f );
// make red 75% darker:
Color.Red.Lerp( Color.Black, 0.75f );
// make white 10% bluer:
Color.White.Lerp( Color.Blue, 0.1f );
Simply multiply the RGB values by the amount you want to modify the level by. If one of the colors is already at the max value, then you can't make it any brighter (using HSV math anyway.)
This gives the exact same result with a lot less math as switching to HSV and then modifying V. This gives the same result as switching to HSL and then modifying L, as long as you don't want to start losing saturation.
HSV ( Hue / Saturation / Value ) also called HSL ( Hue / Saturation / Lightness ) is just a different color representation.
Using this representation is it easier to adjust the brightness. So convert from RGB to HSV, brighten the 'V', then convert back to RGB.
Below is some C code to convert
void RGBToHSV(unsigned char cr, unsigned char cg, unsigned char cb,double *ph,double *ps,double *pv)
{
double r,g,b;
double max, min, delta;
/* convert RGB to [0,1] */
r = (double)cr/255.0f;
g = (double)cg/255.0f;
b = (double)cb/255.0f;
max = MAXx(r,(MAXx(g,b)));
min = MINx(r,(MINx(g,b)));
pv[0] = max;
/* Calculate saturation */
if (max != 0.0)
ps[0] = (max-min)/max;
else
ps[0] = 0.0;
if (ps[0] == 0.0)
{
ph[0] = 0.0f; //UNDEFINED;
return;
}
/* chromatic case: Saturation is not 0, so determine hue */
delta = max-min;
if (r==max)
{
ph[0] = (g-b)/delta;
}
else if (g==max)
{
ph[0] = 2.0 + (b-r)/delta;
}
else if (b==max)
{
ph[0] = 4.0 + (r-g)/delta;
}
ph[0] = ph[0] * 60.0;
if (ph[0] < 0.0)
ph[0] += 360.0;
}
void HSVToRGB(double h,double s,double v,unsigned char *pr,unsigned char *pg,unsigned char *pb)
{
int i;
double f, p, q, t;
double r,g,b;
if( s == 0 )
{
// achromatic (grey)
r = g = b = v;
}
else
{
h /= 60; // sector 0 to 5
i = (int)floor( h );
f = h - i; // factorial part of h
p = v * ( 1 - s );
q = v * ( 1 - s * f );
t = v * ( 1 - s * ( 1 - f ) );
switch( i )
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default: // case 5:
r = v;
g = p;
b = q;
break;
}
}
r*=255;
g*=255;
b*=255;
pr[0]=(unsigned char)r;
pg[0]=(unsigned char)g;
pb[0]=(unsigned char)b;
}
Rich Newman discusses HSL color with respect to .NET System.Drawing.Color on his blog and even provides an HSLColor class that does all the work for you. Convert your System.Drawing.Color to an HSLColor, add/subtract values against the Luminosity, and convert back to System.Drawing.Color for use in your app.
You can convert your color into the HSL color-space, manipulate it there and convert back to your color-space of choice (most likely that's RGB)
Lighter colors have a higher L-value, darker a lower.
Here's the relevant stuff and all the equations:
http://en.wikipedia.org/wiki/HSL_color_space
Another method is to simply interpolate your color with white or black. This will also desaturate the color a bit but it's cheaper to calculate.
I have used the ControlPaint.Dark() and .Light() in System.Windows.Forms.
I'm guessing you're using RGB with byte values (0 to 255) as that's very common everywhere.
For brighter, average the RGB values with the RGB of white. Or, to have some control over how much brightening, mix in them in some proportion. Let f vary from 0.0 to 1.0, then:
Rnew = (1-f)*R + f*255
Gnew = (1-f)*G + f*255
Bnew = (1-f)*B + f*255
For darker, use the RGB of black - which, being all zeros, makes the math easier.
I leave out details such as converting the result back into bytes, which probably you'd want to do.
If you are using RGB colors I would transform this color paramaters to HSL (hue, saturation, lightness), modify the lightness parameter and then transform back to RGB. Google around and you'll find a lot of code samples on how to do these color representation transformations (RGB to HSL and viceversa).
This is what I quickly found:
http://bytes.com/forum/thread250450.html
Assuming you get the color as RGB, first convert it to HSV (hue, saturation, value) color space. Then increase/decrease the value to produce lighter/darker shade of the color. Then convert back to RGB.
If your colours are in RGB format (or, presumably CMYK), you can use the fairly crude method of increasing the value of each component of the colour. E.g., in HTML colours are represented as three two-digit hex numbers. #ff0000 will give you a bright red, which can then be faded by increasing the values of the G and B componenets by the same amount, such as #ff5555 (gives a lighter red). Presumably for Hue, Saturation and Lightness (HSL) colours, you can just raise the L component, but I can't say for certain; I'm less familiar with this colour space.
As I say, though, this method is quite crude. From my memories of Live Messenger, it sounds like you're trying to do gradients, which can be applied really quite easily in Windows Presentation Foundation (WPF, part of .NET 3.0). WPF supports many different types of gradient brush, including linear and radial gradients.
I can highly recommend Adam Nathan's book Windows Presentation Foundation Unleashed as a good and thorough introduction to WPF.
HTH
Any variations in color are better done in HSL/HSV.
A good test is to interpolate between two equivalent values in RGB space and HSL space. The ramp in HSL space looks like a natural progression. In RGB space it typically looks quite unnatural. HSL maps to our visual color space perception much better than RGB.
The idea of converting to HSV or some other color space seems good, and may be necessary for precise color work, but for ordinary purposes the error of working in RGB may not be enough to matter. Also, it can be a pain to deal with boundary cases: RGB is a cube-shaped space, while HSV is not. If working with byte values, you can have many-to-one and one-to-many mappings between the spaces. This may or may not be a problem depending on the application. YMMV
This website notes that you can use the ControlPaint class within the BCL C# System.Windows.Forms namespace.