Download Gradiator_Demo.zip - 136.4 KB
Download Gradiator_Src.zip - 527.3 KB
I must admit I got a basic understanding of Gradient Brushes and
hurriedly started coding. But I didn't really get a good understanding of
Gradients until I started playing with this utility. At that point I realized
that I needed to go back and do some further research on the subject. So I've
been researching, upgrading, researching,...well you get the idea. And since I
was upgrading the Gradiator application I thought I would relate what I learned
while this research/upgrade process has been going on.
In the latest upgrade I have;
- Changed the UI, hopefully to make it a tad easier to use
- Added a brush manager with the ability to Load/Save your
favorite brushes.
- Color selector with ability to Load/Save color palettes
- A status bar with ability to modify position and size, view the
current shape type and cycle through shapes.
I'm not going to go knee deep into explaining graphics, GDI+ or even
gradients, instead I'm going to give a brief overview for each of the important
concepts then I'll move on and and get into how to create the gradients that you
see/have seen in this article. A lot of them were easy, some I stumbled on and
some I really had to scratch my head and just try different things but overall
I've managed to create some pretty nice graphics and you can too.
First
thing we need to do is get a basic understanding of the concepts, so this first
section is devoted to that.
Concepts
Introduction to Gradients
Linear Gradient
Brush
PathGradientBrush
Blending
Color Blending
Alpha
Blending
Using Gradiator
An Example
References and Links
I need to add a disclaimer here and state that for some
applications GDI+ may be slow because at this point it doesn't take advantage of
the hardware acceleration features built in to many of the graphics cards,
hopefully in the future this will be solved. But until that time there are
things we can do to make sure we're getting the most from GDI+.
1. Use double buffering
2. Only redraw areas that need
to be redrawn.3. Avoid drawing in controls such
as Panel or PictureBox, instead use the parent controls client area.
4. If
you can use DrawImageUnscaled instead of DrawImage, the auto scaling is nice but
eats resources.
I'm sure there more tips on performance but these are the
ones I've personally found to be helpful.
As I've used/developed this application I have added functionality that
I've found useful and time saving. There is a lot more that could be done with
this application and if you have any suggestions or want to add to it please
feel free. I have provided default and Web color palettes and a brush palette
with some interesting brushes, if you come up with any brushes you find
interesting I would be interested in seeing them. Barney says "share" :)
As always, I hope this article is instructive and the application useful. If
you learn as much from it as I did writing it, then we are both
rich.
Mike
Introduction to Gradients
My interpretation of a gradient is the
progression from one color to another at a defined angle. Webster's definition:
"ascending or descending with a uniform slope"
The two types of gradients
that will be covered here are the Linear and Radial gradient brushes.
Figure 1. Simple Linear Gradient
The gradient in Figure 1 is the simplest type of
linear gradient it "Starts" with the Color White and progresses to the color Red
at an angle of 0 degrees.
The code used to draw the
above gradient is;
private void label1_Paint(object sender, PaintEventArgs e)
{
LinearGradientBrush lgb = new LinearGradientBrush(label1.ClientRectangle, clr1, clr2, 0f, true);
e.Graphics.FillRectangle(lgb, label1.ClientRectangle);
lgb.Dispose();
}

Figure 2. Simple Path Gradient
The gradient in Figure 2 is the simplest type of radial
gradient also starts at one color and progresses to another but the axis begins
at a center point with a center color and progresses outward to the end color,
also White and Red in the above figure.
The code to draw the gradient in
Figure 2 is;
private void label1_Paint(object sender, PaintEventArgs e)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(label1.ClientRectangle);
PathGradientBrush pgb = new PathGradientBrush(gp);
pgb.CenterPoint = new PointF(label1.ClientRectangle.Width / 2, label1.ClientRectangle.Height / 2);
pgb.CenterColor = Color.White;
pgb.SurroundingColors = new Color[] { Color.Red };
e.Graphics.FillPath(pgb, gp);
pgb.Dispose();
gp.Dispose();
}
Linear Gradient Brushes
Now that we've got the basics out of the way we can find out what else we can
do with gradients. Two interesting methods that can be used to alter the way in
which gradients are drawn are the; SetSigmaShapeBell and SetTriangularShape
methods.
Figure 3. Using the SetSigmaShapeBell
property with linear gradient brush
Figure 4. Using the SetBlendTriangularShape
with linear gradient brush
Figure 3 and 4 show the result of using the SetSigmaShapeBell and
SetBlendTriangularShape methods with the middle of the label as the focus point
and a drop off rate of 50%. As you can see from the figures the bell shape
method distributes the center color over a broader range than its triangular
counterpart.
The constructors for both brushes have parameters that allow one
to determine the focal point and the rate of fall off from that point. The
example code below shows how to use a linear gradient brush to draw the gradient
of Figure 4.
private void label1_Paint(object sender, PaintEventArgs e)
{
LinearGradientBrush lgb = new LinearGradientBrush(label1.ClientRectangle, clr1, clr2, 0f, true);
lgb.SetBlendTriangularShape(.5f, 1.0f);
e.Graphics.FillRectangle(lgb, label1.ClientRectangle);
lgb.Dispose();
}
We've seen this code before but with the addition
of the highlighted text. The first parameter defines the focal point and the
second the drop off scale. In this case I used a drop off rate of 100% for
dramatic/visual effect.
You can also use an additional property that
controls the overall brightness and ratio of red to green to blue, the Gamma
correction property. For a detailed discussion of gamma correction refer to http://www.siggraph.org/education/materials/HyperGraph/color/gamma_correction/gamma_intro.html
Path Gradient Brushes
The Path Gradient brush employs the same methods as the Linear Brush and
behaves the similarly but the outcome looks different because the Path Gradient
brush works radially. One thing worth mentioning here is that when setting the
focus, focus starts at the outer edge (from 0) and works toward the center (to
1.0). To set the center point use the Path Gradients center point
property.
Figure 5. Path Gradient Brush using the SetTriangularBlendShape
method
In Figure 5, on the left we are using the SetTriangularBlendShape method and
setting the Focal point to 50% and again the Focal Scale is set to 100% and on
the right the focal point has been shifted to the upper left corner. Using the
SetTriangularBlendShape and the SetSigmaShapeBell methods in conjunction with
the FocusScales which is similar to the focus parameter for both methods,
defines the scaling of the gradient.
Note: oddly enough the FocusScales work
just the opposite of there equivalents in that they start at the center (0) and
work out (1).
The code used to produce the left hand drawing in Figure 5 is list below.
private void label1_Paint(object sender, PaintEventArgs e)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(label1.ClientRectangle);
PathGradientBrush pgb = new PathGradientBrush(gp);
pgb.CenterPoint = new PointF(label1.ClientRectangle.Width / 2, label1.ClientRectangle.Height / 2);
pgb.CenterColor = Color.White;
pgb.SurroundingColors = new Color[] { Color.Red };
pgb.SetTriangularBlendShape(.5f, 1.0f);
pgb.FocusScales = new PointF(0f, 0f);
e.Graphics.FillPath(pgb, gp);
pgb.Dispose();
gp.Dispose();
}
As an example of using the SetTriangularBlendShape method with the
FocusScales property we will use the left drawing in Figure 5. If we use the
above code but change the FocusScales property to (.5f, .5f) the focal point
will be 75% out from the center of the shape.
Blending
With blending we can define a custom gradient and therefore take control over
how the gradient is rendered. Blending allows us to override the normal
blending behavior and set points along the path where we define alternate drop
off rates. We still go from a start color to an end color but as you can see in
the figure below the drop off rates at the various positions allow much greater
control over the rendering process.


Figure
6. Blending using the LinearGradientBrush (left) and PathGradientBrush
(right)
A couple of terms are in order
here;
In Figure 6 above I have numbered the
positions and combined with the listing below you will get a better
understanding of how Blending works.
This code is used to produce the right
hand drawing in Figure 6.
private void label1_Paint(object sender, PaintEventArgs e)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(label1.ClientRectangle);
PathGradientBrush pgb = new PathGradientBrush(gp);
pgb.FocusScales = new PointF(0f, 0f);
Blend blnd = new Blend();
blnd.Positions = new float[] { 0f, .25f, .5f, .75f, 1f };
blnd.Factors = new float[] { 1f, 0f, 1f, 0f, 1f };
pgb.Blend = blnd;
e.Graphics.FillPath(pgb, gp);
pgb.Dispose();
gp.Dispose();
}
Both gradients were drawn using the same values and from what we've learned
so far the outcome is predictable. The only difference being the PathGradient
brush, the positions radiate outward from the center point and at the positions
noted you can see the transitions made.
Note: There are three things that are very important here;
-
The number of positions and factors must be the same.
-
The first position must be 0 and the last 1.
-
The number of positions, factors and colors should not exceed the number of
points in the graphics point list. If it does I turn off Color Blending or GDI+
throws an exception. (Working on this)
If either of these conditions is not met GDI+ will throw an
exception.
Color
Blending
Color blending works much the same as
regular blending except that at each position instead of a drop off value we can
use a color. An interesting observation can be made at this point, if we move
point 2 to where the dotted line is, this will move the end position for Red
over to where the arrow is and effectively make point 3 useless which is pretty
much the way we would expect it to behave. But if either of the two objects are
semitransparent then the color in the resultant union is a blend of the two
colors and will in itself be an alpha blend. Alpha blending will be covered in
the next section.


Figure 7. Color Blend using
LinearGradient Brush
Figure 7 shows an example of a shape
that employs the color blend features of the linear gradient Brush. As you can
see the color at each position is a different color of the rainbow at evenly
spaced positions along a gradient path of 0 degrees. The snippet below was used
to draw Figure 7.
private void label1_Paint(object sender, PaintEventArgs e)
{
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(label1.ClientRectangle);
PathGradientBrush pgb = new PathGradientBrush(gp);
pgb.CenterPoint = new PointF(label1.ClientRectangle.Width / 2, label1.ClientRectangle.Height / 2);
pgb.CenterColor = Color.White;
pgb.SurroundingColors = new Color[] { Color.Red };
pgb.SetTriangularBlendShape(.5f, 1.0f);
pgb.FocusScales = new PointF(0f, 0f);
e.Graphics.FillPath(pgb, gp);
pgb.Dispose();
gp.Dispose();
}
Alpha Blending
While I was searching for a good explanation for alpha blending I ran across
the following from an article "Alpha Blending Tutorial" writen by Toshihiro
Horie and it pretty much says it all.
What is alpha blending? It's a way of mixing the colors of two images
together to form a final image.
An example of naturally occurring alpha
blending is a rainbow over a waterfall. If
you think of the rainbow by
itself as one image, and the background waterfall as another,
then the final
image can be formed by alpha blending the two together. Pixel artists and
programmers sometimes call alpha blending "translucency"-- it is the same
thing.
In addition, when the blending factor changes dynamically over time,
alpha blending is
called "cross fade" or "dissolve."
To add alpha blending to your drawings mearly adjust the first
argument in the Color.FromArgb method call, this is the alpha channel parameter
and can have a value from 0 - 255, 0 being completely transparent and 255 being
opaque. Things get interesting when you start using alpha blending it adds
another dimension to the problem. The reason for this is that where the shapes
overlap it forms a blend of the the two colors and the opacity level of each. I
can akin this to an artist when they mix colors on there palettes to form a new
color. In the same way you can adjust the levels of each...add a little more
white, a little less black, etc..
Using Gradiator
I have used this application as I've been developing it, and have
used it as a kind of a doodle pad. I get an idea and scratch my head for a
while then I start doodling and go smoke a cig, think a little more and then
save it, try it, then go back and tweek it until I get what I want. Problem is
the more I use Gradiator my skills get better and I run across something that
looks better and I just can't seem to finalize the dang thing. The About dialog
is a perfect example since I want it to reflect what can be done with gradients.
Check it out, there are only 4 objects drawn on the form and two are text, the
other two are the background and the button.
Overview
In a nutshell what we are doing here is creating brushes to render
our shapes. When we first create a shape, the default brush assigned to it is
a solid brush with a White background and a border. You change the properties
of the brush using the Properties editor located in the TabControl to the right
of the works pace area. I couldn't put all the controls I needed in once area
and have room for a decent works pace and I didn't want a bunch of floaters so I
compromised and divided the functionality as I saw it so ended up with three
tabs and they are;
General Properties - This tab contains the common properties
for the brush selected.
Brushes - Brush Management
Blend - Blend
property editor
The Shape Editor
I don't think a lot needs to be said about the shape editor itself,
its just a basic graphics editor that allows you to create, move and resize a
few basic shapes.
To create an shapeClick on the shape desired,
move mouse into the canvas area, press the left mouse button at the place you
want to start the shape and drag out until you get to the end point and release
the mouse button.
To select a Shape:
Click anywhere within the
shape boundary. Something I did a little different when selecting the shapes
that is bothersome in some cases but a really nice feature for most editing. In
my selection logic if you have two objects and one sits on top of the other, I
select the smaller of the two if they are the same I pick the last one drawn
(top of z-order) but if the top shape is not transparent then you will not see
the shape underneath unless you bring it to the top, by selecting it and
pressing the right mouse button and choosing the "bring to top" option. I did
this because when I'm working with two objects it allows me to see what I'm
doing when I'm positioning the shape in the background. Once you start using
Gradiator you will appreciate this option.
To move a shape:Press and hold the left mouse
button anywhere within the shape boundary and move it to the new location
To resize an object:Press and hold the left
mouse button within the resizing rectangles and drag to new shape.
You can
only resize in the positive direction right now. I'm still working on this
problem.
Brush Manager
The Brush manager is the repository for
brushes that you've created and want to use in the future. You can;
-
Create a new Brush palette
-
Load a palette - On startup a default palette is
loaded called "default palette.xml" in the startup directory.
Import
-
a palette, appending it to current palette
-
Save the current palette to file
To use brushes from the palette, use the shape
editor to create a shape primitives and if not already selected, select it then
click on any one of the thumbnail images from the Brush Managers list to
associate it with the primitive. These primitives, either opaque
or semitransparent, may then be overlaid one on top of another to produce
composite images.
Now to save an brush once you have it just so select it and
right click, choose the "Save Brush" option and it will be added to the Brush
Managers list. Be sure to save before you exit the application.
Blend Editor
Here is where you can really get artistic
and create some nice images. I'm by no means an artist,, but after spending a
short time working with blends it became easier to visualize what I wanted to do
and how to achieve the images shown in this article. (even a blind squirrel gets
a nut occasionally)
The only real advice I can give you here is
just play with it!
To use the Editor select an object, go to
the Blend tab and select either Blend or the Color Blend style by using the
CheckBox to turn blending on or off then selecting the type of blend desired,
regular blending being the default. Blending is only available when using the
linear gradient or path gradient brushes for obvious reason.
The type of
blending determines which parameters are meaningful, for;
LinearGradientBrush - Position and
Factor
PathGradientBrush - Color and Position
Color Selector
For Color selection I decided to devise a
way to have one selector active. To do this I put a color swatch next to each
color property. In some cases this is kind of a pain but overall it turned out
to be a good solution. To select a color go to the color selector and pick a
color, then for the property you wish to modify left click on the swatch. To
transfer the color from the property swatch to the primary color in the Color
selector right click on the properties swatch.
On startup a default color
palette "color palette.xml" is loaded from the startup directory.
An Example
When I first started I had a little trick I
would do if I got confused. I would choose a color/position combo in the area
that I was confused about and dramatically change the color. This would give me
a general idea what are the blend covered and the color distribution if opacity
was involved. The point here is if you don't understand the way I'm explaining
or I'm explaining it wrong is to go into Gradient create a shape and associate
this brush with it and change the color or just play with it. I tried thin
borders, thick borders and a lot of different things before I got to this.
Shading around the edge took a little head scratchin (I told ya I ain't no
artiste')

So here was what I was thinking when I
created this;
-
Picture frame-ish so I can overlay
something is this area or blend it to suit
-
A nice clean transition between
?client area? and border
-
Shading for the border, hopefully
adding a little 3D look to it.
Well lets get started, while I'm puttin
a Saliva CD and getting a quick smoke you can start up Gradiator or not (smoke
em if ya got em) and then we'll begin.
Ok, I'm back.
So lets start at the center and wind our
way out:
-
Start Position (0) Lets start with a
light/powder blue
-
82 we want to end this transition
abruptly so we gradiate to a steel blue/gray, just a tad darker so it isn't
plain
-
85 we want a dark shaded area make it
appear sunken. (85 - 82 = 3) so we have a 3 pixel shaded area
-
86 after the darker shaded area we
want a thin light area, back to the steel gray, to represent that its raised,
and to start the edge blend.
-
92 at this point we've gradiated from
the steel color and we want to darken it, fade the colors out. If we bypassed
this step the transition would be linear and would look like a ramp instead of
having the curved edge look as in the above example.
A couple of observations can be
made;
-
If we change the first two colors and
make them transparent the it will be a true frame since the client area is
transparent!
-
Pay attention to perspective. Look at
the border size on the sides as compared to the top and bottom. If it were
square this wouldn't be a problem. Just something to keep in
mind.
Well that's about it...Good
luck!
Mike
References and Links
All the illustrations in this article where
generated using the Gradiator application.
An article can be found here on CP that covers Alpha
blending
Transparency Tutorial with C# - Part 1 by Joe Pardue
http://www.codeproject.com/cs/media/CsTranspTutorial1.asp
Painting with Solid Colors and Gradients
OverviewThis is a very good article that gives an
overview of the concepts used in this application for ColorBlending.
msdn2.microsoft.com/en-us/library/ms754083.aspx
If your interested in learning about the basics of color this is a good
site
http://www.rgbworld.com/color.html
Color Tools - Reference Charts, Swatches, Software, and More
http://websitetips.com/color/tools/
The physics of light and color
http://micro.magnet.fsu.edu/primer/lightandcolor/index.html
A good site for beginners, covers the basics of
GDI+
http://www.bobpowell.net/beginnersgdi.htm
Two applications similar in concept to this one; both
named GradientMaker
http://www.robinland.com/en/free-product/gradientmaker/#changes
http://www.codeproject.com/dotnet/GradientMaker.asp
An excellent book for graphics programming in general is;
"Graphics
Programming with GDI+" by Mahesh Chand
Microsoft .NET Development Series,
ISBN 0-321-16077-0