2

I'm working on some image transformations using ASP.NET/C#/GDI+. I have a method that looks like this to make a rectangular image round:

public static Image MakeRound(Image img)
{
    Bitmap bmp = new Bitmap(img.Width, img.Height);

    GraphicsPath gp = new GraphicsPath();
    Graphics gr = Graphics.FromImage(bmp);

    using (gp)
    {
        gp.AddEllipse(0, 0, img.Width, img.Height);
        using (gr)
        {
            gr.SetClip(gp);
            gr.DrawImage(img, Point.Empty);
        }
    }
    return bmp;
}

It takes a square image and then an ellipse is added that is as big as the image. I then use SetClip to remove everything that lies outside the path and return a round image. This works as intended.

The returned image is then drawn onto another (larger) image at a certain position and the resulting composite image is saved as a file. A real world example of how to use this could be adding a logo or a watermark to an existing image. Here is some code from this operation:

// Get backdrop image from server
string backdropPath = Server.MapPath("/img/backdrop.jpg");
System.Drawing.Image backdrop = Bitmap.FromFile(backdropPath);

// Create a graphics object to work with
Graphics gra = Graphics.FromImage(backdrop);
gra.DrawImage(MakeRound(smallerImage), new Point(50,50));

// Save the new image
backdrop.Save(saveFilePath);

The only problem is that the edges of the superimposed/round/returned image are a bit rough. I'd like to make its edges smoother so it blends in better with the larger background image it's superimposed upon.

Are there any anti-aliasing parameters that I could use? Do you think that this smoothing should be done in the method above or is it applied when the round image is superimposed on the bigger backdrop?

All pointers and tips are most welcome!

tkahn
  • 1,407
  • 2
  • 21
  • 37

3 Answers3

1

Most examples you'll find for this either:

  1. Use a brush to draw the background, or
  2. Use SetClip to remove the part of the image you don't want

But there are problems with both if you want a transparent background:

  1. You can't draw with a transparent brush. It just does nothing.
  2. SetClip won't give you an anti-aliased edge, as you've noticed.

I found this answer that works well, 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;
}

Instead of trying to crop the image, this creates a new, transparent image first, then draws a cut-out of the image on top.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
1

The technique you're looking for is called Feathering, ie: feathered edges is a form of anti-aliasing applied at the edge of a drawn image.

Take a look at this post on soft edges in GDI+. It may be applicable to your scenario.

Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178
  • Yes, I think it's something along these lines I'm looking for. When I apply Dan Byströms technique to my solution I get feathered edges on the round images that I'm superimposing. So it works! The only thing I'm a bit concerned about is the fact that there's a block of unsafe code (with pointers) in this solution. At first I got an error but I fixed that by adding an unsafe compiler option in web.config. – tkahn Jan 31 '12 at 13:39
  • @tkahn you may find that unsafe is a problem in an ASP.NET context. A workaround would be to use GetPixel/SetPixel on the bitmaps to transfer the alpha channel across instead, although it will be a lot slower. – Dr. Andrew Burnett-Thompson Jan 31 '12 at 14:16
0

Try setting the SmoothingMode to HighQuality, http://msdn.microsoft.com/en-us/library/system.drawing.graphics.smoothingmode.aspx.

Also set InterpolationMode to HighQualityBicubic, http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.interpolationmode.aspx.

Richard Schneider
  • 34,944
  • 9
  • 57
  • 73