绘制剪切图像时可以进行抗锯齿处理吗?

Posted

技术标签:

【中文标题】绘制剪切图像时可以进行抗锯齿处理吗?【英文标题】:Possible to have anti-aliasing when drawing a clipped image? 【发布时间】:2013-10-03 21:17:30 【问题描述】:

目前,我正在成功使用Graphics class 绘制一个非矩形的裁剪图像(里面的乌龟):

我的代码如下所示:

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);
        
    

这一切都按预期工作。我不知道如何解决是使图像边框抗锯齿。

放大后的图像如下:

即图像结束的边界和图像的透明“背景”开始的边界是粗剪,而不是平滑的 alpha 混合。

我的问题是:

是否可以剪切绘制的图像并启用抗锯齿功能?

【问题讨论】:

刚刚找到this article,我认为这将是要走的路。现在就试试。 【参考方案1】:

如果您想获得完整的羽毛,您应该考虑看看这篇文章:

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

如果您想要一个快速简单的解决方案,您可以先绘制图像,然后使用具有抗锯齿功能的纯白色画笔在其顶部绘制 GraphicsPath。你会做这样的事情:

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);
    

【讨论】:

谢谢,这也是我在上面评论的:-) 对不起,g哥是什么?【参考方案2】:

如果您想要透明背景,此处的其他答案将不起作用,因为您无法使用透明画笔进行绘制 - 它没有任何作用。

我找到了其他可以做到的答案(例如,使用SetClip),但它没有消除锯齿边缘。

我发现this answer 可行,但它的设计只是为了圆角,而不是使它成为一个圆圈。所以我修改了它。

以下是如何将图像裁剪为具有透明背景和消除锯齿边缘的圆形:

/// <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;

其他答案在图像顶部绘制背景颜色。相反,这会首先创建一个新的透明图像,然后在顶部绘制图像的切口。

【讨论】:

【参考方案3】:

我想分享我的解决方案,该解决方案基于所选答案。 此代码将图像调整大小并裁剪为圆形,对边缘应用抗锯齿。它还可以防止鼠标悬停或调整窗口大小时图像丢失。裁剪后的图像可以轻松保存。

    /// <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;
    

用法:(所需尺寸为 64x64 像素,白色背景)

    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;
    

【讨论】:

【参考方案4】:

我在构建具有透明背景的圆形个人资料图片时遇到了同样的问题。我最终确定的策略是将图像大小调整为任意倍数(在我的情况下为 5x),进行裁剪操作,然后在使用 SmoothingMode.AntiAlias 时将其缩小回原始大小。我在图片上得到了一个很好的羽毛边缘。

这是一个黑客吗?是的。它是高性能的吗?嗯,应该不会吧。它有效吗?完美!

【讨论】:

代码会使这成为一个更好的答案。

以上是关于绘制剪切图像时可以进行抗锯齿处理吗?的主要内容,如果未能解决你的问题,请参考以下文章

CGContextClip 抗锯齿问题

透明位图上的抗锯齿文本

在JAVA中对多边形进行抗锯齿时出现鬼白线

第5个示例 递归反射抗锯齿

如何使用QSGGeometry对自定义QQuickItem进行抗锯齿处理

画布中的抗锯齿大文本