GDI+如何更改线条平滑模式?

7

如何改变PowerPacks.LineShape的smoothingMode?

我尝试使用以下代码(一个继承了LineShape的类):

  Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    Dim g As Graphics = e.Graphics   

    ' no difference when changing the SmoothingMode ' 
    g.SmoothingMode = SmoothingMode.AntiAlias 

    Using pen As New Pen(Color.Blue, 3)
      g.DrawLine(pen, X1, Y1, X2, Y2)
    End Using

    ' MyBase.OnPaint(e) '
  End Sub

我总是得到同样的结果,就像这样:

alt文本 http://lh6.ggpht.com/_1TPOP7DzY1E/S3v1IbxlbCI/AAAAAAAADD4/q1Y9kP8wJ0g/s800/Capture2.png

=======

编辑

更新测试:

  Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    Dim g As Graphics = e.Graphics

    Dim oldmode As SmoothingMode = g.SmoothingMode

    Using pen As New Pen(Color.Blue, 3)
      g.SmoothingMode = SmoothingMode.AntiAlias
      g.DrawLine(pen, X1, Y1, X2, Y2)
      g.SmoothingMode = SmoothingMode.None
      g.DrawLine(pen, X1 + 50, Y1, X2 + 50, Y2)
    End Using

    g.SmoothingMode = oldmode
    g.Flush()

    'MyBase.OnPaint(e)'
  End Sub

结果(不考虑标签和圆圈):

alt文本 http://lh3.ggpht.com/_1TPOP7DzY1E/S447qYvTqzI/AAAAAAAADE8/eP3kCLqQJbk/s800/Capture2.png

显然平滑模式没有被考虑进去...


你是说这条线没有抗锯齿效果吗?无论设置如何? - Finglas
4个回答

4

SmoothingMode肯定会影响你的输出结果。

以下是我最近使用的一些设置,用于调整图像大小并尽可能地减少质量损失:

graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

InterpolationMode(插值模式)对于您的示例可能不太相关,但PixelOffsetMode(像素偏移模式)可能很重要。让我启动一个快速测试应用程序。

更新:这是一个快速测试应用程序, SmoothingMode(平滑模式)明显影响我绘制的线条。

private void Form1_Load(object sender, EventArgs e)
{
    foreach (var value in Enum.GetValues(typeof(SmoothingMode)))
    {
        _ComboBoxSmoothingMode.Items.Add(value);
    }

    foreach (var value in Enum.GetValues(typeof(PixelOffsetMode)))
    {
        _ComboBoxPixelOffsetMode.Items.Add(value);
    }

    _ComboBoxPixelOffsetMode.SelectedIndex = 0;
    _ComboBoxSmoothingMode.SelectedIndex = 0;
}

private void _ButtonDraw_Click(object sender, EventArgs e)
{
    using (Graphics g = _LabelDrawing.CreateGraphics())
    {
        g.Clear(Color.White);

        if (_ComboBoxPixelOffsetMode.SelectedItem != null && (PixelOffsetMode)_ComboBoxPixelOffsetMode.SelectedItem != PixelOffsetMode.Invalid)
        {
            g.PixelOffsetMode = (PixelOffsetMode)_ComboBoxPixelOffsetMode.SelectedItem;
        }

        if (_ComboBoxSmoothingMode.SelectedItem != null && (SmoothingMode)_ComboBoxSmoothingMode.SelectedItem != SmoothingMode.Invalid)
        {
            g.SmoothingMode = (SmoothingMode)_ComboBoxSmoothingMode.SelectedItem;
        }

        using (Pen pen = new Pen(Color.Blue, 3))
        {
            g.DrawLines(pen, new[] { new Point(0, 0), new Point(25, 50), new Point(_LabelDrawing.Width - 25, _LabelDrawing.Height - 50), new Point(_LabelDrawing.Width, _LabelDrawing.Height), });
        }
    }
}

SmoothingMode: AntiAlias                             None

SmoothingMode.AntiAlias http://www.ccswe.com/temp/SmoothingMode_AntiAlias.png SmoothingMode.None http://www.ccswe.com/temp/SmoothingMode_None.png

更新:正如Morbo所指出的,如果在PaintEventArgs中呈现给您的Graphics对象不是最终用于显示的Graphics对象,则更改平滑度可能没有任何效果。虽然如果那是来自内存Image之类的Graphics对象,我不会期望有这样的巨大差异。

希望我能提供更多信息。也许如果我更好地理解LineShape对您的意义以及使用它而不仅仅是使用其中一个Graphics.DrawLine()方法的原因,就可以了。

我质疑您使用LineShape的原因是,您正在覆盖它的OnPaint并绘制自己的线条。似乎您可以简化应用程序并摆脱LineShape,但也许我错过了什么。


更新:好的,那么您使用LineShape的原因就有意义了。此时我唯一能提供的建议是在面板或LineShape中重写OnPaint,在调用基本事件之前尝试设置平滑模式。类似于:

protected override void OnPaint(PaintEventArgs e)
{
    e.Graphichs.SmoothingMode = SmoothingMode.AntiAlias;
    base.OnPaint(e);
}

谢谢,Cory。然而我画的不是简单的线条,而是使用了重写 PowerPacks.LineShape OnPaint 的方式,这可能有影响。编辑。阅读了 Morbo 的评论。将尝试更改父级。 - serhio
最后,我不明白平滑模式的更改对线条绘制有什么影响,当我覆盖OnPaint并且完全不使用基本的OnPaint逻辑来绘制自定义线条时。 - serhio
@serhio:不确定我理解了没有。您是在说,如果取消注释 MyBase.OnPaint(e)SmoothingMode 就能起作用吗? - Cory Charlton
@serhio:在你的例子中,你重写的是谁的OnPaint?是LineShape还是Panel?(我甚至不知道LineShape有一个OnPaint)也许如果你尝试切换一下?我现在只是在瞎猜,因为我没有一个好答案 :-) - Cory Charlton
LineShape是一个GUI组件,因此它具有OnPaint方法。在我的代码中,我继承了LineShape,所以我重写了LineShape的OnPaint方法。 - serhio
显示剩余4条评论

2
根据Reflector显示,PowerPack LineShape组件使用容器原始Paint事件的Graphics对象进行绘制。更改给定的Graphics对象上的属性可能会影响容器中在您的形状之后绘制的所有其他内容。
在您的示例中,LineShape对象包含在什么内部?(如果它是自定义绘制控件,是否在某个时候创建了位图?如何创建?)如果它们在低色深度的自定义控件内部,那可能是问题的来源。在我的机器上,默认情况下,LineShape进行抗锯齿绘制。

+1:为深入挖掘PowerPack LineShape的实际作用而努力。 - Cory Charlton
我在自定义面板上绘制线形状。如何更改此面板的绘图属性?正如您所看到的,我重写了OnPaint,因此e.Graphics不是传递给父级图形的图形?另外,正如您从我的代码中看到的那样,我没有使用base.OnPaint。 - serhio
我似乎找到了问题,请看这里:http://stackoverflow.com/questions/2370738/have-you-had-probelms-developping-on-a-virtual-pc - serhio

2
你的显示设置是什么?至少是24位彩色吗?
我可以确认,从LineShape派生一个类并像你展示的那样重写OnPaint,确实会像预期的那样影响线条渲染。我还可以证实,Power Pack 3.0和Visual Studio 2010中的版本都在LineShape.DrawInternal方法中明确使用AntiAlias。
我从一个空白的.NET 2.0 Windows Forms应用程序开始。我添加了以下类,它几乎与你的类相同,并添加了一个只包含ShapeContainer和一个对角线MyLine形状的表单。
Imports Microsoft.VisualBasic.PowerPacks

Public Class MyLine
    Inherits LineShape

    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

        Dim g As Graphics = e.Graphics

        'g.SmoothingMode = SmoothingMode.AntiAlias '

        Using pen As New Pen(Color.Blue, 3)
            g.DrawLine(pen, X1, Y1, X2, Y2)
        End Using

        'MyBase.OnPaint(e) '

    End Sub

End Class

如果我按原样运行上面的代码,线条会出现锯齿状。如果我取消注释SmoothingMode设置,线条就会变得平滑。
所以它肯定应该可以工作。我知道这似乎是个愚蠢的问题,但你有没有检查过调试器中是否执行了你的代码?你尝试在DrawLine之后立即调用Graphics.Flush()了吗?
此外,你使用的PowerPack版本是哪个?就像我说的,我可以清楚地在Reflector中看到LineShape.DrawInternal专门在try/finally块中将SmoothingMode设置为AntiAlias。它在返回之前恢复旧的平滑模式。但在你的示例中,你甚至不应该触发这个方法,因为你没有调用基本方法。

我使用最新版本的PowerPack - 3.0。我还在另一个特别创建的新项目上进行了测试... AntiAlias在那里工作...有点奇怪。 - serhio
我似乎找到了问题,请看这里:http://stackoverflow.com/questions/2370738/have-you-had-probelms-developping-on-a-virtual-pc - serhio
啊,是的,在Windows Vista之前,远程桌面只支持16位色彩深度。这就是原因。 - Josh

0

这个问题出现在我的开发模式中:通过虚拟PC上的远程桌面连接。

在我的情况下,RDC没有考虑到AntiAlias图形属性。

更多细节:您在虚拟PC上开发时遇到过问题吗?

感谢大家参与,很抱歉这不是一个真正的.NET问题。


很可能是颜色深度的问题,因为Vista及以上版本的RDP肯定会进行抗锯齿处理。区别在于Vista支持高颜色深度。 - Josh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接