DrawEllipse: Antialiasing broken with PenAlignment

2019-08-24 04:42发布

问题:

As suggested by @TaW on this previous question, I setted PenAlignment.Inset to draw the circle inside the Bitmap, but this caused another problem.


I want to draw a circle on a specified Bitmap with antialiasing.

SmoothingMode.AntiAlias

The problem is that, when I use PenAlignment.Inset, the antialiasing doesn't work correctly!
Instead, with PenAlignment.Center, it works correctly...
Any suggestion to resolve this problem?

Bitmap layer = new Bitmap(80, 80);
using (Graphics g = Graphics.FromImage(layer))
{
    using (Pen p = new Pen(Color.Black, 4))
    {
        p.Alignment = PenAlignment.Inset;
        g.SmoothingMode = SmoothingMode.AntiAlias;
        g.DrawEllipse(p, new Rectangle(0, 0, layer.Width, layer.Height));
    }
}
pictureBox3.Size = new Size(100, 100);
pictureBox3.Image = layer;


(Note the bugs on the left image)

回答1:

Deflating the bounding rectangle by 1/2 of the pen's stroke width should solve this problem. By "deflate", I mean pull in all 4 sides towards the rectangle's center by 1/2 pen width:

float halfPenWidth = p.Width*0.5f;
g.DrawEllipse(p, new RectangleF(halfPenWidth, halfPenWidth, layer.Width - p.Width, layer.Height - p.Width));

or plugging in a hardcoded pen width of 4:

g.DrawEllipse(p, new Rectangle(2, 2, layer.Width - 4, layer.Height - 4));

Note that the full pen width must be subtracted from the rectangle's width and height in order to pull the right and bottom sides in by 1/2 pen width while keeping the rectangle centered on the same point.

Using this code with pen alignment centered, 1/2 of the stroke width will be drawn outside of the rectangle at the points where the ellipse touches the rectangle, but it will still be drawn inside the bitmap.