Converting ARBG to RGB with alpha blending with a White Background - c#

I have a color hex string stored in the database like 0x78dce6b0; I can convert this to an ARGB color using:
string colorString=0x78dce6b0;
int hexColor = Convert.ToInt32(colorString ?? "0", 16);
Color colorTL = Color.FromArgb(hexColor);
Now I want to convert this to use in an HTML page, so I need to convert into an HTML value like #cc3388. If I directly convert using ColorTranslator.ToHtml(colorTL), I lose the alpha blending value. How do I convert it by taking into consideration the alpha value, assuming the background is always white?

HTML Colors do not have an Alpha component.
Unfortunately it is impossible to convert ARGB to HTML RGB without losing the Alpha component.
If you want to blend your color with white, based upon your alpha value...
Convert each Hex component (A, R, G, B) into a value from 0 to 255, where a value of FF equates to 255, 00 equates to 0.
We'll name these 0-255 values, A, R, G, B
We'll assume that an Alpha value of 255 means "fully transparent" and an Alpha value of 0 means "fully opaque"
New_R = CInt((255 - R) * (A / 255.0) + R)
New_G = CInt((255 - G) * (A / 255.0) + G)
New_B = CInt((255 - G) * (A / 255.0) + B)
Your final HTML color string will be: "#" & cstr(New_R) & cstr(New_G) & cstr(New_B)

None of the proposed worked for me, but then used
http://en.wikipedia.org/wiki/Alpha_compositing
to come up with this:
var useColor = Color.FromArgb(
(int)((theStructureColor.R) * (theStructureColor.A / 255.0) + 255 - theStructureColor.A),
(int)((theStructureColor.G) * (theStructureColor.A / 255.0) + 255 - theStructureColor.A),
(int)((theStructureColor.B) * (theStructureColor.A / 255.0) + 255 - theStructureColor.A));

So what you are really doing is combining a white background with a semi-transparent foreground color, and calculating the resulting display color. This seems to be a duplicate question of Calculate resulting RGB from 2 colors, one is transparent, where a suitable answer was posted. To apply it to your situation, it would be something like the following (note, I haven't tested this code):
public static Color FromTransparentWithWhiteBG(Color A)
{
// Assuming Alpha is a value between 0 and 254...
var aFactor = (A.A/254);
var bgAFactor = (1-(A.A/254));
var background = Color.White;
var R_c = (Int32)(Math.Ceiling((Double)A.R * aFactor) + Math.Ceiling ((Double)background.R * (1 - bgAFactor )));
var G_c = (Int32)(Math.Ceiling((Double)A.G * aFactor) + Math.Ceiling ((Double)background.G * (1 - bgAFactor )));
var B_c = (Int32)(Math.Ceiling((Double)A.B * aFactor) + Math.Ceiling ((Double)background.B * (1 - bgAFactor )));
return Color.FromArgb(1, R_c, G_c, B_c);
}

Related

C# Word Interop Automation 2013 - Set Font color to an RGB value

How do you set the FONT COLOR on a Microsoft.Office.Interop.Word C# application?
I noticed the ColorIndex property handles around 20 colors and no sign of allowing me choose from a RGB value ??
This is the code that I cannot make it work:
parag.Range.Font.TextColor.RGB = Color.FromArgb(84, 141, 212).ToArgb();
The exception i get is:
One of the values passed to this method or property is out of range.
Any help will be truly appreciated !!
Although Color doesn't appear in the intelisense, you can access it on Font like so:
parag.Range.Font.Color = WdColor.wdColorBlue;
And to create a custom WdColor, you can use:
Color c = Color.FromArgb(229, 223, 236);
var myWdColor = (Microsoft.Office.Interop.Word.WdColor)(c.R + 0x100 * c.G + 0x10000 * c.B);
Try using Font.TextColor.RGB.
Just try this:
Color c = Color.FromArgb(84, 141, 212);
parag.Range.Font.TextColor.RGB = (c.R + 0x100 * c.G + 0x10000 * c.B)

How to overlay two images (as byte arrays)

People, i'm sure that it's quite easy, but google didn't helped...
Here is the task - i have two byte arrays (as ARGB), representing my images. They have the same size.
What operation i should perform (byte by byte) to overlay one image to another?
Second image has some transparency, which must be considered.
To clear, im looking for a code like this:
bytes[] result = new bytes[first.Length];
for(i = 0; i< first.Lenght;i++)
{
result[i] = first[i] !!%SOMETHING%!! second[i];
}
Simple guesses like bitwise OR (I know - that's stupid ;) ) don't working.
Thx for your answers.
edit: i can't use standart library becouse of security issues (all this strange manipulations occur on Silverlight).
Assuming that you are in fact working with bitmaps, you'll likely find it easier to just let the library do this for you.
The System.Drawing.Graphics class has a CompositingMode property that can be set to either SourceCopy (the default - overwrites the background colour) or SourceOver (blends with the background color).
See MSDN: How to Use Compositing Mode to Control Alpha Blending for more detail.
If you just want the raw math, alpha blending is pretty simple. For an alpha value a between 0.0 and 1.0, the result should be:
(aOld * oldValue) + ((1 - aOld) * aNew * newValue)
Where oldValue is the previous value before overlay, newValue is what you want to overlay with, and aOld and aNew are the old and new alpha values respectively. You obviously need to do this calculation for the R, G, and B values separately.
See also: Alpha Compositing (wiki link) for a more thorough explanation.
Update: I think it should be easy to figure out how to adapt this to the code in the OP, but I guess not everybody's a math person.
I'm going to assume that the byte[] is a repeating sequence of A, R, G, B values (so Length would be a multiple of 4). If that's not the case, then you'll have to adapt this code to whatever storage format you're using.
bytes[] result = new bytes[first.Length];
for(i = 0; i < first.Length; i += 4)
{
byte a1 = first[i];
byte a2 = second[i];
byte r1 = first[i+1];
byte r2 = second[i+1];
byte g1 = first[i+2];
byte g2 = second[i+2];
byte b1 = first[i+3];
byte b2 = second[i+3];
byte a = a1 + (255 - a1) * a2 / 255;
byte r = r1 * a1 / 255 + r2 * (255 - a1) * a2 / 65025;
byte g = g1 * a1 / 255 + g2 * (255 - a1) * a2 / 65025;
byte b = b1 * a1 / 255 + b2 * (255 - a1) * a2 / 65025;
result[i] = a;
result[i+1] = r;
result[i+2] = g;
result[i+3] = b;
}
I think you have the right idea. The operation you use depends on what you want for the output. Here are some operations that are useful:
average - a common way to combine
minimum
maximum
bitwise replace
xor
or
add
subtract
multiply image 1 value by (image 2 scaled 0 to 1). This will put more of image 1 on the bright places of image 2 and not so much on the dark places. Try them out and see what you like best, or better yet, let the user select.
You can probable add or or the transparency bytes, and use one of the other operations for the each of the three colors.

Convert RGB method?

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).

How do I determine darker or lighter color variant of a given color?

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.

Conditional formatting -- percentage to color conversion

What's the easiest way to convert a percentage to a color ranging from Green (100%) to Red (0%), with Yellow for 50%?
I'm using plain 32bit RGB - so each component is an integer between 0 and 255. I'm doing this in C#, but I guess for a problem like this the language doesn't really matter that much.
Based on Marius and Andy's answers I'm using the following solution:
double red = (percent < 50) ? 255 : 256 - (percent - 50) * 5.12;
double green = (percent > 50) ? 255 : percent * 5.12;
var color = Color.FromArgb(255, (byte)red, (byte)green, 0);
Works perfectly - Only adjustment I had to make from Marius solution was to use 256, as (255 - (percent - 50) * 5.12 yield -1 when 100%, resulting in Yellow for some reason in Silverlight (-1, 255, 0) -> Yellow ...
I made this function in JavaScript. It returns the color is a css string. It takes the percentage as a variable, with a range from 0 to 100. The algorithm could be made in any language:
function setColor(p){
var red = p<50 ? 255 : Math.round(256 - (p-50)*5.12);
var green = p>50 ? 255 : Math.round((p)*5.12);
return "rgb(" + red + "," + green + ",0)";
}
What you probably want to do is to assign your 0% to 100% some points in a HSV or HSL color-space. From there you can interpolate colors (and yellow just happens to be between red and green :) and convert them to RGB. That will give you a nice looking gradient between the two.
Assuming that you will use the color as a status indicator and from a user-interface perspective, however, that is probably not such a good idea, since we're quite bad at seeing small changes in color. So dividing the value into, for example, three to seven buckets would give you more noticeable differences when things change, at the cost of some precision (which you most likely would not be able to appreciate anyway).
So, all the math aside, in the end I'd recommend a lookup table with the following colors with v being the input value:
#e7241d for v <= 12%
#ef832c for v > 12% and v <= 36%
#fffd46 for v > 36% and v <= 60%
#9cfa40 for v > 60% and v <= 84%
#60f83d for v > 84%
These have been very naïvely converted from HSL values (0.0, 1.0, 1.0), (30.0, 1.0, 1.0), (60.0, 1.0, 1.0), (90.0, 1.0, 1.0), (120.0, 1.0, 1.0), and you might want to adjust the colors somewhat to suit your purposes (some don't like that red and green aren't 'pure').
Please see:
Using HSL Color (Hue, Saturation, Luminosity) To Create Better-Looking GUIs for some discussion and
RGB and HSL Colour Space Conversions for sample C# source-code.
In pseudocode.
From 0-50% your hex value would be FFxx00 where:
XX = ( Percentage / 50 ) * 255 converted into hex.
From 50-100 your hex value would be xxFF00 where:
XX = ((100-Percentage) / 50) * 255 converted into hex.
Hope that helps and is understandable.
This is a nice clean solution that improves on the currently accepted answer in three ways:
Removes the magic number (5.12), therefore making the code easier to follow.
Won't produce the rounding error that's giving you -1 when the percentage is 100%.
Allows you to customise the minimum and maximum RGB values you use, so you can produce a lighter or darker range than simple rgb(255, 0, 0) - rgb(0, 255, 0).
The code shown is C# but it's trivial to adapt the algorithm to any other language.
private const int RGB_MAX = 255; // Reduce this for a darker range
private const int RGB_MIN = 0; // Increase this for a lighter range
private Color getColorFromPercentage(int percentage)
{
// Work out the percentage of red and green to use (i.e. a percentage
// of the range from RGB_MIN to RGB_MAX)
var redPercent = Math.Min(200 - (percentage * 2), 100) / 100f;
var greenPercent = Math.Min(percentage * 2, 100) / 100f;
// Now convert those percentages to actual RGB values in the range
// RGB_MIN - RGB_MAX
var red = RGB_MIN + ((RGB_MAX - RGB_MIN) * redPercent);
var green = RGB_MIN + ((RGB_MAX - RGB_MIN) * greenPercent);
return Color.FromArgb(red, green, RGB_MIN);
}
Notes
Here's a simple table showing some percentage values, and the corresponding red and green proportions we want to produce:
VALUE GREEN RED RESULTING COLOUR
100% 100% 0% green
75% 100% 50% yellowy green
50% 100% 100% yellow
25% 50% 100% orange
0% 0% 100% red
Hopefully you can see pretty clearly that
the green value is 2x the percentage value (but capped at 100)
the red is the inverse: 2x (100 - percentage) (but capped at 100)
So my algorithm calculates the values from a table looking something like this...
VALUE GREEN RED
100% 200% 0%
75% 150% 50%
50% 100% 100%
25% 50% 150%
0% 0% 200%
...and then uses Math.Min() to cap them to 100%.
I wrote this python function based on the javascript code. it takes a percentage as a decimal. also i have squared the value to keep the colours redder for longer down the percentage scale. I also narrowed the range of colours from 255 to 180 to give a darker red and green at each end. these can be played with to give nice colours. I'd like to add a touch of orange in the middle, but i gotta get on with proper work, boo.
def getBarColour(value):
red = int( (1 - (value*value) ) * 180 )
green = int( (value * value )* 180 )
red = "%02X" % red
green = "%02X" % green
return '#' + red + green +'00'
As yellow is a mix of red and green, you can probably start with #F00 and then slide green up until you hit #FF0, then slide red down to #0F0:
for (int i = 0; i < 100; i++) {
var red = i < 50
? 255
: 255 - (256.0 / 100 * ((i - 50) * 2));
var green = i < 50
? 256.0 / 100 * (i * 2)
: 255;
var col = Color.FromArgb((int) red, (int) green, 0);
}
I use the following Python routines to blend between colours:
def blendRGBHex(hex1, hex2, fraction):
return RGBDecToHex(blendRGB(RGBHexToDec(hex1),
RGBHexToDec(hex2), fraction))
def blendRGB(dec1, dec2, fraction):
return [int(v1 + (v2-v1)*fraction)
for (v1, v2) in zip(dec1, dec2)]
def RGBHexToDec(hex):
return [int(hex[n:n+2],16) for n in range(0,len(hex),2)]
def RGBDecToHex(dec):
return "".join(["%02x"%d for d in dec])
For example:
>>> blendRGBHex("FF8080", "80FF80", 0.5)
"BFBF80"
Another routine wraps this to blend nicely between numerical values for "conditional formatting":
def colourRange(minV, minC, avgV, avgC, maxV, maxC, v):
if v < minV: return minC
if v > maxV: return maxC
if v < avgV:
return blendRGBHex(minC, avgC, (v - minV)/(avgV-minV))
elif v > avgV:
return blendRGBHex(avgC, maxC, (v - avgV)/(maxV-avgV))
else:
return avgC
So, in Jonas' case:
>>> colourRange(0, "FF0000", 50, "FFFF00", 100, "00FF00", 25)
"FF7F00"
My solution for ActionScript 3:
var red:Number = (percentage <= 50) ? 255 : 256 - (percentage - 50) * 5.12;
var green:Number = (percentage >= 50) ? 255 : percentage * 5.12;
var redHex:Number = Math.round(red) * 0x10000;
var greenHex:Number = Math.round(green) * 0x100;
var colorToReturn:uint = redHex + greenHex;
Because it's R-G-B, the colors go from integer values of -1 (white), to -16777216 for black. with red green and yellow somewhere in the middle that. Yellow is actually -256, while red is -65536 and green is -16744448. So yellow actually isn't between red and green in the RGB notation. I know that in terms of wavelenghts, green is on one side, and red is on the other side of the spectrum, but I've never seen this type of notation used in computers, as the spectrum doesn't represent all visible colours.

Categories