WinUI3 で画像ビューアを作ってみた
WinUI3 でテクスチャや HDR 画像に強い画像ビューアを作ってみました。
昔、似た物を作ったことがあるのですが WinForm で作ったので見た目が古いのと高 DPI 対応や HDR 対応に難があったので今時のフレームワークで作り直したいなぁ…とは思っていたのです。
ソースコードはこちら https://github.com/ueda-san/TexViewer
フレームワークを選ぶ
| WinForm | WindowsXP(.NET Framework1~)世代 |
| WPF | Windows Vista(.NET Framework3~)世代。使ったことがないのでよく知らない |
| UWP | Windows10 や WindowsMR 世代。サンドボックス化されていて制約が多い |
| WinUI3 | 2021年末に1.0になった。(WinUI2 は UWP 用) |
かつて Project Reunion と呼ばれた WinUI3 が1.0になった頃ちょっと調べたのですが HDR 表示に必要な SwapChainPanel の挙動が buggy だったりで「今はまだ時期が悪い」感じでした。
その後 WinUI も1.7ぐらいになってそろそろ使えるかと新たに作り始めました。
が、Win2D 経由で HDR 表示もできるはずなんだけどうまくいかなくて HDR 表示は Win2D か WinUI3 のアップデート待ちにして SDR 版で公開しようかと思っていたのですが HDR1400 のモニタを買ったらやっぱり HDR 対応したくなってきましたw
ちょうどその時 watch していた issue の新着通知でやればできるらしいと。
可能であることさえわかれば後は作るだけ。
C# 版の Win2D ではネイティブの Win2D ではできるはずのことができなかったり制約が多いようなので Vortice を使って DirectX で描画する方法で初期テストは成功。本格的に作り始めます。
描画系
最初 Win2D で描画して選択範囲とかは別 Canvas で重ねていたのですが、Tonemap かけるのに HDRToneMapEffect ってのがあるはずなのに Win2D からはアクセスできなかったり HDR 対応に難があったりで Vortice に乗り換えました。ウィンドウのリサイズと再描画のタイミングがずれるのも嫌だったので最終的に背景+画像+選択範囲の描画と色空間の変換やトーンマップなど全部入りのシェーダーで描画しています。
WinUI3 の Image で HDR 画像を正しく扱えるようになったら WinUI3 の流儀に従ってやった方が良いとは思いますが。
HDR対応
ちゃんと HDR 対応するには BT2020/PQ で出力しないといけない。BT709/Linear でもできる筈なんだけどうまくいかなかったので今回はナシで。
SwapChainPanel の SwapChain を自分で作った SwapChain に差し替えて色空間を指定する感じ。
swapChainPanel = ComObject.As<Vortice.WinUI.ISwapChainPanelNative2>(panel);
swapChain = dxgiFactory2.CreateSwapChainForComposition(d3dDevice, swapChainDesc);
ColorSpaceType colorSpace = ColorSpaceType.RgbFullG2084NoneP2020;
using (var swapChain3 = swapChain.QueryInterface<IDXGISwapChain3>()){
var flags = swapChain3.CheckColorSpaceSupport(colorSpace);
if ((flags & SwapChainColorSpaceSupportFlags.Present) != 0) {
swapChain3.SetColorSpace1(colorSpace);
}
}
swapChainPanel.SetSwapChain(swapChain);
で出力を BT2020/PQ に設定すれば HDR 表示になる (SMPTE ST 2084/ITU-R BT.2020)
但しガンマカーブは自分で PQ エンコードする必要があるのでメンドイ。
Gamut対応
元々 sRGB かリニアかぐらいの判別は行っていたのですが Kikiちゃん や ドロイド君 もちゃんと表示したいのでちょっとだけ真面目に色空間変換してみました。
時を同じくして png v3 が CICP チャンクに対応したというのも理由の一つです。
CICP 同様、色域と伝達関数の Enum 値をシェーダーに渡しています。ColorPrimaries が取れればそちらを使いますが TRC はパラメトリック関数やテーブル参照の奴には未対応。このあたりは ICC データをシェーダーに渡してしまえばより正確な表示ができそうなのですが面倒くせぇなぁ…。気が向いたらやるかもやらないかも。
ちなみに ICC や Exif の解析は自作のパーサで行っています。実績のあるコンパクトなパーサも色々あるようなのでそちらを使ったほうが楽なのですが謎のバイナリがあれば読んでみたくなるのが人というもの。(なのでバグってたら教えて下さい)
その他
結局 WinUI3 ってどうよ?
そろそろ使えるんじゃないかな? でも
- 微妙に足りてない部分がまだある
例えばテーマ(ダークとかライト)には対応してるんだけどタイトルバーだけは変わらない。対応するにはタイトルバーを自分で頑張らないといけないとか。 - UWP とか他の SDK と混乱しがち
Web で API ドキュメント読み進めるうちにいつの間にか他の SDK のページに飛ばされていることがある。特に Windows.* 名前空間と Microsoft.* 名前空間。さらに Microsoft.Windows.* 名前空間まである。あとは Win32 ならできるんだけど WinUI3 用のラッパー経由だとできない、みたいなのもあったかな?
ストアアプリで外部プログラム呼び出せるの?
ある程度作ってから「あれ? ImageMagick とか使ってるけど外部プログラム呼び出せない?」と思って、まずは一般公開でなく自分だけにプライベート公開(パッケージフライト)にしてみた。試した範囲では問題なく動いているみたいですね。
png1.8 系の正式公開を待って一般公開する予定だったけど半年ほど待っても tag すら振られないので還暦の記念に公開することにしました。
パッケージフライト
自分だけに公開してテストとかできる。
https://learn.microsoft.com/ja-jp/windows/apps/publish/package-flights
念の為「今すぐ公開」を押さないと公開されない設定にしてみた。「審査が通ったら公開」は「パッケージフライト用に公開」だとは思うけど一般公開の可能性も微粒子レベルで存在するかもなので。
前回の教訓からテスト担当者への追加情報に runFullTrust 機能の事を書き添えておいた。
翌日、審査結果のメールは来てないけどパートナーセンターを見ると「公開準備が完了しました」になって「今すぐ公開」も押せそうな感じになってた。
もしかして公開しないと審査結果が届かないのか? いや、そんなことは無いだろう。わかるぞ、焦って何か押すとよくわからん状態になってハマるやつだ。公式には5営業日待って進展がなければ問い合わせろ、って書いてるので大人しく審査結果のメールを待つことに。
数日待ったけどメール来ないな。今すぐ公開を押したら公開処理中になった。リジェクトされるか公開された時にしかメールは来ないのかな?
iGPU のノイズ
動作確認でサブモニタを内蔵 GPU に繋いでいた時、たまに画像にノイズが乗ることがあって調べていたのですが XMP メモリを定格で動作させると起こらないので、この PC を組んでベンチマーク取っていた時 FF ベンチで起こった内蔵 GPU はオーバークロックメモリだと不安定なのと同じ原因のようです。もし画像にノイズが出ることがあればモニタをグラボからの出力に繋ぐかメモリを XMP でなく定格で試してみてください。
おまけ: おすすめのHDR画像
HDR モニタをお持ちの方にテストで使った HDR 画像の紹介。HDR1400 のモニタで見ていますがニヤニヤが止まりませんw
AVIF
https://www.mark-heath.com/hdrphotos/
UltraHDR
https://github.com/MishaalRahmanGH/Ultra_HDR_Samples
Gain Map
https://helpx.adobe.com/camera-raw/using/gain-map.html
他にも素敵な画像やうまく表示できない画像があったら教えてください。
