Sitelet https://github.com/okaz-code/HDRScopeWin
Skip to content

About

HDR Scope for Windows

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

7 Commits

Folders and files

Repository files navigation

HDRScope for Windows

Windows 11向けの、HDRウィンドウキャプチャ・表示・RGB測定ツールです。macOS版HDRScopeの移植で、測定値の意味と保存形式の考え方はそちらと同じです。外部ライブラリやネットワーク通信は使いません。

入手方法

Releases に HDRScope.exe を置いてあります。単体で動きます(インストール不要、DLLの同梱もありません)。

**コード署名はしていません。**そのためダウンロードした実行ファイルは Microsoft Defender SmartScreen に止められます。「詳細情報」→「実行」で起動できます。気になる場合は下の手順で自分でビルドしてください。macOS版と違い、ビルドし直しても権限設定はやり直しになりません(署名と権限が結びつく仕組みがWindowsにはないため)。

自分でビルドする

必要なもの:

  • Windows 11(Windows.Graphics.Capture が使えること。--diagnose で確認できます)
  • Visual Studio 2022(C++デスクトップ開発ワークロード)
  • Windows 10/11 SDK(C++/WinRTヘッダを含みます。SDKに同梱されているのでNuGetは不要です)
  • CMake 3.20以降
git clone https://github.com/okaz-code/HDRScopeWin.git
cd HDRScopeWin
build.cmd --test

build\dist\HDRScope.exe ができます。--test を付けると自己テストと独立検証まで走ります。

アイコン

Resources\AppIcon.ico を Resources\HDRScope.rc から埋め込みます。リソース番号1にしてあるのは、エクスプローラーが実行ファイルに対して最も小さい番号のアイコンを使うためです。ウィンドウクラスには大小それぞれのサイズを別々に読み込ませています(片方を縮小したものではなく、そのサイズ用に描かれた絵が出ます)。

図案はmacOS版と同じで、コード内の計算だけで描いています。画像素材にも外部ツールにも依存しません。暗い角丸背景(連続曲率に近い超楕円)に、加算合成したR/G/Bのにじみ、その上に白い測定用レティクル。中央のセルはアプリ内の測定枠と同じ「黒の太線+白の細線」で描いています。64px未満では細い線が消えるため、リングだけの簡略版になります。

macOS版との違いは余白だけです。macOSは全アプリ共通のグリッドに合わせて9%空けますが、Windowsにその慣習はなく、同じだけ空けるとタスクバーで隣のアイコンより小さく見えるため4%にしています。

16 / 20 / 24 / 32 / 40 / 48 / 64 px はDIB、128 / 256 px はPNGで格納します(全部DIBにするとファイルが数倍になるため)。図案を変えたら次を実行してください。build.cmd も .ico がなければ自動生成します。

tools\make-icon.cmd

差し替えたのにエクスプローラーが古いアイコンを表示する場合は、シェルのアイコンキャッシュが残っています。ie4uinit.exe -show を実行するか、エクスプローラーを再起動してください。

**画面収録の許可設定は不要です。**macOS版のREADMEの大半を占めていたTCCの許可・署名・tccutil reset の話は、Windowsには存在しません。デスクトップアプリからの Windows.Graphics.Capture に権限設定もマニフェスト宣言も要らないため、setup-signing-identity.sh / check-permission.sh に相当するものはありません。代わりに環境を確認したいときは --diagnose を使います。

操作

  1. 「開く…」(Ctrl+O)で保存済みの画像を読み込んで測定できます。ウィンドウへのドラッグ&ドロップ、コマンドラインへのファイル指定も同じ動作です。
  2. 左側の「更新」で現在のウィンドウ一覧を取得します。一覧はアプリごとにまとめ、検索欄でアプリ名・タイトル・IDを絞り込めます。
  3. アプリ名・タイトル・サイズ・IDを確認して選択し、「キャプチャ」を押します。一覧の項目をダブルクリックしても同じです。
  4. 「再キャプチャ」は最後に正常取得したウィンドウを再取得します。一覧で別の項目を選んでも再取得対象は変わりません。ウィンドウハンドル・PID・プロセス起動日時を再確認します。失敗時は最後の画像を保持します。
  5. ホイールで、ポインタ位置を中心にズームします。左ボタンドラッグで移動します。キーボードは不要です。
  6. 「全体表示」でフィット、「1:1」で画像1画素をディスプレイの物理1画素に表示します。
  7. カーソル位置のRGB・アルファ・画像座標・測定範囲を下部に表示します。HDRがONのときは、その値が何nitに相当するかも併記します。
  8. 画像上で左クリックすると、その2行をそのままクリップボードへコピーします。ドラッグは移動のままで、3ピクセル未満の移動だけをクリックとして扱います。メニューの「測定値をコピー」(Ctrl+C)も同じ内容をコピーします。範囲外では何もコピーしません。
  9. 左下の「テストパターン ×30」「ヘッドルーム階調」で、キャプチャなしの既知値パターンを表示できます(「テストパターン」を参照)。
  10. 「保存…」から形式を選びます。測定用は32bit float TIFF、WindowsフォトでHDRを見たいならHDR JPEG XRです。表示倍率や表示位置は保存内容に影響しません。

再キャプチャでは現在の倍率・表示原点を保ちます。全体表示モードの場合はサイズ変更時に再フィットします。

Win32のクライアント座標は物理ピクセルなので、「1:1」は文字どおり画像1画素=ディスプレイ1画素です。macOS版にあった「Retinaの論理ポイントとは異なります」という注意は、Windowsでは不要です。

RGB値と平均の定義

  • 色空間:拡張リニアsRGB(Rec.709原色・D65白色点)。ガンマ符号化されたsRGB値ではありません。
  • (1, 1, 1) がSDR基準白です。キャプチャ値はそうなるように正規化しています(「scRGBとSDR基準白」を参照)。
  • RGBの1超え、負値を内部処理・測定・保存でクリップしません。RGBは非乗算(straight)アルファ、Aは別表示です。
  • 座標原点は画像の左上、xは右方向、yは下方向です。
  • 100%以上ではポインタが位置する元画像1画素を読みます。
  • 100%未満では、ポインタが位置するディスプレイの物理1画素セルを元画像に逆投影し、各画素との重なり面積を重みにして平均します。境界では画像内の有効面積で正規化します。
  • 平均はリニアRGBを用います。アルファによる重み付けは行いません。表示背景の市松模様や測定枠は測定・保存に混入しません。
  • 縮小表示自体も同じ面積平均をGPUで計算し、拡大表示は最近傍で画素を区別します。
  • ピッカーは保存用float32データをdouble精度で集計します。画面から色を読み取っているのではありません。

scRGBとSDR基準白

これがmacOS版との唯一の実質的な違いです。

Windowsのコンポジタ(DWM)はscRGBで合成します。scRGBは仕様上 1.0 = 80 nit 固定で、SDR基準白はそこにはありません。SDR白は「設定 → システム → ディスプレイ → HDR → SDRコンテンツの明るさ」のスライダーが決める SDR白レベル の位置に来ます。

実測(このリポジトリの開発機、SDR白レベル240 nit):

対象 キャプチャの生scRGB値
純白のSDRウィンドウ(sRGB 255,255,255) 3.000000
グレー128(sRGB 128,128,128) 0.647461

0.647461 は linear(128/255) = 0.21586 の3倍です。240 / 80 = 3.0 と一致します。

つまり生のscRGBのままでは 1.0 はSDR白ではありません。macOS版と同じ意味の数値にするため、キャプチャ値をこの係数(SDR白レベル ÷ 80)で割ってから保持します。上の白は 1.000000 になります。係数はキャプチャ時のステータス行に必ず出ます(正規化 ×3.0000(SDR白 240 nit))。

この決め方の帰結:

  • macOS版と同じTIFFの意味になります。両ツールで同じファイルを開いて同じ数字が読めます。
  • SDRコンテンツの明るさスライダーを動かすと係数も変わります。**PQ動画のように絶対輝度で描かれる内容を測る場合、スライダー位置によって読み値が変わります。**そのときはステータス行の係数を掛け戻してscRGBに戻してください。値 × 80 = nit です。
  • HDRがOFFのときはSDR白レベルが定義上80 nitなので、係数は 1.0000 になり、正規化は何もしません。

ピッカーの2行目には、HDRがONのとき nit 相当 も出します。Rec.709の輝度係数で重み付けした値 × SDR白レベルです。Windowsは合成が絶対輝度基準なので、macOS版では出せなかったこの数字が出せます。

負値と1超えの意味

測定値に負のRGBが出ることがあります。異常ではありません。原因は主に2つで、見分け方が異なります。

1. sRGB色域の外にある色

測定値はRec.709原色を基準にした座標系です。キャプチャ元がDisplay P3やRec.2020の色を出していると、その色はsRGBの三角形の外側にあり、sRGB原色の足し算だけでは表現できません。負の係数が必要になります。原色を変換した実際の値です。

元の色 R G B
Display P3の赤 +1.2249 −0.0421 −0.0196
Display P3の緑 −0.2249 +1.0421 −0.0786
Rec.2020の赤 +1.6605 −0.1246 −0.0182
Rec.2020の緑 −0.5876 +1.1329 −0.1006

この表の値は自己テストで原色から再計算して照合しています(Tests ではなく --self-test に入っています)。

拡張sRGBは、この色域外を表すために負値と1超えを許すよう定義された色空間です。負値はデータの破損ではなく、より鮮やかな色であるという情報そのものです。クリップすると彩度の情報が失われ、元の色に戻せなくなるため、このツールはクリップしません。

1を超える値は、色域外か、SDR基準白より明るいHDR輝度か、その両方です。

2. アルファの逆乗算による増幅

DWMは乗算済みアルファで合成するため、非乗算(straight)へ戻しています。アルファが極端に小さい画素では、この除算が微小な誤差を大きく増幅します。乗算済みで−0.0001だった値は、A = 0.002なら−0.05になります。

該当するのはウィンドウの角の丸みや影の縁です。Aが1.0から大きく外れているときは、RGBの絶対値をそのまま信用しないでください。A = 1.0000の領域ではこの経路を通りません。

見分け方

  • Aがほぼ1で、負値が−0.3〜0程度 — 色域外の色。正常な測定値です。
  • Aが0に近く、負値が大きい — アルファ逆乗算による増幅。参考値として扱ってください。

面積加重平均は重みがすべて非負なので、平均処理が負値を作り出すことはありません。平均が負なら、元画素に負値があります。

HDRの経路

Windows.Graphics.Capture の Direct3D11CaptureFramePool を R16G16B16A16Float で作り、DWMが合成したウィンドウをscRGB float16のまま受け取ります。SDR画像へのフォールバックは行わず、OSが浮動小数点サーフェスを返さなかった場合はエラーにします。読み出し後に非乗算アルファへ戻し、SDR白レベルで正規化してRGBA float32として保持します。

描画はRGBA float32テクスチャ → Direct3D 11 → DXGI_FORMAT_R16G16B16A16_FLOAT のフリップモデルスワップチェーンで、色空間は DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709(scRGB)です。保持値をSDR白レベル基準からscRGBへ戻して出力するので、保存値の1.0はそのディスプレイのSDR白として出ます。描画面の精度やディスプレイ上限は保存・測定データに影響しません。固定SDRトーンマップは行いません。

scRGBスワップチェーンが使えない環境では、その旨を右下に表示したうえでsRGB符号化して表示します。表示だけがSDRになり、測定値は変わりません。

右下に表示状態を出します。表示 5.79× · パネル 1390 nit · SDR白 240 nit の形式で、倍率はパネルピーク ÷ SDR白レベル、つまりSDR白の上にどれだけ余地があるかです。パネルが全画面持続輝度をピークと別に申告する場合は / 全画面 ◯ nit も出ます。値は1秒ごとに更新します。

5.79× なら、5.79倍程度までは階調として区別でき、それを超える値は頭打ちになります。1.00× でも、HDRがONにできるディスプレイなら「今はSDR表示なだけ」で、1を超えるRGB値はデータとして保持されています。

輝度設定とヘッドルームの関係

パネルのピーク輝度は固定なので、SDR白レベル × ヘッドルーム ≦ パネルのピークという関係になります。「SDRコンテンツの明るさ」を上げるとSDR白そのものが明るくなり、その上に残る余地が減ります。上げすぎるとヘッドルームが 1.00× まで潰れます。

ヘッドルームが潰れた状態でHDR画像を見ると、1.0を超える値がすべて同じ明るさへクリップされます。テストパターンなら階調の段が区別できなくなり、色は最大値へ張り付いてサチュレーションしたように見えます。**これは表示側の頭打ちで、データは変化していません。**ピッカーの値は正しいままです。

HDRを評価するときは「SDRコンテンツの明るさ」を下げてください。現在の画像の最大値がヘッドルームを超えている場合、右下の表示に「画像の最大 30.00× は表示しきれず頭打ちです」と出ます。

なおスライダーを動かすと正規化係数も変わります。測定値の再現性が要るときは、スライダー位置を固定してください。

OSによる処理

DWMによる合成時の色変換はアプリ外の処理です。キャプチャ元アプリの内部シェーダー値とキャプチャ結果が完全一致するとは限りません。

保存形式

用途で使い分けます。1つの形式で測定と表示の両方は満たせません。

32bit float TIFF HDR JPEG XR
用途 測定・解析 表示・共有
値 生成データとビット単位で一致 half floatへ丸め、1.0 = 203 nit へスケール
Windowsフォト SDRにクリップされて表示 HDR表示
サイズ 幅×高さ×16バイト 数十分の1

32bit float TIFF(測定用)

TIFF、非圧縮、RGBA各32bit IEEE float、straight alpha、上から下の行順、リニアsRGB ICCプロファイル埋め込み。TIFFタグのSampleFormatはIEEE float、ExtraSamplesはunassociated alphaです。ImageDescriptionに 1.0 = SDR reference white と書き込みます。

macOS版と同じバイト構成です。両方のREADMEが同じ Tests/verify_tiff.py で検証できます。

浮動小数点配列を直接書き込み、保存前に自前のTIFFリーダーで解釈と一致を確認します。保存は一時ファイルを作ってから差し替える方式で、書き出しに失敗しても既存のファイルを壊しません。差し替え後は実ファイルを読み戻して生成データと完全一致することを確認します。SDR化・ガンマ再符号化・非可逆圧縮を行いません。

埋め込むICCプロファイルはコード内で組み立てています。ICCの色度はs15Fixed16なのでsRGB原色を厳密には表現できず、書き出した行列を読み戻すと単位行列から数万分の1ずれます。読み込み時にこの範囲の行列は単位行列として扱い、自分で書いたファイルの値が行列積で動かないようにしています。最も近い実在の色空間であるDisplay P3は22%離れているので、この判定で取り違えは起きません。

**WindowsフォトはこのTIFFをSDRにクリップして表示します。**これは保存値がSDR化されたことを意味しません。ファイル内には1.0を超える値がそのまま入っています。32bit float TIFF対応の解析ソフトで開くか、HDRScope上で測ってください。ファイルサイズは概ね幅×高さ×16バイトです。Classic TIFFのため4GB以上は拒否します。

HDR JPEG XR(表示用)

16bit float、scRGB、可逆。WindowsのHDRスクリーンショットと同じ形式で、追加のコーデック導入なしにWICだけで書けます。書き出し後に読み戻し、寸法とピクセル形式を確認してから配置します。

**ICCプロファイルは意図的に埋めていません。**プロファイルを埋めると、色管理を行うビューアはこれを普通のリニアsRGBとみなしてSDRにクリップします。実測で、プロファイル入りはWindowsフォトでピークがちょうどSDR白(scRGB 3.0)に張り付き1.0超が0.000%、プロファイルなしはピークscRGB 69.0・1.0超3.292%になりました。プロファイルのない浮動小数点JPEG XRはWindowsの慣例でscRGBなので、ビューアにとってプロファイルは不要で、あるとHDRを失うだけです。

そのかわり、1.0が何nitを指すかは ImageDescription(TIFFタグ270) に文字列で書きます。色管理の対象にならないメタデータなので表示に影響せず、HDRScopeで開き直したときはこれを読んでSDR白基準へ戻します。

値は 1.0 = 203 nit(ITU-R BT.2408のHDR基準白) へスケールして書きます。scRGBの1.0は80 nitなので、SDR白は 203/80 = 2.5375 として格納されます。保存時のスライダー位置に依存しない固定値です。**表示用なので、測定にはTIFFを使ってください。**ビューアがどう表示するかはビューア側の裁量です。

読み込み

TIFF / JPEG XR / HEIC / HEIF / PNG / JPEG を開けます。ファイル自身の色空間からキャプチャと同じ拡張リニアsRGBへ変換するので、開いた画像もキャプチャと同じ条件で測れます。

色空間の決定は次の順です。

  1. 埋め込みICCプロファイル。matrix/TRC形式(sRGB、リニアsRGB、Display P3、Adobe RGB、Rec.2020など、表示用RGBプロファイルのほぼ全部)を自前で解析し、TRCと原色行列を適用します。LUT型など解釈できない形式は、そう明示したうえでsRGBとして扱います。
  2. ISOBMFFの colr/nclx(HEIC・HEIFのCICP)。transfer characteristic 16 をBT.2100 PQとして扱います。ただしデコーダが浮動小数点で返してきた場合は、伝達関数も原色変換もすでに済んでいるものとして扱います(次項)。
  3. ImageDescriptionの基準白宣言(このツールが書いたJPEG XR)。
  4. それ以外の浮動小数点ファイルはscRGB(リニアRec.709、1.0 = 80 nit)。Windows標準のHDRスクリーンショットがこれにあたります。
  5. 整数ファイルはsRGB。

デコーダが先に変換している場合

WICの浮動小数点ピクセル形式は、Windowsの定義ではscRGB(リニアRec.709)です。**HEIFデコーダが 64bppRGBAHalf を返してきたら、その時点でPQは解かれ、原色もRec.709へ移されています。**このときCICPは「ファイルがどう符号化されていたか」の記録であって「いま手元にある値が何か」ではないので、CICPどおりに逆変換をもう一度かけると値が壊れます。

実測で確認できます。macOS版が書いたPQ HEICをデコードした生値には負値が含まれます。PQの符号値は非負なので、これは原色変換がすでに済んでいる証拠です。値の並びも元のリニアな階調の一定倍(実測 約2.52倍 = 203/80)で、PQ符号値の並びではありません。

そのためHEIC・HEIFが浮動小数点で返ってきた場合は、伝達関数も行列も適用せず、PQタグがあるときだけ 80 ÷ 203 を掛けてSDR基準白のスケールへ戻します。

整数形式は16bit整数のまま取り出してから自前で伝達関数を適用します。プラットフォームの変換に線形化を任せません。伝達関数は0..1の外側で奇対称に延長するので、色域外の負値が符号を保ったまま通ります。

PQは絶対輝度なので、1.0 = 203 nit(BT.2408)として換算します。**この基準はmacOS版と一致していました。**macOS版が書いたPQ HEICと、同じ内容のfloat TIFFを本ツールで開いて突き合わせたところ、階調が0.3〜1.1%以内で一致しました(下の検証記録)。ずれはPQの10bit量子化によるものです。

読み込み後、ステータス行に寸法・ビット深度・元の色空間・最大RGB・1.0超の画素の割合を出します。「このファイルは本当にHDRなのか」を外部ツールなしで確認できます。キャプチャ直後も同じ情報を出します。

コマンドラインからも同じ読み取り経路を使えます。

build\dist\HDRScope.exe --inspect image.tiff

--at x,y を並べると、その座標の測定値も出ます。GUIを開かずに2つのファイルを突き合わせるのに使えます。

HDRScope.exe --inspect a.tiff --at 180,90 --at 340,90
build\shot.tiff
  1262 × 851 px · 32bit float · ICC: HDRScope linear sRGB (Rec.709 primaries, D65, gamma 1.0)
  RGB 最小 -0.5876 / 最大 30.0000 · 1.0超 13.178% · アルファ最大 1.0000

環境の診断

macOS版の check-permission.sh にあたるものです。許可の概念がないので、代わりにディスプレイの状態と正規化係数、キャプチャ可否、ウィンドウ一覧の絞り込み結果を出します。

build\dist\HDRScope.exe --diagnose
HDRScope 診断
  Windows 10.0 build 26200
  ウィンドウキャプチャ(Windows.Graphics.Capture): 利用可能

ディスプレイ
  ディスプレイ 1: 32R84
    HDR              : ON(対応 あり)
    パネルピーク     : 1390 nit
    全画面持続       : 1390 nit
    SDR白            : 240 nit
    ヘッドルーム     : 5.79×
    正規化係数       : ×3.0000(キャプチャ値をこれで割ります)

ウィンドウ: 全230個、一覧に出るもの6個

ウィンドウを指定すると、GUIを開かずにキャプチャして測れます。座標指定と保存もできます。

HDRScope.exe --diagnose --capture "ウィンドウタイトルの一部" --at 564,262 --at 588,262 --save out.tiff

--save は拡張子で形式を選びます(.jxr ならHDR JPEG XR、それ以外はfloat TIFF)。

アプリ起動時に --test-pattern(固定の×30)または --headroom-pattern(ディスプレイに合わせた階調)を渡すと、キャプチャなしで表示・ピッカー・保存を確認できます。

ビルド・テスト

build.cmd --test

または直接:

cmake -S . -B build -G "Visual Studio 17 2022" -A x64
cmake --build build --config Release
build\dist\HDRScope.exe --self-test --test-output build\test-results
python Tests\verify_tiff.py build\test-results\roundtrip.tiff

Tests\verify_tiff.py はmacOS版と同一のファイルです。Python標準ライブラリだけで、TIFFタグ・ICC署名・行順・アルファ・float32のビット一致を独立実装で確認します。

tools\verify.cpp は表示経路の独立検証用です。指定したウィンドウを Windows.Graphics.Capture で取り込み、生のscRGB値とピーク輝度、SDR白を超えた画素の割合を出します(tools\build-verify.cmd でビルド)。HDRScopeにテストパターンを表示させてこれを向けると、既知の値がスワップチェーンからコンポジタを経て戻ってくるまでを一周で確認できます。

テストパターン

左下の2つのボタンで、キャプチャなしで表示上限を読み取れる既知値のパターンを出せます。どちらも白・赤・緑・青の4本の階調と、最下段の色域外・負値の帯(値は「負値と1超えの意味」の変換表と同じ)でできています。

**明るさが変わらなくなる段が、そのときの表示上限です。**ベタ塗りのパッチにしてあるのはこれを読み取るためです。

テストパターン ×30(固定)

1360 × 780 px。列は左から 0 / 0.09 / 0.18 / 0.5、以降は1刻みで30まで(34段)。macOS版と同じ内容で、どのディスプレイでも同じファイルになります。

刻みが1.0固定なので、ヘッドルームは「整数倍で何倍まで見えるか」までしか分かりません。ヘッドルーム5.79のディスプレイでは34段のうち使えるのが6段だけ、という使い方になります。

ヘッドルーム階調(ディスプレイに合わせて生成)

いま接続しているディスプレイのヘッドルームに合わせて刻みを決め、全部の列を実際に見える範囲に使います。押した時点のヘッドルームで作るので、輝度設定を変えたら押し直してください。

刻みは 1/16 / 1/8 / 1/4 / 1/2 / 1 のいずれかで、いずれも1.0を割り切ります。SDR白がかならず段のひとつに乗るので、基準として使えます。列数は最大34段に収まるうちで最も細かい刻みを選び、ヘッドルームの先に4段を足します。上限ちょうどで終わると頭打ちが「段が消える」形で見えないためです。

実機(ヘッドルーム 5.79)では 0 から 6.75 まで 0.25 刻みの28段になりました。ヘッドルームは23段目(5.75)と24段目(6.00)の間にあり、その先に4段が続きます。

ヘッドルーム 刻み 段数 上端
1.00 0.0625 20 1.1875
2.00 0.125 20 2.375
5.79 0.25 28 6.75
8.00 0.5 20 9.5
12.0 0.5 28 13.5
20.0 1.0 24 23
30.0 1.0 34 33

ヘッドルームが33を超えると、1刻みの34段でも届きません。そのときは階調が上限に届いていない旨をステータス行に出します(テストパターン ×30 を使ってください)。HDRがOFFのときはヘッドルームを1.00として作るので、SDR表示でどこからクリップされるかを見るのに使えます。

読み取りを狂わせる要因が2つあります。パネルの持続輝度制限により、面積の大きいパッチは小さいパッチほど明るくなりません。拡大表示してパッチを画面の一部だけに出すと影響が減ります。もう1つはSDRコンテンツの明るさ設定で、上げすぎるとヘッドルームが潰れて全段がサチュレーションします。

検証記録(2026-09-07)

環境:Windows 11 build 26200 / RTX 4070 Laptop / 32R84(HDR ON、パネルピーク1390 nit、SDR白240 nit)/ Visual Studio 2022 17.14(MSVC 14.44)/ Windows SDK 10.0.26100 / CMake 4.3.2。

  • 276アサーション成功:単一画素、面積平均、部分画素、画像境界、範囲外、行順、アルファ、sRGB・PQ伝達関数の往復、色域変換表の再計算、ICCプロファイルの往復、float TIFFのビット一致、上書き保存、sRGB PNGの線形化、JPEG XRの往復、クリップボード文字列、ヘッドルーム階調の構成。

  • Tests/verify_tiff.py(macOS版と同一)が本ツールの生成したTIFFで PASS。両ビルドのTIFFがバイト構成として互換であることを確認。

  • scRGBの基準を実測。純白のSDRウィンドウが 3.000000、グレー128が 0.647461 で返ることを確認。後者は linear(128/255) × 3.0 と完全一致し、SDR白レベル240 nit ÷ 80 = 3.0 に一致する。これを根拠に正規化係数を決めた。

  • 表示経路を実測。テストパターンを表示したウィンドウを別プロセスから Windows.Graphics.Capture で取り込み、保存値と出力scRGBの対応を確認。

    保存値 0 0.09 0.18 0.5 1 2 3 4 5 6 7
    出力scRGB 0.00000 0.26978 0.53955 1.50000 3.00000 6.00000 9.00000 12.00000 15.00000 18.00000 21.00000

    すべて厳密に3.0倍。保存値1.0がSDR白ちょうどに乗ることを確認した。

  • キャプチャ経路を実測。上のウィンドウをHDRScope自身でキャプチャして測り直し、0.18 → 0.179850(half float丸め)、0.5 → 0.500000、1 → 1.000000、2 → 2.000000、4 → 4.000000、5 → 5.000000 を確認。最小 −0.5876(Rec.2020緑のサンプル)、最大 30.0000 も保持。3.0の段が 2.997396 になったのはセル境界の面積平均によるもの。

  • 通常のSDRウィンドウのキャプチャで、最大RGBがちょうど 1.0000、1.0超が 0.000% になることを確認。SDR白が定義どおり1.0に乗っている。

  • JPEG XRのICCプロファイルがHDR表示を殺すことを実測。同じ内容で、プロファイル入りはWindowsフォトでピークがscRGB 3.0000(= SDR白ちょうど)・1.0超 0.000%、プロファイルなしはピーク 69.0000・1.0超 3.292%。フォトが色管理してSDRにクリップしていた。プロファイルを外し、基準白の宣言はImageDescriptionへ移した。移動後もフォトのHDR表示は維持され、本ツールでの読み戻しも基準白どおりに戻ることを確認。

  • float TIFFがWindowsフォトでSDRに見えることを実測。同じ内容のTIFFはピークがscRGB 3.0000(= SDR白ちょうど)・1.0超 0.000%、JPEG XRはピーク 69.0000・1.0超 3.292%。ファイル内には最大30.0000が入っており(--inspect で確認)、クリップはビューア側の挙動であることが確定した。macOS版のプレビューと同じ関係になっている。

  • 1360×780のテストパターンをGUIで開き、「1:1」に切り替えた状態を取り込んで、可視範囲の最大が階調23 → scRGB 69.0 になることを確認。1:1が物理1画素であることの裏取り。

  • ウィンドウ一覧の絞り込みを実測。トップレベルウィンドウ231個中、一覧に出るのは7個。

  • ヘッドルーム階調を実測。ヘッドルーム5.79の実機で 0 から 6.75 まで 0.25 刻みの28段が生成され、表示されたscRGBが 0段目 0.00000 / 1段目 0.75000 / 2段目 1.50000 / 4段目 3.00000 / 8段目 6.00000 / 12段目 9.00000 / 20段目 15.00000 / 23段目 17.25000 / 24段目 18.00000 / 27段目 20.25000 と、すべて階調値のちょうど3.0倍になることを確認。SDR白(1.0)が4段目にちょうど乗り、ヘッドルームの先に4段が残る。刻みの選び方・段数・SDR白が段に乗ること・等間隔であること・上限に届かない場合の申告は自己テストで7種類のヘッドルームについて検証。

  • GUIの操作を実機で確認。一覧からウィンドウを選んで「キャプチャ」→ 720 × 126 px · 正規化 ×3.000(SDR白 240 nit) · 最大RGB 1.0006 · 1.0超 0.710%、「保存…」→ float TIFF で 1,452,334 バイト(720×126×16 + ヘッダ)。保存したファイルを --inspect で読み戻し、最大RGB 1.0006・1.0超 0.710%・アルファ最大 0.9004 が一致することを確認。対象が半透明のウィジェットだったため、アルファ逆乗算でRGBがわずかに1.0を超える例にもなっている。

  • コマンドライン引数でのファイル指定・「1:1」への切り替え・ドラッグ&ドロップの受け口を確認。

  • HEIC / HEIFの読み込みを実ファイルで確認。iPhoneで撮影した10bit HEIC 3枚(4032 × 3024)を読み、いずれもICCが Display P3 として解釈され、最小RGBが 3枚とも −0.2250 になった。これは「負値と1超えの意味」の表にあるDisplay P3緑の赤成分 −0.2249 そのもので、色域外の色がsRGB原色へ正しく変換されていることの裏取りになっている(差はICCプロファイルの色度がs15Fixed16に量子化されているため)。最大RGBは 1.0653〜1.0863、1.0超は 0.419〜1.259% で、いずれもP3の色域外にある色。

  • macOS版が書いたファイルとの相互運用を実ファイルで確認(同じHDRテストパターンのfloat TIFFとPQ HEIC)。

    float TIFFは ICC: sRGB IEC61966-2.1 Linear として読め、最小 −0.5876 / 最大 30.0000 / 1.0超 41.503% で、Windows版が書いたものと完全に同じ値になった。

    PQ HEICは同じ座標で次のとおり一致した。

    座標 macOS float TIFF macOS PQ HEIC 差
    (180, 90) 1.000000 0.993688 −0.63%
    (340, 90) 5.000000 4.975369 −0.49%
    (500, 90) 9.000000 8.903941 −1.07%
    (700, 90) 14.000000 13.940886 −0.42%
    (1020, 90) 22.000000 21.921183 −0.36%
    (1340, 90) 30.000000 29.901478 −0.33%

    1.0超の画素の割合も 41.503% に対し 41.825%。色域外サンプルも (1359, 720) で −0.5854 / 1.1284 / −0.1002 となり、Rec.2020緑の理論値 −0.5876 / 1.1329 / −0.1006 と一致した。差はいずれもPQの10bit量子化による。macOS版のPQ書き出しも基準白は約203 nitであることが、この一致から確認できた。

  • WICのHEIFデコーダが先にPQを解いていることを実測。生のデコード結果は 64bppRGBAHalf で、負値 −1.5078 を含み(PQ符号値なら非負)、階調は元のリニア値の約2.52倍(= 203/80)だった。当初はCICPどおりPQの逆変換をかけていたため、最大 8.5×10¹⁹ という値になっていた。浮動小数点で返ってきた場合は変換済みとして扱うよう修正。

  • PQ HEICの最大値は 62.2660 と、TIFFの 30.0000 の2倍以上になる。位置は (1339, 179)、白帯の右端かつ赤帯との境界の1行上で、そこだけ R が跳ねている(G 24.70 / B 17.76)。4:2:0クロマサブサンプリングのリンギングであって、パッチ本体の値ではない。macOS版READMEが記録している「TIFF 13.88 に対しPQ HEIC 24.90」も同じ現象。PQ HEICを測定に使わないという原則は、この一点だけでも十分な理由になる。

  • 物理輝度の測定器による検証は未実施。nit表示はOSの申告値に基づく計算値です。

ウィンドウ一覧の絞り込み

EnumWindows はトップレベルウィンドウをすべて返します。この中には実際のウィンドウのほかに、メッセージ専用のヘルパー、クロークされたシェル用サーフェス、画面外のツールウィンドウが多数含まれます。実測では全231個中、一覧に出るものは7個でした。

そのため既定では、画面に出ていて(可視・最小化されておらず・クロークされておらず)、ツールウィンドウでなく、40ピクセル以上のウィンドウだけを一覧に出します。「非表示・小さなウィンドウも表示」をONにすると全件表示に戻ります。最小化中や別デスクトップのウィンドウを選びたい場合はONにしてください。

一覧のサイズは DWMWA_EXTENDED_FRAME_BOUNDS(見えている枠。不可視のリサイズ枠と影を含まない)で、Windows.Graphics.Capture が返すサイズと一致します。一覧の数字がそのままキャプチャの寸法になります。

キャプチャ結果は取得後に検査し、全画素が完全に透明だった場合と、全画素が同一の値だった場合は下部のステータスに明示します。エラーにはせず画像は表示するため、透明だったのか取得に失敗したのかを区別できます。

macOS版との違い

macOS版 Windows版
キャプチャ ScreenCaptureKit Windows.Graphics.Capture
権限 画面収録の許可・署名の管理が必要 不要
値の基準 OSが最初からSDR白基準 scRGB(1.0 = 80 nit)をSDR白レベルで正規化
表示 Metal + CAMetalLayer(EDR) Direct3D 11 + scRGBスワップチェーン
表示用の保存 PQ HEIC HDR JPEG XR
表示上限の申告 現在値と上限の2つの倍率 倍率+パネルピーク・全画面持続・SDR白のnit
Canonical / Local 選択あり なし(合成は単一のscRGB空間。かわりに正規化係数を常時表示)

「Canonical / Local」に相当する概念がWindowsにはありません。DWMの合成空間は1つで、ディスプレイごとに違うのはSDR白レベルだけです。キャプチャ対象ウィンドウが載っているディスプレイのSDR白レベルを使い、その値をステータス行に出します。

制約

最小化・別デスクトップ・保護コンテンツ等はOSにより取得不可、黒画像、または更新されない画像になることがあります。一覧では非表示のウィンドウを明示します。タイトルのないウィンドウもIDで選択できます。閉じたウィンドウの代わりに同名の別ウィンドウを自動選択しません。

非常に大きい画像では、float32配列・GPUテクスチャ・保存用データのためにメモリを多く使用します。通常のデスクトップウィンドウの静止画利用を想定しています。

表示の縮小率が極端に小さい場合(元画像1画素あたりの表示セルが32×32画素を超える場合)、GPU側の面積平均はセルを間引いて計算します。ピッカーの測定値は常にCPUで厳密に積分するので、この間引きは表示にしか影響しません。

ライセンス

MIT License。LICENSE を参照してください。

About

HDR Scope for Windows

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages