macOS の Retina scale factor は GUI API 無しで Finder desktop bounds ÷ system_profiler Resolution で検出できる
AppleScript
macOS
画面解像度
知識
判断
Swift/Objective-C の NSScreen.backingScaleFactor を使わずとも、shell だけで実効的な HiDPI scale factor(物理px ÷ 論理pt)を求められる。
手順
- 論理pt解像度: AppleScript で Finder のデスクトップウィンドウの bounds を取得する(
tell application "Finder" to get bounds of window of desktop)。戻り値はx1, y1, x2, y2のカンマ区切りで、幅は x2、高さは y2(原点は 0,0)。 - 物理px解像度:
system_profiler SPDisplaysDataTypeのプレーンテキスト出力にあるResolution: <W> x <H>[ Retina]行から幅・高さを取得する。 - scale = round(物理px幅 / 論理pt幅)。実機(Apple Silicon 内蔵 Retina ディスプレイ)で
bounds幅 1728pt・Resolution幅 3456px → scale=2 が正しく算出されることを確認済み。
採用条件・却下した代替案
system_profiler SPDisplaysDataType -jsonの構造化キー(例: pixels/resolution 相当のキー)を厳密パースする案は却下した。JSON のキー名は macOS バージョンで変わるリスクがあり、キー名不一致で静かに検出失敗する。プレーンテキストのResolution:行を正規表現で拾う方が macOS バージョン間で安定する(表示文言はユーザー向けなので互換性が保たれやすい)。- Swift で CGDisplayScreenSize 等のネイティブ API を叩く案も検出精度は高いが、コンパイル済みヘルパーの配布・ビルド環境が要るためシェルコマンドのみで完結する軽量ツールには過剰。
落とし穴
- 複数ディスプレイ環境では
system_profilerのResolution:行は複数出現する。デスクトップの bounds が指すディスプレイ(通常は主ディスプレイ)と、system_profiler 側でどのエントリが同じ物理ディスプレイかを対応付ける処理をしないと、外部モニタなど別ディスプレイの解像度と誤ってペアリングしうる。単一ディスプレイ前提の簡易実装ではこの対応付けを省略し、複数ディスプレイは非対応として明示的に切り捨てるのが安全。 - 検出手段(osascript / system_profiler)が失敗する環境(権限不足・sandboxed 実行等)を想定し、固定値へのフォールバックを必ず用意する。
検証方法
実機で bounds と Resolution: を両方手動取得し、既知の scale(例: Retina=2, 非Retina=1)と一致するかを確認する。継続的な検証としては、算出した scale を使ってウィンドウサイズ(pt)から求めた px 寸法が、実際にスクリーンキャプチャした画像の寸法と一致するかで裏取りする。