How to crop an image to a circle in c# / winforms?

2019-07-03 23:48发布

问题:

EDIT: the code given in the "duplicate" question didn't solve the problem for me.

The main problem I'm having is that I can't simply use CSS and radius, which would be easy.

It's an image being loaded in, in a winforms page/project. I have to try and make a square/rectangle image into a circle. I've tried following 2 methods (results will be posted beneath each):

public Image RoundCorners(Image StartImage, int CornerRadius, Color BackgroundColor)
{
    CornerRadius *= 2;
    Bitmap RoundedImage = new Bitmap(StartImage.Width, StartImage.Height);

    using (Graphics g = Graphics.FromImage(RoundedImage))
    {
        g.Clear(BackgroundColor);
        g.SmoothingMode = SmoothingMode.AntiAlias;

        Brush brush = new TextureBrush(StartImage);

        GraphicsPath gp = new GraphicsPath();
        gp.AddArc(0, 0, CornerRadius, CornerRadius, 180, 90);
        gp.AddArc(0 + RoundedImage.Width - CornerRadius, 0, CornerRadius, CornerRadius, 270, 90);
        gp.AddArc(0 + RoundedImage.Width - CornerRadius, 0 + RoundedImage.Height - CornerRadius, CornerRadius, CornerRadius, 0, 90);
        gp.AddArc(0, 0 + RoundedImage.Height - CornerRadius, CornerRadius, CornerRadius, 90, 90);
        g.FillPath(brush, gp);

        return RoundedImage;
    }
}

Code being called:

Image StartImage = Image.FromFile(medwImg);
Image RoundedImage = btn.RoundCorners(StartImage, 100, Color.Transparent);
btn.NormalImage = RoundedImage;

Result:

If you change the radius value to 145 you can see this result:

As you can see, not good either.

This is my second method:

public Image CropToCircle(Image srcImage, Color backGround)
{
    Image dstImage = new Bitmap(srcImage.Width, srcImage.Height, srcImage.PixelFormat);
    Graphics g = Graphics.FromImage(dstImage);

    using (Brush br = new SolidBrush(backGround))
    {
        g.FillRectangle(br, 0, 0, dstImage.Width, dstImage.Height);
    }

    GraphicsPath path = new GraphicsPath();
    path.AddEllipse(0, 0, dstImage.Width, dstImage.Height);
    g.SetClip(path);
    g.DrawImage(srcImage, 0, 0);        

    return dstImage;
}

Code being called:

Image StartImage = Image.FromFile(medwImg);
Image RoundedImage = btn.CropToCircle(StartImage, Color.FromArgb(0, 101, 167));
btn.NormalImage = RoundedImage;

Here the result is as follows:

This looks better, but still isn't a nice full circle.

My best guess is the 2nd method is closest by to a good solution, but I don't know what to do next in order for a full circle to be created from the source image.

回答1:

I've found an answer to my problem, using following method:

// makes nice round ellipse/circle images from rectangle images
public Image ClipToCircle(Image srcImage, PointF center, float radius, Color backGround)
{
    Image dstImage = new Bitmap(srcImage.Width, srcImage.Height, srcImage.PixelFormat);

    using (Graphics g = Graphics.FromImage(dstImage))
    {
        RectangleF r = new RectangleF(center.X - radius, center.Y - radius,
                                                 radius * 2, radius * 2);

        // enables smoothing of the edge of the circle (less pixelated)
        g.SmoothingMode = SmoothingMode.AntiAlias;

        // fills background color
        using (Brush br = new SolidBrush(backGround))
        {
            g.FillRectangle(br, 0, 0, dstImage.Width, dstImage.Height);
        }

        // adds the new ellipse & draws the image again 
        GraphicsPath path = new GraphicsPath();
        path.AddEllipse(r);
        g.SetClip(path);
        g.DrawImage(srcImage, 0, 0);

        return dstImage;
    }
}

Code calling the method:

Image StartImage = Image.FromFile(medwImg);
Image RoundedImage = btn.ClipToCircle(StartImage, new PointF(StartImage.Width/2, StartImage.Height/2), StartImage.Width/2, Color.FromArgb(0, 101, 167));
btn.NormalImage = RoundedImage;

Now I get beautiful round images (result):