Graphics.DrawPath and LinearGradientBrush issue

699 Views Asked by At

In relation to this question that I asked a few weeks ago now

LinearGradientBrush does not render correctly

Consider the following code:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    Rectangle rect = new Rectangle(100, 100, 200, 100);
    using(LinearGradientBrush brush = new LinearGradientBrush(rect, Color.Red, Color.Blue, 90))
    {
        using(Pen pen = new Pen(brush, 1))
        {
            pen.Alignment = PenAlignment.Inset;
            e.Graphics.DrawRectangle(pen, rect);
        }
    }            
}

Produces this result...

Brush

Why is there a red line where there should be a blue line, and how do I fix this?

Pen.Alignment = PenAlignment.Inset didn't work!

2

There are 2 best solutions below

6
On BEST ANSWER

Pens (or the Graphics DrawMethods) have a tendency to draw outside their boundaries. I think Microsoft considered that a feature, but I never understood it.

Try using a smaller rectangle for the pen:

using (var brush = new LinearGradientBrush(rect, Color.Red, Color.Blue, 90)) {
  using (Pen pen = new Pen(brush, 1)) {
    e.Graphics.DrawRectangle(pen, new Rectangle(rect.X, rect.Y,
                                                rect.Width - 1, rect.Height - 1));
  }
}

enter image description here

4
On

OK, to sum it up: DrawRectangle always overdraws by 1 pixel (*) and the LinearGradientBrush therefore restarts with the 1st color.

Yes, Lars got one solution, but here is an interesting alternative:

  brush.WrapMode = WrapMode.TileFlipXY;

This makes sure that the gradient doesn't start at the beginning when it has to overdraw but reverses in both directions, so the extra pixel is drawn in the right Color and you don't need to manipulate one of the two the Rectangle Sizes..

Well ok, if you need total precision it is probably second best, as the last row and column will have the same color as their neighbours..but not having to deal with two sizes may be worth it..

(*) Which is why you can't use it to draw a 1x1 square/pixel. Instead you need to use FillRectangle..