How brush convert to color (UWP)? - c#

I have convert "Windows.UI.Xaml.Media.Brush" to "Windows.UI.Color". But VS return error. Tell me please how can I do this conversion correctly?

You cannot convert a brush to a color. The concept of a brush cannot be reduced to a color, as it could be a gradient of colors, or an image etc.
The conversion only makes sense for the special case of SolidColorBrush. I am guessing that's what you are after. Here is how you do it in code:
Windows.UI.Color colorFromBrush;
if (brush is SolidColorBrush)
colorFromBrush = (brush as SolidColorBrush).Color;
else
throw new Exception("Can't get color from a brush that is not a SolidColorBrush");
Thanks,
Stefan Wick - Windows Developer Platform

You can convert Brush to color, but you have to write it explicitly.
To do so just do this:
StackPanel pane = new StackPanel()
{
Background = Background = new SolidColorBrush(new Windows.UI.Color() { A = 255, R = 25, B = 0, G = 0})
}
This works for EVERY single UIElement as long as you assign the Background property properly.

There is a workaround if you're converting it to a string, then the string to bytes and then the bytes to color:
var brushString = Foreground.ToString(); // brushString equals "#FF000000" (in case of black brush)
var brushWithoutHash = brushString.Substring(1); // brushWithoutHash equals "FF000000"
var color = Color.FromArgb(Convert.ToByte(brushWithoutHash.Substring(0, 2), 16), Convert.ToByte(brushWithoutHash.Substring(2, 2), 16), Convert.ToByte(brushWithoutHash.Substring(4, 2), 16), Convert.ToByte(brushWithoutHash.Substring(6, 2), 16));
in the last line you take the hexadecimal string values and convert them to a byte.
Make sure that you're brush is made out of one single color and not null, otherwise you'll get an exception.

Related

Color a button in Unity

I was trying to change the color of my button through scripting. I'm facing a weird problem.
if I write
button1.color = new Color(255, 0, 0);
It colors the button correctly. But if I change the color something like:
button1.color = new Color(237, 85, 59);
this, then it turns to ash or no color.
I'm new in unity and don't know where is the actual problem.
The Color constructor takes in 4 values: red, green, blue and alpha. The values are between 0.0f and 1.0f, instead of
button1.color = new Color(237, 85, 59);
write something like
button1.color = new Color(0.93f, 0.33f, 0.23f, 1.0f)
The way to get the 0.0 - 1.1 values from the RGB 0 - 255 values is by dividing the color values by 255. Hope this answered your question.

How do I implement this "color difference" algorithm?

As a follow up to this question: (How can I draw legible text on a bitmap (Winforms)?), I'm drawing legible but small text on top of a bitmap by calculating the "average" color beneath the text, and choosing an appropriately contrasting color for the text.
I've stolen Till's code from https://stackoverflow.com/a/6185448/3784949 for calculating "average" bmp color. Now I'm looking at the "color difference" algorithm suggested by http://www.w3.org/TR/AERT#color-contrast.
This suggests that I need to make my color brightness at least 125 "units" greater, and my color difference at least 500 units greater, where brightness and difference are calculated like this:
Color brightness is determined by the following formula:
((Red value X 299) + (Green value X 587) + (Blue value X 114)) / 1000
Color difference is determined by the following formula:
(maximum (Red value 1, Red value 2) - minimum (Red value 1, Red value 2)) + (maximum (Green value 1, Green value 2) - minimum (Green value 1, Green value 2)) + (maximum (Blue value 1, Blue value 2) - minimum (Blue value 1, Blue value 2))
How do I implement this? I can set my color by ARGB (I believe, it's a label foreground color); but how do I calculate how much to change each individual value to achieve the difference being required here? I'm not familiar with the math required to break the "difference" units down into their component parts.
As an example, my "average" for one bitmap is: Color [A=255, R=152, G=138, B=129]. How do I "add" enough to each part to achieve the two differences?
EDIT: To be specific, my confusion lies here:
it looks like I need to add to three separate values (R,G,B) to achieve two different goals (new RGB adds up to original plus 125, new RGB adds up to original plus 500
it looks like I may need to "weight" my added brighness values to add more to G than R than B.
I have no idea how to address #1. And I'm not positive I'm correct about #2.
EDIT: Proposed solution
I'm currently experimenting with this:
private Color GetContrastingFontColor(Color AverageColorOfBitmap,
List<Color> FavoriteColors)
{
IEnumerable<Color> AcceptableColors =
(IEnumerable<Color>)FavoriteColors.Where(clr =>
(GetColorDifferenceAboveTarget(AverageColorOfBitmap, clr, (float)200) > 0)
&& (GetBrightnessAboveTarget(AverageColorOfBitmap, clr, (float).125) > 0))
.OrderBy(clr => GetColorDifferenceAboveTarget(
AverageColorOfBitmap, clr, (float)200));
return AcceptableColors.DefaultIfEmpty(Color.Aqua).First();
}
It's a good framework, but I need to work on selecting the "best" candidate from the list. Right now it's just returning "the qualifying color with the greatest color difference that meets the brightness criteria". However, this allows me to modify the float values (W3's "500 color difference required" is complete crap, zero KnownColors qualify) and experiment.
Support code:
private float GetBrightnessAboveTarget(Color AverageColorOfBitmap,
Color proposed, float desiredDifference)
{
float result = proposed.GetBrightness() - AverageColorOfBitmap.GetBrightness();
return result - desiredDifference;
}
private float GetColorDifferenceAboveTarget(Color avg, Color proposed,
float desiredDifference)
{
float r1 = Convert.ToSingle(MaxByte(Color.Red, avg, proposed));
float r2 = Convert.ToSingle(MinByte(Color.Red, avg, proposed));
float r3 = Convert.ToSingle(MaxByte(Color.Green, avg, proposed));
float r4 = Convert.ToSingle(MinByte(Color.Green, avg, proposed));
float r5 = Convert.ToSingle(MaxByte(Color.Blue, avg, proposed));
float r6 = Convert.ToSingle(MinByte(Color.Blue, avg, proposed));
float result = (r1 - r2) + (r3 - r4) + (r5 - r6);
return result - desiredDifference;
}
private byte MaxByte(Color rgb, Color x, Color y)
{
if (rgb == Color.Red) return (x.R >= y.R) ? x.R : y.R;
if (rgb == Color.Green) return (x.G >= y.G) ? x.G : y.G;
if (rgb == Color.Blue) return (x.B >= y.B) ? x.B : y.B;
return byte.MinValue;
}
private byte MinByte(Color rgb, Color x, Color y)
{
if (rgb == Color.Red) return (x.R <= y.R) ? x.R : y.R;
if (rgb == Color.Green) return (x.G <= y.G) ? x.G : y.G;
if (rgb == Color.Blue) return (x.B <= y.B) ? x.B : y.B;
return byte.MinValue;
}
This is more an answer to the original question. I call it a homemeade outline.
Using transparency plus the maximum and minimum brightness you can get (white&black) it creates good contrast, at least it looks pretty good on my screen.
It is a mixture of shadowing and transparency. I have subtracted a little from the red component to get the aqua you thought about..
It is creating first a darker version of the background by printing the text 1 pixel up left and the 1 pixel down right. Finally it prints a bright version on top of that. Note that it is not really using black and white because with its semi-transparent pixels the hue really it that of each background pixel.
For an actual printout you will have to experiment, especially with the font but also with the two transparencies!
Also you should maybe switch between white on a black shadow and black on a white highlight, depending on the brightness of the spot you print on. But with this homemeade outline it really will work on both dark and bright backgrounds, it'll just look a little less elegant on a bright background.
using (Graphics G = Graphics.FromImage(pictureBox1.Image) )
{
Font F = new Font("Arial", 8);
SolidBrush brush0 = new SolidBrush(Color.FromArgb(150, 0, 0, 0))
SolidBrush brush1 = new SolidBrush(Color.FromArgb(200, 255, 255, 222))
G.DrawString(textBox1.Text, F, brush0 , new Point(x-1, y-1));
G.DrawString(textBox1.Text, F, brush0 , new Point(x+1, y+1));
G.DrawString(textBox1.Text, F, brush1, new Point(x, y));
}
Edit: This is called from a button click but really should be in the paint event.
There the Graphics object and its using block G would be replaced by simply the e.Graphics event parameter..
I noticed that you are using a 'transparent' label to display the data to avoid the details of Graphics.DrawString and the Paint event.
Well that can be done and the result looks rather similar:
string theText ="123 - The quick brown fox..";
Label L1, L2, L3;
pictureBox1.Controls.Add(new trLabel());
L1 = (trLabel)pictureBox1.Controls[pictureBox1.Controls.Count - 1];
L1.Text = theText;
L1.ForeColor = Color.FromArgb(150, 0, 0, 0);
L1.Location = new Point(231, 31); // <- position in the image, change!
L1.Controls.Add(new trLabel());
L2 = (trLabel)L1.Controls[pictureBox1.Controls.Count - 1];
L2.Text = theText;
L2.ForeColor = Color.FromArgb(150, 0, 0, 0);
L2.Location = new Point(2, 2); // do not change relative postion in the 1st label!
L2.Controls.Add(new trLabel());
L3 = (trLabel)L2.Controls[pictureBox1.Controls.Count - 1];
L3.Text = theText;
L3.ForeColor = Color.FromArgb(200, 255, 255, 234);
L3.Location = new Point(-1,-1); // do not change relative postion in the 2nd label!
However you will note that due to the impossiblity of having really transparent controls in Winforms we need a little extra effort. You probably use a label subclass like this:
public partial class trLabel : Label
{
public trLabel()
{
SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
BackColor = Color.Transparent;
Visible = true;
AutoSize = true;
}
}
This seems to work. But in reality it only seems that way, because upon creation each label gets a copy of its current background from its parent. Which never gets updated. Which is why I have to add the 2nd & 3rd label not to the picturebox I display the image in, but to the 1st and 2nd
'transparent' label respectively.
There simply is not real transparency between Winforms controls unless you draw things yourself.
So the DrawString solution is not really complicated. And it gives you the bonus of allowing you to twist several properties of the Graphics object like Smoothingmode, TextContrast or InterpolationMode
Short suggestion: Just use black or white.
The algorithms are giving you a passing criteria, but not an algorithm for determining what colors meet that criteria. So, you will have to create such an algorithm. A naive algorithm would be to loop through every possible color, and calculate the color difference, then see if the difference is greater than 125, and if so you have a good color to use. Better, you could search for the color with the maximum difference.
But that's foolish - if I gave you the color R=152, G=138, B=129 - what do YOU think is a very good color to contrast that with? Just by gut, I'm gonna guess 0,0,0. I picked a color with the farthest possible R value, G value, and B value. If you gave me the color 50,200,75 I'd pick R=255, G=0, B=255. Same logic. So my algorithm is if R<128 choose R = 255, else choose R = 0. Same thing for G, and B.
Now that algorithm only picks RGB values that are 0 or 255. But if you don't like that, now you need a mathematical definition for what is "pretty" and I'll leave you to figure that out on your own. :-)

Cast Color Name to SolidColorBrush

How I can cast color name to SolidColorBrush type? I mean the word i.e. "Yellow".
SolidColorBrush scb = ??? ; // "Yellow"
Thank you!
For getting the color, use:
Color col=(Color)ColorConverter.ConvertFromString("Red");
Then create your brush:
Brush brush=new SolidColorBrush(col);
or if you can use the Colors-enum
Brush brush=new SolidColorBrush(Colors.Red);
If you already know the name of the color you can get the brush directly from Brushes:
SolidColorBrush scb = Brushes.Yellow; //scb seems a bit redundant at this point...
In code you should usually not use converters unless you have a string whose value you do not know.
You cannot cast one to another. They are simply different concepts. A brush is brush and color is, well, a color. Just because a brush "paints" in a specific color, doesn't mean you can interchange one with another.
You can however create a SolidColorBrush with a specific color, for example:
var brush = new SolidColorBrush(Color.Yellow);
// Yellow is green + red
SolidColorBrush yellowBrush = new SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 255, 0));

Setting Color Using Number in C#

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 drawString method be used for writing diagonal way

I am using c# 2005 i want to write string diagonally on image. But by default c# provides the option to write horizontally or vertically.
how we write diagonally?
Thanks
You can use the RotateTransform and TranslateTransform that are available on the Graphics class. Because using DrawString is GDI+ the transforms affects the drawing. So use something like this...
g.RotateTransform(45f);
g.DrawString("My String"...);
g.RotateTransform(-45f);
Don't forget to reverse the change though!
Do a Graphics.rotateTransform before the drawString call. Don't forget to reverse the change afterwards, as Phil Wright points out.
You can use this function.
void DrawDigonalString(Graphics G, string S, Font F, Brush B, PointF P, int Angle)
{
SizeF MySize = G.MeasureString(S, F);
G.TranslateTransform(P.X + MySize.Width / 2, P.Y + MySize.Height / 2);
G.RotateTransform(Angle);
G.DrawString(S, F, B, new PointF(-MySize.Width / 2, -MySize.Height / 2));
G.RotateTransform(-Angle);
G.TranslateTransform(-P.X - MySize.Width / 2, -P.Y- MySize.Height / 2);
}
Like this
u have right..It can be done in that way..BUT text will be written from top to bottom always and I'm not sure u can change it from bottom to top.. cheers
There is another way to draw a text vertically which is built in the C#. There is no need of explicit graphics transformation. You can use the StringFormat class. Here is a sample code which draws a text vertically:
StringFormat sf = new StringFormat();
sf.FormatFlags = StringFormatFlags.DirectionVertical;
e.Graphics.DrawString("My String", this.Font, Brushes.Black, PointF.Empty, sf);

Categories