DPIスケール変更時におけるWPFとSilverlightの違い

 以前の投稿@ITの.NET開発者中心厳選ブログ記事として転載されました。ここでは、以前の投稿では文章量の関係から書かなかったもう1つの要素について書きたいと思います。それは、高DPIへの対応です。

Windows 8時代のディスプレイ



 この15年くらいの間で、画面解像度*1は種類が増え、その大きさも大きくなりました。しかしながら、それとともに物理的なディスプレイのサイズも大きくなっているため、ピクセル密度は96PPI(pixel per inch)前後のままと大きな変化はありません。


 現在一般向けとして販売されているデスクトップPC向けディスプレイで物理的に一番大きいものは27インチです。おそらくこれが常用できる最大サイズであり、これ以上大きいディスプレイが普及するということはないのではないかと思います。そう考えた場合、この先のディスプレイの進化の矛先はディスプレイの物理的な大きさはそのままに画面解像度を高くする高精細化に向けられるのではないかと思います。


 2010年6月24日に発売されたiPhone 4Retinaディスプレイピクセル密度は326PPIです。

iPhone - Apple(日本)



 また、先月には東芝モバイルディスプレイがRetinaディスプレイを超える498PPIの液晶ディスプレイの開発を発表しています。

「写真画像並」の超高精細モバイルディスプレイ、東芝グループが開発 - ITmedia PC USER



 このような高精細ディスプレイは、スマートフォンなどの比較的小さいサイズの液晶から普及していくと思いますが、ゆくゆくはスレートPC、デスクトップ/ノートPCでも普及してくるものと予想しています。


 高精細ディスプレイではシステム側が何もしなければ文字やアイコンなどが通常よりも小さく表示されます。96PPIと192PPIのディスプレイでは実際に見える大きさが単純に4分の1になります。WindowsではDPIスケーリングを変更することでシステムフォントとシステムUI要素のサイズを大きく表示できるようになっており、120PPI前後の一部のノートPCなどでは初期設定でDPIスケールが125%(120DPI)に設定されているものもあるようです。


 今後の5年間を考えた場合、アプリケーションがDPIスケーリングによってきれいにスケールされるかどうかはとても重要な要素になるのではないかと思います。ここまで書いた内容は、MSDNライブラリの下記のページにほぼ同じことが書かれています。

High DPI | Microsoft Docs


2つのDPIスケーリング方式



 Windows Vista以降、DPIスケーリングには2つの形式があります。ここでは1つをXP形式、もう1つをVista以降の形式と呼ぶことにします。これは[カスタム DPI 設定]画面で「Windows XP 形式の DPI スケーリングを使用する」にチェックが入っているかどうかで決まります。144DPI(150%の設定)126%より小さいの場合、このチェックボックスはデフォルトでオンになりますが、144DPI(150%の設定)126%以上の場合はデフォルトでオフになります。





 Vista以降の形式では、DPI仮想化と呼ばれる機能によってスケーリングが行われます。アプリケーションをいったん96DPIで画面表示領域外に描画し、それをDWM(デスクトップウィンドウマネージャ)がDPIスケーリングに合わせて拡大表示します。そのため、Visata以降の形式はDWMがオンの状態でのみ使用可能です。DPI仮想化が有効な場合、DPIスケーリングに対応していないアプリケーションでもほぼ期待する形でスケーリングすることができるというメリットがあります。しかしながら実際にはスケールではなくビットマップとして拡大表示されているため、どうしてもぼやけた印象の表示となってしまいます。


 96DPIの環境で作成したWindowsフォームの画面を144dpi(150%)で表示した結果が下の図です。

XP形式 Vista以降の形式



 DPI仮想化は、あくまでDPIスケーリングに対応していないアプリケーションを救うための措置といえます。アプリケーションがDPIスケーリングに対応しているにもかかわらず、DPI仮想化が行われてしまい画面がぼやけてしまったのでは困ります。そのため、DPIスケーリングの設定がVista以降の形式になっていたとしても、そのアプリケーションにだけDPI仮想化を行わないようにする方法が2つ(SetProcessDPIAware関数を使う方法もあるため正確には3つ)用意されています。

ファイルのプロパティの[互換性]タブ



 ファイルのプロパティの[互換性]タブの[設定]というところに、「高 DPI 設定では画面のスケーリングを無効にする」というチェックボックスがあります。このチェックボックスをオンにすることで、DPI仮想化が無効になります。




アプリケーションマニフェストを使用する



 以下のようなアプリケーションマニフェストファイルを作成し、mt.exeなどを使って実行ファイルに埋め込むことで、このアプリケーションはDPIスケーリングに対応しているアプリケーションであることを宣言できます。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
 <assemblyIdentity type="win32" name="app" version="1.0.0.0" processorArchitecture="x86"></assemblyIdentity>
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>



mt.extの使い方の例

mt.exe /manifest WindowsFormsApplication.exe.manifest -outputresource:WindowsFormsApplication.exe;1


DPIスケーリング変更時のWPFアプリケーションの表示



 こちらの以前の投稿でも解説していますが、WPFにおけるピクセルという単位は物理的なピクセルに依存しない論理上のピクセルとなっています。これはDPIスケーリングが96DPIのときの1ピクセルを1論理ピクセルとするもので、144DPIでは1論理ピクセルが物理的なピクセルとして1.5ピクセルとなります。


 このようなWPFにおけるスケーリングの動作は、XP形式とVista以降の形式のどちらが設定されていても働きます。つまり、WPFアプリケーションではDPI仮想化は有効にならず、常に下の図のようにスケーリングされた表示となります。

96DPI 144DPI


DPIスケーリング変更時のSilverlightアプリケーションの表示



 Silverlightの場合、通常のWebブラウザー内に表示される場合とブラウザー外実行の場合で動作が異なります。

Webブラウザー内に表示される場合



 Webブラウザー内で表示される場合、Webブラウザーの種類によって以下のように表示が異なります。なお、Internet ExplorerFirefoxはDPIスケーリングに対応しているアプリケーションであるとマークされておりDPI仮想化は有効になりませんが、ChromeはマークされておらずDPI仮想化が有効となります。また実際にChrome自体がDPIスケーリングに対応していません。

Webブラウザーの種類 XP形式 Vista以降の形式
Internet Explorer 9 Webブラウザーの拡大機能によって拡大 Webブラウザーの拡大機能によって拡大
Firefox 8.0 通常(96DPI)と同様 通常(96DPI)と同様
Chrome 15.0 通常(96DPI)と同様 DPI仮想化によって拡大



 なお、Internet Explorerが異なるのはWebブラウザーの拡大機能が自動で実行される部分だけであり、FirefoxChromeでも手動でWebブラウザーの拡大率を変更することでSilverlightコンテンツ部分も拡大されます。

96DPI 144DPI


ブラウザー外実行の場合



 ブラウザー外実行の場合、sllauncher.exeという実行ファイルにホストされてSilverlightアプリケーションが動作します。そしてこのsllauncher.exeはDPIスケーリングに対応しているアプリケーションであるとマークされていないため、Vista以降の形式の場合にはDPI仮想化が有効となり下の図のようにぼやけた表示となります。

96DPI 144DPI



 そして、XP形式にしてDPI仮想化を無効にすると、Webブラウザー内で表示される場合のInternet Explorerのときと同じ表示になります。





 一瞬100%で表示されたのちに150%に拡大されるためおそらくはInternet Explorerの拡大表示機能が内部で使われていると思われます。


 なお、sllauncher.exeに対して、ファイルのプロパティの「高 DPI 設定では画面のスケーリングを無効にする」の設定や、マニフェストを埋め込むといった方法を実際に試してみましたが、有効でした。Vista以降の形式になっていてもこれらの設定をすることで、ブラウザー外実行でもDPI仮想化を無効とすることができます。

*1:本来は総画素数というのが正しいようですが、解像度が一般的に使われているため画面解像度とします。