Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to have anti-aliasing when drawing a clipped image?

Currently, I'm successfully using the Graphics class to draw a non-rectangular clipped image (the turtle inside):

enter image description here

My code looks something like:

using (var g = Graphics.FromImage(image))
{
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;

    using (var gfxPath = new GraphicsPath())
    {
        gfxPath.AddEllipse(r);

        using (var region = new Region(r))
        {
            region.Exclude(gfxPath);

            g.ExcludeClip(region);

            g.DrawImage(turtleImage, r, r2, GraphicsUnit.Pixel);
        }
    }
}

This all works just as expected. What I do not know how to solve is to make the image border anti-aliased.

The image zoomed looks like:

enter image description here

I.e. the border where the image ends and the transparent "background" of the image starts is a rough cut, not a smooth alpha blending.

My question is:

Is it possible to clip a drawn image and having anti-aliasing active?

like image 206
Uwe Keim Avatar asked Sep 27 '13 14:09

Uwe Keim


People also ask

Does anti-aliasing reduce image quality?

Supersample Anti-Aliasing (SSAA)It makes your GPU render games at a higher resolution, and then it down-samples the image. The higher resolution increases the number of pixels, making the image look sharper. But again, the downside is that it requires a high-end and powerful GPU with additional video memory.

What is anti-aliasing in PNG?

Anti-aliasing is the smoothing of jagged edges in digital images by averaging the colors of the pixels at a boundary.

Does anti-aliasing reduce pixelation?

Spatial anti-aliasing helps reduce artifacting when displaying images. This technique requires a monitor that can display high-quality images at certain levels of resolution. A good monitor needs a display resolution of 1900×1080 pixels on horizontal and vertical axes.

What is anti-aliasing in editing?

A camera setting that prevents the appearance of vertical or horizontal lines (banding) when photographing images on TV and monitor screens. Antibanding may be automatic or have manual settings for 50 Hz and 60 Hz to ensure the frame rate is the same as the country's electrical grid.


3 Answers

If you want to go for full blown feathering you should consider taking a look at this article:

http://danbystrom.se/2008/08/24/soft-edged-images-in-gdi/

If you want a quick and easy solution you could probably draw the image first then draw a GraphicsPath on top of it using a solid white brush with antialiasing. You would do something like this:

Rectangle outerRect = ClientRectangle;
Rectangle rect = Rectangle.Inflate(outerRect, -20, -20);

using (Image img = new Bitmap("test.jpg"))
{
    g.DrawImage(img, outerRect);

    using (SolidBrush brush = new SolidBrush(Color.White))
    using (GraphicsPath path = new GraphicsPath())
    {
        g.SmoothingMode = SmoothingMode.AntiAlias;

        path.AddEllipse(rect);
        path.AddRectangle(outerRect);

        g.FillPath(brush, path);
    }
}
like image 55
Trevor Elliott Avatar answered Oct 16 '22 15:10

Trevor Elliott


The other answers here won't work if you want a transparent background because you cannot draw with a transparent brush - it doesn't do anything.

I found other answers that can do it (for example, using SetClip), but it doesn't come out with an anti-aliased edge.

I found this answer that works, but that one is designed to just round the corners, not make it a circle. So I modified it.

Here's how you can crop an image to a circle with a transparent background and anti-aliased edges:

/// <summary>
/// Crop the given image into a circle (or ellipse, if the image isn't square)
/// </summary>
/// <param name="img">The image to modify</param>
/// <returns>The new, round image</returns>
private static Bitmap CropCircle(Image img) {
    var roundedImage = new Bitmap(img.Width, img.Height, img.PixelFormat);

    using (var g = Graphics.FromImage(roundedImage))
    using (var gp = new GraphicsPath()) {
        g.Clear(Color.Transparent);

        g.SmoothingMode = SmoothingMode.AntiAlias;

        Brush brush = new TextureBrush(img);
        gp.AddEllipse(0, 0, img.Width, img.Height);
        g.FillPath(brush, gp);
    }

    return roundedImage;
}

The other answers draw the background color on top of the image. Instead, this creates a new, transparent image first, then draws a cut-out of the image on top.

like image 32
Gabriel Luci Avatar answered Oct 16 '22 17:10

Gabriel Luci


I'll like to share my solution, which is based on the selected answer. This code Resize and Crop an image into a Circle applying antialias to the edges. It also Prevents the loss of the image on Mouse Over or Window Resize. Cropped image can easily be saved.

    /// <summary>Redimensiona y recorta la imagen en forma de Circulo (con Antialias).</summary>
    /// <param name="srcImage">Imagen Original a Recortar</param>
    /// <param name="size">Tamaño deseado (en pixeles)</param>
    /// <param name="BackColor">Color de fondo</param>
    public static Image CropToCircle(System.Drawing.Image srcImage, Size size, System.Drawing.Color BackColor)
    {
        System.Drawing.Image Canvas = new System.Drawing.Bitmap(size.Width, size.Height, srcImage.PixelFormat);
        System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(Canvas);

        System.Drawing.Rectangle outerRect = new System.Drawing.Rectangle(-1, -1, Canvas.Width + 1, Canvas.Height + 1);
        System.Drawing.Rectangle rect = System.Drawing.Rectangle.Inflate(outerRect, -2, -2);

        g.DrawImage(srcImage, outerRect);

        using (System.Drawing.SolidBrush brush = new System.Drawing.SolidBrush(BackColor))
        using (System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath())
        {
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            path.AddEllipse(rect);
            path.AddRectangle(outerRect);

            g.FillPath(brush, path);
        }

        return Canvas;
    }

Usage: (Desired Size is 64x64 pix with White Background)

    System.Drawing.Image img = System.Drawing.Image.FromFile(@"E:\Mis Documentos\Mis imágenes\ergo-proxy-fullon-fight.jpg");
    System.Drawing.Image circle = Util.CropToCircle(img, new System.Drawing.Size(64,64), System.Drawing.Color.White);
    if (circle != null)
    {
        this.picUser.Image = circle;
    }
like image 30
Jhollman Avatar answered Oct 16 '22 16:10

Jhollman