質問
WPFでアンチエイリアスグラフィックスを使用しようとすると、奇妙なレンダリングの問題が発生します。
こちらは簡易版です。
次の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>
そして次の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);
}
}
}
クロップする四角形のエッジがあるアンチエイリアスで奇妙なレンダリングの問題が発生します(プログラムを実行すると、それはかなり明白になりますが、クロップする四角形がパスを切り詰めているかすんだ灰色の線です)
特定のピクセルにコントロールを配置するなどのさまざまな手法を試し、これがこの問題を解決することを期待してさまざまなコントロールにSnapsToDevicePixelsを設定しました(余分なかすんだグレーバンドを削除します)が、何も役に立たないようです。
アイデアはありますか
解決
これは、当然ながら、ウィンドウはピクセル境界で整列しているが、ウィンドウ内のグリッドは整列していない可能性があるためです。これを修正することはそれほど難しくありませんが、何をすべきかを理解するのに時間がかかることがあります。
SnapsToDevicePixelsと呼ばれる素晴らしい機能があり、すべてを正しく整列させる必要があります。そして、悲しいことに、何らかの理由で、それはまったく動作しないようです(これは理解されているバグのようです)。どうすればいいですか?
最初に、グリッドはピクセル境界で整列する必要があります(つまり、中央揃えではない、またはウィンドウの水平方向または垂直方向に奇数のピクセルがある場合はグリッド、したがってグリッドの内容、位置がずれます。)
しかし、対処すべき他の問題があります...スクロールバーをスクロールし始めるとすぐに、アーティファクトが再表示されます!これは、スクロールバーが必ずしもコンテンツを整数ピクセルでスクロールするとは限らないためです。それに対処するために、ScrollViewerでいくつかのイベントをキャプチャして、スクロール位置を整数値に設定します。
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);
}
}
それを行うと、すべてがうまくいくようです。
(サイドビューとして、ScrollViews内で画像の問題を抱えている人のために...同じ問題に直面している場合、これは画像が拡大縮小、回転、など...画像をピクセル境界に揃えようとしている限り、これでうまくいきます)