DrawingContext.DrawLine:Pen没有完全不透明度?

时间:2012-06-12 16:31:38

标签: wpf transparency opacity z-order drawingcontext

当我画这样的东西时(这里只是随机图纸):

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DrawingVisual visual = new DrawingVisual();
        DrawingContext context = visual.RenderOpen();

        Pen pen = new Pen(Brushes.Black, 1);

        context.DrawEllipse(Brushes.YellowGreen, pen, new Point(0,0), 40, 40);

        for (int i = 0; i <= 100 - 1; i++)
          context.DrawLine(new Pen(Brushes.Black, 1), new Point(0, i), new Point(i, i));

        context.Close();

        RenderTargetBitmap bmp = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);

        bmp.Render(visual);
        image1.Source = bmp;
    }
}

DrawLine和DrawEllipse混合的颜色。(我发现只有DrawLine使用笔,而不是使用其他形式,如Rectangle和Ellipse,使用画笔)。奇怪的是,即使是基础网格背景(argh)的LinearGradientBrush的颜色。 我希望它们是z-Ordered,每个都具有完全不透明度。

这里是XAML代码:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Image Name="image1" Stretch="None" />
</Window>

感谢您的帮助。

4 个答案:

答案 0 :(得分:5)

RenderTargetBitmap有两个抗锯齿或子像素问题:

1

禁用位图本身的子像素化(例如,在UIElement中渲染时)。通过应用:

解决了这个问题
    RenderOptions.SetBitmapScalingMode(image1, BitmapScalingMode.NearestNeighbor);

(其中image1是WPF图像对象)。

仅支持.NET 4及更高版本。 在您的特定情况下,无关紧要,因为线条以像素为单位进行渲染。

2

在渲染INTO RenderTargetBitmap时禁用子像素。它可以通过方法RenderOptions.SetEdgeMode实现,参数值为EdgeMode.Aliased。

但是,此方法仅在以下情况下有效:

  • 为DrawingGroup对象调用该方法。

  • 抗锯齿几何体仅通过常规绘图合成嵌套(例如,如果DrawingGroup包含一个带有VisualBrush的矩形封装DrawingVisual,即使您使用该方法,该DrawingVisual的内容也将被抗锯齿化。)< / p>

因此,您可以按如下方式重写代码:

    DrawingVisual visual = new DrawingVisual();
    DrawingGroup group = new DrawingGroup();

    Pen pen = new Pen(Brushes.Black, 1);

    group.Children.Add(new GeometryDrawing(Brushes.YellowGreen, pen, new EllipseGeometry(new Point(0,0), 40, 40)));

    for (int i = 0; i <= 100 - 1; i++)
      group.Children.Add(new GeometryDrawing(null, new Pen(Brushes.Black, 1), new LineGeometry(new Point(0, i), new Point(i, i))));

    RenderOptions.SetEdgeMode(group, EdgeMode.Aliased);

    DrawingContext context = visual.RenderOpen();
    context.DrawDrawing(group);
    context.Close();

    RenderTargetBitmap bmp = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);

    bmp.Render(visual);
    image1.Source = bmp;

答案 1 :(得分:2)

您发布的代码是在彼此旁边绘制多条细线。他们每个都是抗锯齿的,并且其侧面模糊。我想你所描述的不透明混合效果是因为这个。

如果您画了一条粗线(即宽度为10),则不会出现效果。

因此,解决方案取决于您要实现的目标:

  • 你可以尝试禁用抗锯齿功能,如果这是令人满意的,有关详细信息,请查看此处:Disabling antialiasing on a WPF image
  • 使用宽度更大的笔绘制线条,即new Pen(Brushes.Black, 2)
  • 在这种绘制线条彼此接近的特殊情况下,您可以将计数器增加0.5f而不是1,因此将for (int i = 0; i <= 100 - 1; i++)替换为for (float i = 0.0f; i <= 100 - 1; i+=0.5f)
  • 如果你不介意再写一些代码,你可以创建自己的自定义Bitmap类,它不会使图像模糊。这里有一些解决方案http://www.nbdtech.com/Blog/archive/2008/11/20/blurred-images-in-wpf.aspx以及那里引用的网站

答案 2 :(得分:1)

另一种(更简单)方式:

https://stackoverflow.com/a/10257614/2463642

对于您的示例,您只需要创建一个类:

    public class AliasedDrawingVisual : DrawingVisual
    {
        public AliasedDrawingVisual()
        {
            this.VisualEdgeMode = EdgeMode.Aliased;
        }
    }

并使用AliasedDrawingVisual替换您的DrawingVisual实例:

    DrawingVisual visual = new AliasedDrawingVisual(); // Here is the only change
    DrawingContext context = visual.RenderOpen();

    Pen pen = new Pen(Brushes.Black, 1);

    context.DrawEllipse(Brushes.YellowGreen, pen, new Point(0,0), 40, 40);

    for (int i = 0; i <= 100 - 1; i++)
      context.DrawLine(new Pen(Brushes.Black, 1), new Point(0, i), new Point(i, i));

    context.Close();

    RenderTargetBitmap bmp = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);

    bmp.Render(visual);
    image1.Source = bmp;

答案 3 :(得分:1)

我遇到了与givenInMat的程序化渲染相同的问题。唯一有效的方法是使用std::vector<cv::Mat> filesDVec; cv::Mat temp; cv::FileStorage fs("tileDesc.yml", cv::FileStorage::READ); for(size_t i = 0; i < (imgVec.size()); i++){ cv::string iValue = std::to_string(i); cv::string filename = "Image_" + iValue; fs[filename] >> temp; filesDVec.push_back(temp); } fs.release(); http://wpftutorial.net/DrawOnPhysicalDevicePixels.html

相关问题