Anti-aliasing artifacts in WPF

我只是一个虾纸丫 提交于 2019-12-07 18:12:31

问题


I have a bizarre rendering issue when I'm trying to use anti-aliased graphics in WPF.

Here's a simplified version.

If I use the following XAML

<Window x:Class="RenderingBug.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Width="300" Height="300">
    <Grid Name="myGrid" Background="AntiqueWhite" Width="250" Height="250">
        <ScrollViewer Name="myScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <Canvas Height="500" Width="500" Name="myCanvas" />
        </ScrollViewer>        
    </Grid>
 </Window>

And the following cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace RenderingBug
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            PathFigureCollection pfc = new PathFigureCollection();
            PathFigure pf = new PathFigure();
            pf.StartPoint = new Point(100, 20);
            LineSegment ls = new LineSegment();
            ls.Point = new Point(20, 100);
            PathSegmentCollection psc = new PathSegmentCollection();
            psc.Add(ls);
            pf.Segments = psc;
            pfc.Add(pf);
            PathGeometry pg = new PathGeometry(pfc);

            RectangleGeometry clippingRectangle = new RectangleGeometry(new Rect(0, 0, 80, 80));

            Path p1 = new Path();
            p1.ClipToBounds = true;
            p1.Clip = clippingRectangle;
            p1.StrokeDashCap = PenLineCap.Square;
            p1.Stroke = Brushes.Black;
            p1.StrokeThickness = 30;
            p1.Data = pg;
            myCanvas.Children.Add(p1);

            Path p2 = new Path();
            p2.ClipToBounds = true;
            p2.Clip = clippingRectangle;
            p2.StrokeDashCap = PenLineCap.Square;
            p2.Stroke = Brushes.White;
            p2.StrokeThickness = 10;
            p2.Data = pg;
            myCanvas.Children.Add(p2);
        }
    }
}

I get a strange rendering issue with the anti-aliasing where the cropping rectangle edge is (running the program, it will be fairly obvious, but it's a hazy gray line where the cropping rectangle is truncating the paths.)

I've tried various techniques like aligning the controls to specific pixels, and setting SnapsToDevicePixels on the various controls in the hopes that this would solve this issue (remove the extra hazy gray band), but nothing seems to help.

Any ideas?


回答1:


Turns out that this is because although the window is, of course, aligned on a pixel boundry, the grid within the window may not be. Fixing this isn't overly difficult, but it can take a while to figure out what to do.

There is a nice feature called SnapsToDevicePixels that should get everything aligned correctly. And, sadly, for whatever reason, it doesn't seem to work at all (this seems to be an understood bug). So what to do?

First, the grid must be aligned at a pixel boundry (ie not centered, or something like that since if the window has an odd number of pixels in either the horizontal or vertical direction then the grid, and hence the grid contents, will be misaligned.)

But then, there are other issues to deal with...as soon as you start to scroll the scroll bars, the artifact reappears! This is because the scrollbars do not necessarily scroll the content an integer number of pixels. To deal with that, I capture some events in the ScrollViewer to set the scrolling location to integer values.

private void workingAreaScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
{
    double w = e.NewSize.Width;
    double h = e.NewSize.Height;
    workingAreaScrollViewer.Width = Math.Round(w);
    workingAreaScrollViewer.Height = Math.Round(h);
}

private void Window_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.A)
    {
        workingAreaCanvas.Children.Remove(p2);
    }
    if (e.Key == Key.Z && p2.Parent != workingAreaCanvas)
    {
        workingAreaCanvas.Children.Add(p2);
    }
}

Do that, and all seems to be well.

(As a side note, for people that are having Image problems inside ScrollViews...if you're running into the same issue, this should fix that as well, so long as the Image isn't scaled, rotated, etc...so long as you're just trying to align the image to a pixel boundry, this should do the job.)



来源:https://stackoverflow.com/questions/467331/anti-aliasing-artifacts-in-wpf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!