読者です 読者をやめる 読者になる 読者になる

亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

SnapToDevicePixelsとUseLayoutRoundingの違い

WPF プログラミング .NET

WPF4でUseLayoutRoudningプロパティが追加されました。
こいつはWPFのサブピクセル描画に起因する画像のボヤケを取り除くための物になっています。

ところが,WPF3までにはSnapToDevicePixelsがありました。こいつも機能的にはほぼ同一だったはず。。。一体違いはなんなんでしょう?

まず一つは,StackOverflowのこの記事。
API Only - Stack Exchange

<Image Name="ImageOrderedList"
       Source="images/OrderedList.png"
       ToolTip="Ordered List"
       Margin="0,0,5,5"
       Width="20"
       Height="20"
       SnapsToDevicePixels="True"
       MouseUp="Image_MouseUp"
       MouseEnter="Image_MouseEnter"
       MouseLeave="Image_MouseLeave" />

上記XAMLがSnaptoDevicePixelを用いてもぼやけてしまうとのこと。何がぼやけるかというと,Image内の画像。
そしてこれはUseLayoutRoudningによって綺麗にぼけずに表示されるようになります。

この違いは? それについてはMSDNに言及があります。

基本的に、ピクセル スナップはガイドラインによって制御されます。ガイドラインは、ジオメトリの位置をデバイス ピクセル グリッドに合わせるのに役立ちます。通常は、SnapsToDevicePixels プロパティを使用してピクセル スナップを行うと、意図した結果が得られます。しかし、このプロパティを使用できない場合もあり (特に、Drawing オブジェクトを使用している場合や DrawingContext を直接処理する場合)、ピクセル スナップによって提供される目的の鮮明さを実現するために、ガイドラインの設定が必要になります。

Imageの中に表示する画像や,Contextをひったくって直接描画をかけている場合などは,SnapToDevicePixelsは効果がないようです。
あと,どうも経験上,PathにGeometryを流しこんで細かい描画をさせた時も,うまくピクセルスナップは効いてないので,単純にVisualTreeに表示されるエレメントの描画にしか効果は及ばない,というのが正しいと思います。

じゃあ,UseLayoutRoudning一択なの?となると,どうもMSDN的にはそのようです。

メモ
.NET Framework 4 以降、WPF ではレイアウトの丸めを利用できます。これは、サブピクセル レンダリングによる成果物の推奨される処理方法です。詳細については、UseLayoutRounding プロパティを参照してください。

なるほど,じゃあそれでFAなのね,と思っていますが,一点だけ気になる記述が。

Use of SnapToDevicePixels is not longer recommended for achieving pixel-perfect lines in WPF 4. There's actually a note on the MSDN doc page for SnapToDevicePixels.

As Josh said, UseLayoutRouting is a layout pass modifier whereas SnapToDevicePixels is calculated at render time. I haven't tested anything, but I would assume you'd see some differences when animating, as well as potentially some perf differences between the two, depending on how many times layout is called vs. render.

なんと,SnapToDevicePixelsはRender時の処理らしいですが,UseLayoutRoundingが(プロパティ名通り)レイアウト時に処理されるようです。
RenderTransformとLayoutTransformの違いを見るに,パフォーマンス的には恐らくSnapToDevicePixelsが有利,ということになるんでしょうか・・・?

とりあえずメモ書き程度に情報の整理をしてみました。