[C#] WPF - 加载的png图像为什么宽度和高度和实际不一样(BitmapImage类的PixelWidth,PixelHeight,Width,Height,DpiX,DpiY之间关系)

问题描述

一张2074x876的png图像,通过BitmapImage类加载到WPF中,发现Bitmap的Width(为438)和Height(1037)和png图像的宽和高不一样。

 

然而,对于加载有opencv生成的bmp图像则不会导致这样的问题:

原因分析和解决

什么是DPI?

DPI(Dots Per Inch,每英寸点数)是一种表示屏幕分辨率的单位。它表示在屏幕上每英寸长度内包含多少个像素点。通常情况下,屏幕上的 DPI 越高,显示的图像就越清晰,文字也越清晰易读。

例如,一个 96 DPI 的屏幕每英寸包含 96 个像素点,而一个 120 DPI 的屏幕每英寸则包含 120 个像素点。这意味着在同样的物理尺寸下,120 DPI 的屏幕会比 96 DPI 的屏幕显示更多的像素点,因此显示的图像更加清晰。

什么是BitmapImage对象DpiX和DpiY?

BitmapImage Class (System.Windows.Media.Imaging) | Microsoft Learn

 表示通过BitmapImage类加载进来的图像在宽(X)和高(Y)方向对应的DPI值。

什么是WPF独立设备单位?

WPF窗口和所有之内的元素都是使用“独立设备单位”进行测量的。一个独立设备单位被定义为一英寸的96分之一。要理解它在实际应用中的含义,需要考虑一个例子。

假设你在WPF中创建了一个96×96单位大小的按钮,如果你使用的是标准的Windows DPI设置(96dpi),那么每一个独立设备单位对应一个实际的物理象素。这是因为WPF采用如下的计算方式:

[物理单位大小]=[独立设备单位大小] × [系统DPI点数]

                       =1/96 英寸 * 96 点每英寸

                       = 1 象素

本质上,WPF假定使用96个象素来组成一英寸是通过Windows的系统DPI的设置而获得的。无论如何,实际值取决于你的显示设备。

举例来讲,一个20英寸的液晶显示器的最大分辨率是1600×1200象素。通过下面的简单计算,就可以计算出这个显示器的象素密度。

[系统每英寸点数]=Sqrt(1600×1600 +1200×1200) 象素 /19 英寸       (Sqrt为开根号)

                          =100点每英寸

这种情况下的象素密度是100dpi,这实际上比Windows假定的值要高一些。结果,这个显示器按96×96象素显示的按钮比一英寸要小一些。

另一方面,15英寸的液晶显示器的分辨率为1024×768,它的象素密度降到了大约85dpi每英寸,所以96×96的按钮实际上比一英寸要大一些。

这两种情形中,如果减少屏幕尺寸(选择800×600分辨率),按钮会相应成比例的变大,这是因为系统的DPI设置仍然是96dpi的缘故。换句话说,Windows仍然假定使用96象素大小作为一英寸。

什么是系统DPI?

目前为止,WPF的按钮工作原理和应用程序中的其他用户界面元素的工作原理是严格一致的。WPF考虑系统特有的DPI设置,如果将系统DPI改为120dpi,WPF会假定它需要120个象素去填充一英寸的空间。WPF使用如下的计算去得出如何将逻辑单位转换为物理设备的象素。

[Physical Unit Size]= [独立设备单位尺寸]×[系统DPI]

                =1/96 英寸 ×120 dpi

                =1.25 象素

换句话说,当你设置系统DPI为120dpi的时候,WPF渲染引擎假定一独立设备单位等于1.25象素大小。如果显示一个96×96的按钮,物理尺寸实际上是120象素×120象素。

这种自动缩放的功能如果只被应用到按钮中,则实际上是没有多大用处的。但是WPF使用独立设备单位来显示所有的东西,包括形状,控件,文本和放进窗体中的任何元素。结果,系统的DPI可以被更改为任何需要的值,WPF会自动无缝的调整应用程序的尺寸。

在Windows10中,可以通过下面步骤:

1.右键点击桌面空白处,选择“显示设置”。
2.在“显示设置”窗口中,找到“缩放和布局”部分。
3.在“缩放和布局”部分中,可以看到当前的 DPI 设置。可以将其更改为所需的 DPI(例如 96 -100%、或者96的其它百分比等)。当前我的操作系统设置为200%。

为什么WPF打开png图像会采用192的dpi?

上面打开的png图像,是通过C#的Bitmap类生成,因为我操作系统的DPI为200%,也就是96的2倍,刚好就是192。

因此当WPF使用Bitmap打开该png图像时,会使用PixelWidth/DpiX来计算BitmapImage在WPF中显示的Width,PixelHeight/DpiY来计算BitmapImage在WPF中显示的Height。

如何解决该问题?

Bitmap类保存图像时,我们可以通过SetResolution来指定使用的DpiX和DpiY值:

修改完代码,重新生成对应的png图像,然后WPF重新加载该图像,对应的高度和宽度显示正常:

参考资料

WPF中DPI的问题

论如何优雅使用Windows:详解DPI缩放

猜你喜欢

转载自blog.csdn.net/u011775793/article/details/135329761
今日推荐