Image を使って画像を表示させていると等倍で表示しているはずなのにぼやけてしまいました。
SnapsToDevicePixels や UseLayoutRounding では直らなかったので途方に暮れていたらいいものがありました。
blogs.msdn.microsoft.com
専用のコントロールを作っているので、Imageコントロールに移植します。
※2016/06/03 LayoutUpdatedイベントの処理を追記
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
public class Image : System.Windows.Controls.Image {
public Image() {
this.LayoutUpdated += Image_LayoutUpdated;
}
private Point _pixelOffset;
void Image_LayoutUpdated( object sender, EventArgs e ) {
Point pixelOffset = GetPixelOffset();
if( !AreClose( pixelOffset, _pixelOffset ) ) {
InvalidateVisual();
}
}
private bool AreClose( Point point1, Point point2 ) {
return AreClose( point1.X, point2.X ) && AreClose( point1.Y, point2.Y );
}
private bool AreClose( double value1, double value2 ) {
if( value1 == value2 ) {
return true;
}
double delta = value1 - value2;
return ( ( delta < 1.53E-06 ) && ( delta > -1.53E-06 ) );
}
protected override Size MeasureOverride( Size constraint ) {
var bitmapSource = Source as BitmapSource;
if( bitmapSource != null ) {
Size measureSize = new Size();
PresentationSource ps = PresentationSource.FromVisual( this );
if( ps != null ) {
Matrix fromDevice = ps.CompositionTarget.TransformFromDevice;
Vector pixelSize = new Vector( bitmapSource.PixelWidth, bitmapSource.PixelHeight );
Vector measureSizeV = fromDevice.Transform( pixelSize );
measureSize = new Size( measureSizeV.X, measureSizeV.Y );
}
return measureSize;
}
return base.MeasureOverride( constraint );
}
protected override void OnRender( System.Windows.Media.DrawingContext dc ) {
_pixelOffset = GetPixelOffset();
dc.DrawImage( this.Source, new Rect( _pixelOffset, DesiredSize ) );
}
private Point GetPixelOffset() {
Point pixelOffset = new Point();
PresentationSource ps = PresentationSource.FromVisual( this );
if( ps != null ) {
Visual rootVisual = ps.RootVisual;
pixelOffset = this.TransformToAncestor( rootVisual ).Transform( pixelOffset );
pixelOffset = ApplyVisualTransform( pixelOffset, rootVisual, false );
pixelOffset = ps.CompositionTarget.TransformToDevice.Transform( pixelOffset );
pixelOffset.X = Math.Round( pixelOffset.X );
pixelOffset.Y = Math.Round( pixelOffset.Y );
pixelOffset = ps.CompositionTarget.TransformFromDevice.Transform( pixelOffset );
pixelOffset = ApplyVisualTransform( pixelOffset, rootVisual, true );
if( rootVisual.TransformToDescendant( this ) != null ) {
pixelOffset = rootVisual.TransformToDescendant( this ).Transform( pixelOffset );
}
}
return pixelOffset;
}
private Point TryApplyVisualTransform( Point point, Visual v, bool inverse, bool throwOnError, out bool success ) {
success = true;
if( v != null ) {
Matrix visualTransform = GetVisualTransform( v );
if( inverse ) {
if( !throwOnError && !visualTransform.HasInverse ) {
success = false;
return new Point( 0, 0 );
}
visualTransform.Invert();
}
point = visualTransform.Transform( point );
}
return point;
}
private Point ApplyVisualTransform( Point point, Visual v, bool inverse ) {
bool success = true;
return TryApplyVisualTransform( point, v, inverse, true, out success );
}
private Matrix GetVisualTransform( Visual v ) {
if( v != null ) {
Matrix m = Matrix.Identity;
Transform transform = VisualTreeHelper.GetTransform( v );
if( transform != null ) {
Matrix cm = transform.Value;
m = Matrix.Multiply( m, cm );
}
Vector offset = VisualTreeHelper.GetOffset( v );
m.Translate( offset.X, offset.Y );
return m;
}
return Matrix.Identity;
}
}
論理ピクセルとデバイスピクセルのズレはもういや><