在 Windows App SDK 1.1 中设置图片解码尺寸
刚刚发行的 Windows App SDK 1.1 较前面几个版本,在可用性上有很大的提升。但是在一些细节处的 API 上,还是有很多问题。例如,在通过 DecodePixelWidth
属性给 BitmapImage
对象设置解码尺寸时,无法指定逻辑像素数,只能通过一些 “奇技淫巧” 来绕过这一限制。
为什么指定解码尺寸
当然,不指定解码尺寸也不是不能用。BitmapImage
类会按照图片原始尺寸进行展示。但是这样有两个问题:
- 如果原始图片很大,则位图数据将一直驻留内存,带来不必要的内存压力。我司产品曾经因为这一问题,险些酿成事故
- 如果图片的实际展示区域远小于图片的原始尺寸,则缩放过程中会造成严重的失真,视觉上很不美观
DecodePixelType
属性
在 UWP 中,BitmapImage
类提供了 DecodePixelType
属性,可以指定设置的解码尺寸是物理像素还是逻辑像素。在 Windows App SDK 中,这一 API 仍然存在,但可惜实际上不生效。参见这一 GitHub Issue.
这意味着我们只能根据当前屏幕的缩放比例,手动从希望得到的逻辑分辨率计算出对应的物理分辨率。
DisplayInformation
类
在 UWP 中有 DisplayInformation
类,可以用于获取当前视图的缩放比例,仅需一行代码:
1 | double scaleFactor = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel; |
之后将其与逻辑分辨率相乘即可得到相应的物理分辨率。
可惜这一 API 在 Windows App SDK 上也无法使用。原因是 GetForCurrentView()
方法需要一个 CoreWindow
. 而 Windows App SDK 是基于 Win32 的,没有 CoreWindow 这一说。参见这一 GitHub Issue.
原生互操作
最后本人从这一 GitHub Issue 的评论中找到提示,可以使用 .NET 的原生互操作能力来直接调用 Win32 的 API 来获取缩放比例。通过查阅文档可以得到对应的互操作方法签名。
1 | // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfromwindow |
当前窗口的 HWND 可以通过 Windows App SDK 提供的互操作帮助方法获得:
1 | IntPtr hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window); |
得到的缩放比例是一个 C++ 枚举:
1 | // https://docs.microsoft.com/en-us/windows/win32/api/shtypes/ne-shtypes-device_scale_factor |
注意到要与 DisplayInformation.RawPixelsPerViewPixel
属性等效的话,需要除以 100. 于是完整的代码如下:
1 | using System; |