Sunday, January 22, 2012
■ [Metro]Metro style appsと解像度と画面サイズと画面解像度

このエントリの内容はWindows Developer Previewの仕様を元にしています。今後Betaやリリース時には変更される可能性があることに注意してください。
Metro style appsの解像度に合わせたスケーリング - ういはるかぜの化学 - subtech でスケーリングについて書きましたが、その拡大率が決定される条件がちょっと謎な感じに見えます。たとえば同じ画面解像度1920x1080でも10.6インチと23インチとで拡大率が違うわけです。
しかもVAIO Z(13インチ, 1920x1080)にWindows Developer Previewをインストールするとなぜかシステム解像度(以前からあるあのDPI設定)がデフォルトで120dpiになっています。その割にはMetro style appsはスケーリングしません。どうも画面サイズ(物理的な画面サイズ)をWindows側で把握してコントロールしているような感じです。
画面サイズの取得なんてとれるのかなと思って調べてみると GetDeviceCaps 関数というWin32 APIにVERTSIZE,HORZSIZEを渡すと取れそうなのですがいろいろなところでまともな値は返さない(物理サイズの参考にはならない)という声も見かけます。
まあそうはいっても他に見当たらないのでコードを書いてとりあえず試してみました。
https://gist.github.com/1656292
書いたコードをVAIO L (24インチ, 1920x1080)で実行したところ530x300mmという値が返ってきました。24インチの16:9で53.13cm x 29.89cmぐらいらしいのでだいたいあってそうです。ならばとVAIO Z (13インチ, 1920x1080)で試してみると今度は290x160mmという値が返ってきました。やっぱりちゃんと動いているっぽいです。
Windows 7で動かすと677x381mmという明らかに変な値が出てくることからWindows 8からまともに機能するようになったようです。
というわけでこれをシミュレータで動かしたりして、さらにそのサイズからDPIを求めたりしてまとめたのが以下の表です。
| 環境 | 画面サイズ(インチ) | Windowsが把握している画面サイズ | 画面解像度 | 画面サイズと画面解像度で求めたDPI | 拡大率 |
|---|---|---|---|---|---|
| VAIO L | 24 | 530x300mm | 1920x1080 | 約92dpi x 91dpi | 100% |
| VAIO Z | 13 | 290x160mm | 1920x1080 | 約168dpi x 171dpi | 100% |
| シミュレーター | 10.6 | 132x235mm | 1366x768 | 約148dpi | 100% |
| 1920x1080 | 約207dpi | 140% | |||
| 2560x1440 | 約276dpi | 180% | |||
| 12 | 1280x800 | 162x258mm | 約126dpi | 100% | |
| 23 | 286x509mm | 1920x1080 | 約96dpi | 100% | |
| 27 | 336x598mm | 2560x1440 | 約109dpi | 100% |
これでどういう意味があるかと言うと、どうもWindows 8は10.6インチ(1366x768)をスタンダード スレートと定義しているらしく(ガイドラインの一番上の図がそんな感じ)そこを基準にいろいろ決まっているようです。
たとえば10.6インチの1920x1080では140%に拡大されるのに13インチで1920x1080のVAIO Zでは何も起こらないのは、
- 10.6インチの1920x1080は約207dpiで140%の拡大率
- 拡大率140%は約207dpiが基準になり、それを超えると適用される
- VAIO Zでは約170dpi前後ぐらいしかないので100%の域になる
となっていると推測できます。画面サイズで決定されるので拡大率にシステムのDPI設定は考慮されないことになります。
これで画面解像度だけで拡大率が決まるわけではない理由がなんとなくわかりました。
CSSのメディアクエリーで使われていた謎のdpi値
MSDNのガイドラインでは以下のようなメディアクエリーの例が書かれていました(微妙に間違ってるので直してますけど…)。
/* CSS - 拡大率に応じてリモートの画像を読み込む */ @media all and (max-resolution: 134dpi){ /* 100%の拡大率のとき100%用の画像 */ .imageBackground { background-image: url('http://www.fabrikam.com/foo.png?s=100'); } } @media all and (min-resolution: 135dpi) { /* 140%の拡大率のとき140%用の画像 */ .imageBackground { background-image: url('http://www.fabrikam.com/foo.png?s=140'); } } @media all and (min-resolution: 173dpi) { /* 180%の拡大率のとき180%用の画像 */ /* MSDNのサンプルでは174dpiになっているが173dpiでないと動かない */ .imageBackground { background-image: url('http://www.fabrikam.com/foo.png?s=180'); } }
134dpi、135dpi、173dpiとありますがこれは100%を96dpiとしたときの値です。つまり
- 96dpi * 100% = 96dpi
- 96dpi * 140% = 134.40dpi (135dpi)
- 96dpi * 180% = 172.8dpi (173dpi)
となります。Windowsは96dpiが標準解像度となっているのでそれが基準になっているのですね。
- 一つ目はmax-resolution:134dpiなので134dpiまでなので135dpi(140%)にならない範囲ぎりぎり→100%
- 二つ目はmin-resolution:135dpiなので140%の時の135dpi以上
- 三つ目はmin-resolution:173dpiなので180%の時の173dpi以上
に適用されることになるわけです。
ちなみにこのDPI値はHTML+JavaScriptなMetro style appsではwindow.screen.deviceXDPIとして取得できます。WinRTを経由してもWindows.Graphics.Display.DisplayProperties.LogicalDpiプロパティを使うことで取得できます。
が、なぜか180%の時の値が違います。deviceXDPIは173を返しますがLogicalDpiは174を返します。MSDNのメディアクエリーの例に174dpiと書いてあったのはWinRTの値が元なのではないかと思います。実際ダウンロードできるサンプルコードの方では173dpiになっています。まあ計算しても違うわけですしWinRTのバグのような気がします。
