when I draw something like that (just random drawings here):
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;
}
}
the colors of DrawLine and DrawEllipse mix. (I figured out that it's only with DrawLine which uses a pen, and not with other forms like Rectangle and Ellipse, that use a Brush). Strangely even with colors from the LinearGradientBrush of a underlying Grids' Background (argh). I would like them to be z-Ordered with full opacity each.
Here the XAML code:
<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>
Thanks for any help.
There are two issues of antialiasing, or sub-pixeling, with RenderTargetBitmap:
1.
Disabling sub-pixeling for the bitmap itself (for example, when it is rendered within a UIElement). this is resolved by applying:
RenderOptions.SetBitmapScalingMode(image1, BitmapScalingMode.NearestNeighbor);
(where image1 is the WPF Image object).
It is only supported for .NET 4 and above. In your specific case it doesn't matter as the lines are rendered pixel-after-pixel.
2.
Disabling sub-pixeling when rendering INTO the RenderTargetBitmap. It can be achieved by the method RenderOptions.SetEdgeMode with the parameter value of EdgeMode.Aliased.
HOWEVER, this method will work only if:
The method is called for a DrawingGroup object.
The antialiased geometry is nested only through regular drawing composite (for example, if the DrawingGroup contains a rectangle with a VisualBrush encapsulates a DrawingVisual, the content of that DrawingVisual will be antialiased even if you used that method).
Thus you can rewrite your code as follows:
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;
The code You posted is drawing mutliple thin lines next to each other. Each of them is antialiased and has got its sides blurred. I suppose the opacity mixing effect You described occurs because of this.
If you drew one thick line (i.e. with 10 width) the effect would not appear.
So, the solution depends on what exactly You are trying to achieve:
- you can try to disable antialiasing, if this is satisfactory, for more information about this, take a look here: Disabling antialiasing on a WPF image
- draw lines with a Pen that has got greater width, i.e.
new Pen(Brushes.Black, 2)
- in this particular case of drawing lines close to each other, you can increment the counter by 0.5f instead of 1, so replace
for (int i = 0; i <= 100 - 1; i++)
withfor (float i = 0.0f; i <= 100 - 1; i+=0.5f)
. - if you don't mind writing some more code, you can create your own custom Bitmap class that doesn't make images blurry. Some solution is available here http://www.nbdtech.com/Blog/archive/2008/11/20/blurred-images-in-wpf.aspx and in the site referenced there
Another (easier) way here:
https://stackoverflow.com/a/10257614/2463642
For your example, you just have to create a class like:
public class AliasedDrawingVisual : DrawingVisual
{
public AliasedDrawingVisual()
{
this.VisualEdgeMode = EdgeMode.Aliased;
}
}
and replace your DrawingVisual instance with AliasedDrawingVisual:
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;
I have encountered the same issue with programmatic rendering to DrawingContext
. The only only way that works is to use GuidelineSet
: http://wpftutorial.net/DrawOnPhysicalDevicePixels.html
来源:https://stackoverflow.com/questions/11000866/drawingcontext-drawline-pen-has-no-full-opacity