Find the color of a point in a LinearGradientBrush

January 28, 2008 at 7:54 am | Posted in .Net, C#, Silverlight, WPF | 6 Comments

I became intrigued by the problem of finding the color at any point of a rectangle that has been filled with a LinearGradientBrush.  There is are techniques for doing this by essentially sampling the pixel at a rendered point but I wanted to approach the problem algorithmically.

I developed the following method which receives a rectangle object that has been filled with a LinearGradientBrush and a point relative to the upper left corner of the rectangle and returns the calculated color at that point.  There are no restrictions on the Start/Stop Points or the number of GradientStops.  The ColorInterpolationMode can be either SRgbLinearInterpolation (default) or ScRgbLinearInterpolation.  The GradientSpreadMethod is required to be the default (Pad).

There are two methods below:

Color GetColorAtPoint(Rectangle r, Point p) – finds the color at any point of a LinearGradientBrush filled rectangle.

private Double dist(Point px, Point po, Point pf) – helper method for GetColorAtPoint.

To use, copy both methods to your class and call GetColorAtPoint() with a rectangle and point.

//Calculates the color of a point in a rectangle that is filled
//with a LinearGradientBrush.
private Color GetColorAtPoint(Rectangle theRec, Point thePoint)
    //Get properties
    LinearGradientBrush br = (LinearGradientBrush)theRec.Fill;
    double y3 = thePoint.Y;
    double x3 = thePoint.X;
    double x1 = br.StartPoint.X * theRec.ActualWidth;
    double y1 = br.StartPoint.Y * theRec.ActualHeight;
    Point p1 = new Point(x1, y1); //Starting point
    double x2 = br.EndPoint.X * theRec.ActualWidth;
    double y2 = br.EndPoint.Y * theRec.ActualHeight;
    Point p2 = new Point(x2, y2);  //End point
    //Calculate intersecting points 
    Point p4 = new Point(); //with tangent
    if (y1 == y2) //Horizontal case
        p4 = new Point(x3, y1);
    else if (x1 == x2) //Vertical case
        p4 = new Point(x1, y3);
    else //Diagnonal case
        double m = (y2 - y1) / (x2 - x1);
        double m2 = -1 / m;
        double b = y1 - m * x1;
        double c = y3 - m2 * x3;
        double x4 = (c - b) / (m - m2);
        double y4 = m * x4 + b;
        p4 = new Point(x4, y4);
    //Calculate distances relative to the vector start
    double d4 = dist(p4, p1, p2);
    double d2 = dist(p2, p1, p2);
    double x = d4 / d2;
    //Clip the input if before or after the max/min offset values
    double max = br.GradientStops.Max(n => n.Offset);
    if (x > max)
        x = max;
    double min = br.GradientStops.Min(n => n.Offset);
    if (x < min)
        x = min;
    //Find gradient stops that surround the input value
    GradientStop gs0 = br.GradientStops.Where(n => n.Offset <= x).OrderBy(n => n.Offset).Last();
    GradientStop gs1 = br.GradientStops.Where(n => n.Offset >= x).OrderBy(n => n.Offset).First();
    float y = 0f;
    if (gs0.Offset != gs1.Offset)
        y = (float)((x - gs0.Offset) / (gs1.Offset - gs0.Offset));
    //Interpolate color channels
    Color cx = new Color();
    if (br.ColorInterpolationMode == ColorInterpolationMode.ScRgbLinearInterpolation)
        float aVal = (gs1.Color.ScA - gs0.Color.ScA) * y + gs0.Color.ScA;
        float rVal = (gs1.Color.ScR - gs0.Color.ScR) * y + gs0.Color.ScR;
        float gVal = (gs1.Color.ScG - gs0.Color.ScG) * y + gs0.Color.ScG;
        float bVal = (gs1.Color.ScB - gs0.Color.ScB) * y + gs0.Color.ScB;
        cx = Color.FromScRgb(aVal, rVal, gVal, bVal);
        byte aVal = (byte)((gs1.Color.A - gs0.Color.A) * y + gs0.Color.A);
        byte rVal = (byte)((gs1.Color.R - gs0.Color.R) * y + gs0.Color.R);
        byte gVal = (byte)((gs1.Color.G - gs0.Color.G) * y + gs0.Color.G);
        byte bVal = (byte)((gs1.Color.B - gs0.Color.B) * y + gs0.Color.B);
        cx = Color.FromArgb(aVal, rVal, gVal, bVal);
    return cx;
//Helper method for GetColorAtPoint
//Returns the signed magnitude of a point on a vector with origin po and pointing to pf
private double dist(Point px, Point po, Point pf)
    double d = Math.Sqrt((px.Y - po.Y) * (px.Y - po.Y) + (px.X - po.X) * (px.X - po.X));
    if (((px.Y < po.Y) && (pf.Y > po.Y)) ||
        ((px.Y > po.Y) && (pf.Y < po.Y)) ||
        ((px.Y == po.Y) && (px.X < po.X) && (pf.X > po.X)) ||
        ((px.Y == po.Y) && (px.X > po.X) && (pf.X < po.X)))
        d = -d;
    return d;

The method works by projecting the input point onto the vector that is described by the LinearGradientBrush Start/Stop points.  There are special cases for horizontal and vertical lines.  The width of the line is calculated as well as the relative distance of the projected point from the StartPoint (using the dist() method).  The GradientStops are ordered and two stops are found that are the closest the projected point.  The color channel values are interpolated based on the relative position of the projected point and these two stops.  The values are assembled into a color and returned.

You can download a demo of this method here.


No Events Tab in WPF Designer — No Problem!

January 12, 2008 at 11:52 am | Posted in Cider, Visual Studio 2008, WPF | Leave a comment

When I first encountered ‘Cider’, the designer for WPF, I was somewhat shocked and disappointed that the Properties window did not have an Events tab as in the Windows Forms designer where one can easily browse the available events and simply double-click to hook one up to an automatically generated event handler stub.  Was I going to have to now rely on the documentation to find the events and carefully type in the connection code and handler?

I said, “Very inconvenient!  Too much work.  I’ll stick to Forms!”  From the forums, I see that I was not alone.

Fortunately, Intellisense makes this a non-issue.  Just know the technique:

In Xaml, put your cursor after the control’s tag (Button, Ellipse, Grid etc) and press the spacebar.  Intellisense will list all of the properties and events that are available.  Note the events are marked with the lightning bolt.  Select an event from the list and hit the tab key twice.  This will add the event to the control’s attribute list and add an event handler stub in your code behind. 


Note that the effort is almost identical to using the Events tab in Windows Forms.  The only difference is that you have to scroll through a combined list of properties and events and instead of double clicking, you ‘double tab’.

Or, if you wish, in the code behind, in the window (or page) constructor, type the name of the control (button1 for example) then a ‘.’.  Intellisense will list all properties, methods and events.  Select the event.  Then type ‘+=’ and hit the tab key twice.  Your event will be hooked up along with an event handler stub.  (This is the same as designing with Forms.)

Of course there are some common default events that can be hooked up just by double clicking on the object in the designer.  That is, if you double click on a button in the designer, you get a Button_Click event hookup.

The only thing that is really lacking is the little synopsis of what the event does that is provided by the Properties/Events window in the Forms designer; however, the event names are usually pretty self explanatory.

Hooking up events in the WPF designer are no big deal thanks to the Intellisense support and a little knowledge of how to use it.

Kaxaml: The XAML editor for me

January 11, 2008 at 8:38 am | Posted in Silverlight, WPF | Leave a comment

I highly recommend Kaxaml for your XAML editor.  Not only does it look and work great but it also has some very useful features not found on other XAML editors.

I won’t bother listing all of the features that you can read about here, but my favorites are Intellisense support (with code completion!), snippets including a generous collection of simple control styles and the ability to create and save your own, drag and drop, a beautiful color picker, and a XAML scrubber.

With other XAML editors, I thought, “what’s the point? Just use the designer in Visual Studio.”  But Kaxaml is one tool that I will use first to build and customize my UIs–largely due to its snippets, colorpicker and ease of use.  (I don’t use Blend.)

Download Kaxaml here:

Generating Reports in Visual C# 2008 Express Edition

January 3, 2008 at 7:18 pm | Posted in C#, Visual Studio 2008, WPF | 8 Comments

A common question on the MSDN C# Express forum is how do I generate reports?  That is, how does one get a printout of data?  The Standard and higher editions of Visual Studio have reporting services that allow reports to be easily designed in a WYSIWYG way.  But Express users must either buy a third party application (à la Crystal Reports–about $300 USD) or programmatically create the report using C# and GDI+ Classes.

Now with Visual C# 2008 Express Edition, there is a new option.  Windows Presentation Foundation (WPF) provides a set of classes for converting markup (XAML) to Microsoft’s XML Page Specification (XPS).  XPS documents can then be printed directly from your application or saved an viewed and printed by other applications and platforms.

With this system, there are a couple of options:  First, you can specify the report document directly in C# code much like you would using GDI+.  That is, you could place a textBlock or graphic at a specific x,y coordinate on a page using the properties of these elements.  The second option is almost as good as having a report designer like in the higher Visual Studio editions.  You can use the designer in Visual Studio to layout your report in a WPF grid so you can see exactly how your report should look when it is rendered.  Then it is a very simple matter to pass the name of this grid to XPS generating classes for printing or saving.

Printing and XPS in WPF are covered thoroughly in Chapter 15 of Sells & Griffiths, Programming WPF, O”Reilly.

The following example shows the routine for saving a grid1 (and all that it contains) to an XPS file.

private void button1_Click(object sender, RoutedEventArgs e)
    Microsoft.Win32.SaveFileDialog dialog = new Microsoft.Win32.SaveFileDialog();
    if (dialog.ShowDialog() == true)
        string xpsOutputPath = dialog.FileName;
        using (XpsDocument xpsFile = new XpsDocument(xpsOutputPath, FileAccess.Write))
            XpsDocumentWriter xpsdw = XpsDocument.CreateXpsDocumentWriter(xpsFile);



This routine requires adding a couple of references to the solution: ReachFramework and System.Printing.  You will need to also add some namespace references:

using System.Windows.Xps;
using System.IO;
using Microsoft.Win32;
using System.Windows.Xps.Packaging;

The code for printing directly is not much more complex and is described in the book.

With WPF one should be able to quickly and easily create a rich looking data report that can be printed or saved.

Blog at
Entries and comments feeds.