C# 在WPF应用程序中以像素精度显示图像
我想在WPF应用程序中显示一些图像,但是Microsoft聪明地将所有图像缩放到不正确的比例!我想要的是以像素精度显示图像。即,如果图像为50x50,则无论图像/屏幕的DPI设置如何,我都希望在屏幕上精确显示50像素和50像素 我尝试了以下方法,但无效: 将.png图像dpi设置为96。 在AssemblyInfo.cs中添加行[assembly:System.Windows.Media.DisabledPiaware]C# 在WPF应用程序中以像素精度显示图像,c#,wpf,image,C#,Wpf,Image,我想在WPF应用程序中显示一些图像,但是Microsoft聪明地将所有图像缩放到不正确的比例!我想要的是以像素精度显示图像。即,如果图像为50x50,则无论图像/屏幕的DPI设置如何,我都希望在屏幕上精确显示50像素和50像素 我尝试了以下方法,但无效: 将.png图像dpi设置为96。 在AssemblyInfo.cs中添加行[assembly:System.Windows.Media.DisabledPiaware] 问题是,我坐在远离屏幕的地方,所以在控制面板中,我将文本大小设置为更大。但
问题是,我坐在远离屏幕的地方,所以在控制面板中,我将文本大小设置为更大。但我可以看出图像大小不正确,因为当我在Photoshop中并排打开同一图像时,图像会变大和模糊。Dwayne需要创建一篇关于此问题的优秀博客文章,可以找到。该代码也可在同一位置获得。引用他的话: 下面包含的代码引入了一个名为位图的新类。位图是图像的替代品,但它不显示任何图像源,只显示位图源。这使我可以访问PixelWidth和PixelHeight属性以确定适当的大小。本课程的重要方面包括: 从UIElement而不是FrameworkElement派生,因为我不想要MinWidth、MaxWidth甚至Width之类的东西。 源可以设置为任何位图源。 测量时,它将返回相应的测量单位以显示位图的像素宽度和像素高度 渲染时,它将偏移它绘制的图像以与像素网格对齐 每当布局更新时,它都会检查是否需要重新渲染以再次与像素网格对齐。 这是一个非常简单的类,请查看源代码了解详细信息 我希望他不介意我在这里分享代码: 示例窗口在原始代码中可以找到更好的示例…:
<Window x:Class="ImageSnappingToPixels.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ImageSnappingToPixels"
Height="300" Width="600">
<Grid x:Name="root">
<StackPanel Orientation="Horizontal">
<local:Bitmap Source="picture1.png" />
<local:Bitmap Source="picture2.png" />
</StackPanel>
</Grid>
</Window>
下面是他完整的未桥接位图类:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace ImageSnappingToPixels
{
class Bitmap : UIElement
{
public Bitmap()
{
_sourceDownloaded = new EventHandler(OnSourceDownloaded);
_sourceFailed = new EventHandler<ExceptionEventArgs>(OnSourceFailed);
LayoutUpdated += new EventHandler(OnLayoutUpdated);
}
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
"Source",
typeof(BitmapSource),
typeof(Bitmap),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.AffectsRender |
FrameworkPropertyMetadataOptions.AffectsMeasure,
new PropertyChangedCallback(Bitmap.OnSourceChanged)));
public BitmapSource Source
{
get
{
return (BitmapSource) GetValue(SourceProperty);
}
set
{
SetValue(SourceProperty, value);
}
}
public event EventHandler<ExceptionEventArgs> BitmapFailed;
// Return our measure size to be the size needed to display the bitmap pixels.
protected override Size MeasureCore(Size availableSize)
{
Size measureSize = new Size();
BitmapSource bitmapSource = Source;
if(bitmapSource != null)
{
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;
}
protected override void OnRender(DrawingContext dc)
{
BitmapSource bitmapSource = this.Source;
if (bitmapSource != null)
{
_pixelOffset = GetPixelOffset();
// Render the bitmap offset by the needed amount to align to pixels.
dc.DrawImage(bitmapSource, new Rect(_pixelOffset, DesiredSize));
}
}
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Bitmap bitmap = (Bitmap)d;
BitmapSource oldValue = (BitmapSource)e.OldValue;
BitmapSource newValue = (BitmapSource)e.NewValue;
if (((oldValue != null) && (bitmap._sourceDownloaded != null)) && (!oldValue.IsFrozen && (oldValue is BitmapSource)))
{
((BitmapSource)oldValue).DownloadCompleted -= bitmap._sourceDownloaded;
((BitmapSource)oldValue).DownloadFailed -= bitmap._sourceFailed;
// ((BitmapSource)newValue).DecodeFailed -= bitmap._sourceFailed; // 3.5
}
if (((newValue != null) && (newValue is BitmapSource)) && !newValue.IsFrozen)
{
((BitmapSource)newValue).DownloadCompleted += bitmap._sourceDownloaded;
((BitmapSource)newValue).DownloadFailed += bitmap._sourceFailed;
// ((BitmapSource)newValue).DecodeFailed += bitmap._sourceFailed; // 3.5
}
}
private void OnSourceDownloaded(object sender, EventArgs e)
{
InvalidateMeasure();
InvalidateVisual();
}
private void OnSourceFailed(object sender, ExceptionEventArgs e)
{
Source = null; // setting a local value seems scetchy...
BitmapFailed(this, e);
}
private void OnLayoutUpdated(object sender, EventArgs e)
{
// This event just means that layout happened somewhere. However, this is
// what we need since layout anywhere could affect our pixel positioning.
Point pixelOffset = GetPixelOffset();
if (!AreClose(pixelOffset, _pixelOffset))
{
InvalidateVisual();
}
}
// Gets the matrix that will convert a point from "above" the
// coordinate space of a visual into the the coordinate space
// "below" the visual.
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;
}
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 Point GetPixelOffset()
{
Point pixelOffset = new Point();
PresentationSource ps = PresentationSource.FromVisual(this);
if (ps != null)
{
Visual rootVisual = ps.RootVisual;
// Transform (0,0) from this element up to pixels.
pixelOffset = this.TransformToAncestor(rootVisual).Transform(pixelOffset);
pixelOffset = ApplyVisualTransform(pixelOffset, rootVisual, false);
pixelOffset = ps.CompositionTarget.TransformToDevice.Transform(pixelOffset);
// Round the origin to the nearest whole pixel.
pixelOffset.X = Math.Round(pixelOffset.X);
pixelOffset.Y = Math.Round(pixelOffset.Y);
// Transform the whole-pixel back to this element.
pixelOffset = ps.CompositionTarget.TransformFromDevice.Transform(pixelOffset);
pixelOffset = ApplyVisualTransform(pixelOffset, rootVisual, true);
pixelOffset = rootVisual.TransformToDescendant(this).Transform(pixelOffset);
}
return pixelOffset;
}
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));
}
private EventHandler _sourceDownloaded;
private EventHandler<ExceptionEventArgs> _sourceFailed;
private Point _pixelOffset;
}
}
请参见此解决方案:使用矢量图形。