DrawingContext.DrawLine: Перо не имеет полной непрозрачности?
Когда я рисую что-то подобное (просто случайные рисунки здесь):
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, которые используют Brush). Странно даже с цветами из LinearGradientBrush фона нижележащей сетки (argh).Я хотел бы, чтобы они были 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 ответа
С RenderTargetBitmap есть две проблемы сглаживания или подпикселирования:
1.
Отключение субпикселов для самого растрового изображения (например, когда оно отображается в UIElement). это решается путем применения:
RenderOptions.SetBitmapScalingMode(image1, BitmapScalingMode.NearestNeighbor);
(где image1 - объект изображения WPF).
Поддерживается только для.NET 4 и выше. В вашем конкретном случае это не имеет значения, так как линии отображаются попиксельно.
2.
Отключение субпикселов при рендеринге INTO RenderTargetBitmap. Это может быть достигнуто методом RenderOptions.SetEdgeMode со значением параметра EdgeMode.Aliased.
ОДНАКО, этот метод будет работать, только если:
Метод вызывается для объекта DrawingGroup.
Сглаженная геометрия вкладывается только через обычный составной чертеж (например, если DrawingGroup содержит прямоугольник с VisualBrush, инкапсулирующий DrawingVisual, содержимое этого DrawingVisual будет сглажено, даже если вы использовали этот метод).
Таким образом, вы можете переписать ваш код следующим образом:
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;
Размещенный вами код рисует несколько тонких линий рядом друг с другом. У каждого из них сглаживание и размытые грани. Я предполагаю, что эффект смешивания непрозрачности, который Вы описали, происходит из-за этого.
Если вы нарисовали одну толстую линию (т.е. с шириной 10), эффект не появится.
Итак, решение зависит от того, чего именно вы пытаетесь достичь:
- Вы можете попытаться отключить сглаживание, если это удовлетворительно, для получения дополнительной информации об этом посмотрите здесь: Отключение сглаживания на образе WPF
- рисовать линии с помощью пера, который имеет большую ширину, т.е.
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 и на сайте, на который есть ссылка
Я столкнулся с той же проблемой при программном рендеринге в DrawingContext
, Единственный способ, который работает, это использовать GuidelineSet
: http://wpftutorial.net/DrawOnPhysicalDevicePixels.html
Другой (более простой) способ здесь:
Для вашего примера вам просто нужно создать класс как:
public class AliasedDrawingVisual : DrawingVisual
{
public AliasedDrawingVisual()
{
this.VisualEdgeMode = EdgeMode.Aliased;
}
}
и замените ваш экземпляр DrawingVisual на 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;