WPF 应用程序中的图像显示小于在外部查看器中查看时的图像

发布于 2024-07-15 15:42:01 字数 771 浏览 7 评论 0原文

当我在 WPF 应用程序中显示 JPEG(使用以下代码)时,它显示的大小明显小于在 Windows 图片查看器中以实际大小打开 JPEG 的情况。

我在运行时深入了解了 ImageSource 的属性,我的图像具有:

  • DPI 为 219
  • 高度为 238.02739726027397
  • 宽度为 312.54794520547944
  • 像素高度为 543
  • ,像素宽度为 713

当我使用屏幕标尺测量 WPF 显示时图像,我得到大约。 313x240 像素(如果我可以完美地定位标尺,则可能等于 ImageSource 报告的宽度和高度。)。

我的直觉告诉我这与 WPF 使用设备无关单位(而不是像素)有关,但我无法理解它,而且我仍然需要知道如何以 543x713 的“实际”尺寸显示图像在我的应用程序中。

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="300" Width="300">
    <StackPanel>
        <Image Source="Image15.jpg" Stretch="None" />
    </StackPanel>
</Window>

When I display a JPEG in my WPF application (using the following code), it is shown significantly smaller than if I open the JPEG in the Windows Picture Viewer at actual size.

I've drilled into the properties of my ImageSource at runtime and my image has:

  • a DPI of 219
  • a Height of 238.02739726027397
  • a Width of 312.54794520547944
  • a PixelHeight of 543
  • and a PixelWidth of 713

When I use a screen ruler to measure the WPF display of the image, I get approx. 313x240 pixels (which if I could positiont the ruler perfectly would probably be equal to the Width and Height that the ImageSource is reporting.).

My gut tells me this has something to do with WPF's use of device independent units (instead of pixels) but I can't make sense of it, and I still need to know how to display the image at the 'actual' size of 543x713 in my application.

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="300" Width="300">
    <StackPanel>
        <Image Source="Image15.jpg" Stretch="None" />
    </StackPanel>
</Window>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

无需解释 2024-07-22 15:42:01

谢谢马克! 我根据您的信息进行了一些谷歌搜索,发现这篇文章 提供了一个解决方案来获得我想要的结果。 现在这开始有意义了......

编辑:Linkrot。 将文章中的关键文本粘贴到此处以供参考......

<Image Source=”{Binding …}”
       Stretch=”Uniform”
       Width=”{Binding Source.PixelWidth,RelativeSource={RelativeSource Self}}”
       Height=”{Binding Source.PixelHeight,RelativeSource={RelativeSource Self}}” />

这里我们将 Stretch 设置为 Uniform,并将 Width 和 Height 绑定到源的 PixelWidth 和 >PixelHeight,从而有效地忽略 DPI。 然而,即使使用 SnapToDevicePixels(它只是捕捉边框,而不是图像内的像素),图像也不会是完美的像素。 但是,3.5 SP1 中的 WPF 将支持 NearestNeighbor >BitmapScalingMode,这应该可以纠正此问题。

Thanks Mark! I did some Googling based on your info and found this article that provided a solution to get the result I wanted. This is starting to make sense now...

Edit: Linkrot. Pasting the critical text from the article here for reference....

<Image Source=”{Binding …}”
       Stretch=”Uniform”
       Width=”{Binding Source.PixelWidth,RelativeSource={RelativeSource Self}}”
       Height=”{Binding Source.PixelHeight,RelativeSource={RelativeSource Self}}” />

Here we’ve set Stretch to Uniform and bound the Width and Height to the PixelWidth and >PixelHeight of the Source, effectively ignoring DPI. The image however will not be pixel >perfect, even when using SnapToDevicePixels (which simply snaps the borders, not pixels >within the image). However, WPF in 3.5 SP1 will support a NearestNeighbor >BitmapScalingMode, which should correct this.

牛↙奶布丁 2024-07-22 15:42:01

使用 DPI 96。WPF 根据英寸大小缩放图像,同时图像查看器显示像素。 在大多数 Windows 系统上,屏幕分辨率假定为 96 DPI,因此在图像中使用该分辨率将导致一对一转换。

Use a DPI of 96. WPF is scaling your image based on the size in inches, while the image viewer is displaying pixels. On most Windows systems, the screen resolution is assumed to be 96 DPI, so using that in your image will result in a one-to-one translation.

剪不断理还乱 2024-07-22 15:42:01

或者,您可以扩展 Image 并实现 MeasureOverride 和 ArrangeOverride 来更改图像 DPI 的效果:

class DpiAgnosticImage : Image
{
    protected override Size MeasureOverride(Size constraint)
    {
        var bitmapImage = Source as BitmapImage;

        var desiredSize = bitmapImage == null 
            ? base.MeasureOverride(constraint) 
            : new Size(bitmapImage.PixelWidth, bitmapImage.PixelHeight);

        var dpiScale = MiscUtil.GetDpiScale(this);
        desiredSize = new Size(desiredSize.Width / dpiScale.Width, desiredSize.Height / dpiScale.Height);

        desiredSize = ImageUtilities.ConstrainWithoutDistorting(desiredSize, constraint);

        if (UseLayoutRounding)
        {
            desiredSize.Width = Math.Round(desiredSize.Width);
            desiredSize.Height= Math.Round(desiredSize.Height);
        }

        return desiredSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        return new Size(Math.Round(DesiredSize.Width), Math.Round(DesiredSize.Height));
    }
}

在 xaml 中使用它,就好像它是图像一样:

<Grid>
  <local:DpiAgnosticImage
    Stretch="None"
    Source="{Binding ViewImage}">
    <Image.RenderTransform>
      <ScaleTransform
        x:Name="SomeName"/>
    </Image.RenderTransform>
  </local:DpiAgnosticImage>
</Grid>

上面代码的缺陷(据我所知):

  • 忽略拉伸
  • 假设源是 BitmapImage

= == 编辑 - Will 的评论表明他想知道 GetDpiScale() 中的内容

    public static Size GetDpiScale(Visual visual)
    {
        var source = PresentationSource.FromVisual(visual);

        var dpiScale = new Size(
            source.CompositionTarget.TransformToDevice.M11,
            source.CompositionTarget.TransformToDevice.M22);

        return dpiScale;
    }

Alternatively, you could extend Image and implement MeasureOverride and ArrangeOverride to change the effect of the image's DPI:

class DpiAgnosticImage : Image
{
    protected override Size MeasureOverride(Size constraint)
    {
        var bitmapImage = Source as BitmapImage;

        var desiredSize = bitmapImage == null 
            ? base.MeasureOverride(constraint) 
            : new Size(bitmapImage.PixelWidth, bitmapImage.PixelHeight);

        var dpiScale = MiscUtil.GetDpiScale(this);
        desiredSize = new Size(desiredSize.Width / dpiScale.Width, desiredSize.Height / dpiScale.Height);

        desiredSize = ImageUtilities.ConstrainWithoutDistorting(desiredSize, constraint);

        if (UseLayoutRounding)
        {
            desiredSize.Width = Math.Round(desiredSize.Width);
            desiredSize.Height= Math.Round(desiredSize.Height);
        }

        return desiredSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        return new Size(Math.Round(DesiredSize.Width), Math.Round(DesiredSize.Height));
    }
}

Use it in xaml as if it were an Image:

<Grid>
  <local:DpiAgnosticImage
    Stretch="None"
    Source="{Binding ViewImage}">
    <Image.RenderTransform>
      <ScaleTransform
        x:Name="SomeName"/>
    </Image.RenderTransform>
  </local:DpiAgnosticImage>
</Grid>

Flaws to above code (that I know of):

  • Ignores Stretch
  • Assumes Source is a BitmapImage

=== Edit - Will's comment suggests he would like to know what is in GetDpiScale()

    public static Size GetDpiScale(Visual visual)
    {
        var source = PresentationSource.FromVisual(visual);

        var dpiScale = new Size(
            source.CompositionTarget.TransformToDevice.M11,
            source.CompositionTarget.TransformToDevice.M22);

        return dpiScale;
    }
情绪少女 2024-07-22 15:42:01

这是 .jpg 文件本身指定 DPI 的结果 - WPF 只是遵循。 这是一篇论坛帖子,详细介绍了该问题和一些解决方案:

This is the result of the .jpg file itself specifying the DPI - WPF is simply obeying. Here is a forum post detailing the problem with some solutions:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文