スクリーンショットが2倍サイズで表示されてしまう理由

前回からの続き。

  • Retina環境でスクリーンショットを撮影すると、撮影時の2倍サイズのピクセル数の画像として保存される。
  • 例えば、command-shift-4と押して、縦横500サイズで撮影すると、縦横1000pxの画像になる。
  • その縦横1000pxの画像をプレビュー.appで開くと、画面上は縦横500サイズの元の大きさとなる。
  • command-Iで画像情報を確認してみると、イメージのDPI=144ピクセル/インチとなっている。
  • Retina以前は72ピクセル/インチだったので、ちょうど縦横2倍の解像度になっているのだ。
  • では、144ピクセル/インチ・縦横1000pxの画像はすべて500サイズで表示されるかというと、そうではない。
  • プレビュー.appで「書き出す...」や「別名で保存...」を実行すると、144ピクセル/インチでありながら、画面上は縦横1000サイズの2倍の大きさとなる。

同じ144ピクセル/インチのはずなのに、いったい何が違っているというのか?

  • 以前から、スクリーンショットを加工すると、2倍サイズになってしまう現象に悩んでいた。
  • 2倍サイズになってもブログに載せる画像としては何ら問題ないのだけど、理由を知りたい。

EAの違い

調べてみると、スクリーンショットでもEAが暗躍していた!

  • lsコマンドで確認してみた。
$ ls -l@ スクリーンショット_別名で保存.png スクリーンショット_オリジナル.png 
-rw-r--r--@ 1 bebe  staff  267739  3  9 14:15 スクリーンショット_オリジナル.png
	com.apple.metadata:kMDItemIsScreenCapture	    42 
	com.apple.metadata:kMDItemScreenCaptureType	    51 
	com.apple.quarantine	    22 
-rw-r--r--@ 1 bebe  staff  267739  3  9 14:17 スクリーンショット_別名で保存.png
	com.apple.quarantine	    22 
  • オリジナルのスクリーンショットには、二つのEAが余分に付加されている。怪しい...。
    • com.apple.metadata:kMDItemIsScreenCapture
    • com.apple.metadata:kMDItemScreenCaptureType
  • xattrコマンドで確認してみた。
$ xattr -l スクリーンショット_オリジナル.png 
com.apple.metadata:kMDItemIsScreenCapture:
00000000  62 70 6C 69 73 74 30 30 09 08 00 00 00 00 00 00  |bplist00........|
00000010  01 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00 00 09                    |..........|
0000002a
com.apple.metadata:kMDItemScreenCaptureType:
00000000  62 70 6C 69 73 74 30 30 59 73 65 6C 65 63 74 69  |bplist00Yselecti|
00000010  6F 6E 08 00 00 00 00 00 00 01 01 00 00 00 00 00  |on..............|
00000020  00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00  |................|
00000030  00 00 12                                         |...|
00000033
com.apple.quarantine: 0042;531bf90c;Preview;

$ xattr -l スクリーンショット_別名で保存.png
com.apple.quarantine: 0042;531bf978;Preview;
  • EAの中身はどちらもplistのよう(bplist00で始まっているので)だが、その中身はどうやったら見られるのだろう?

com.apple.metadata:kMDItemIsScreenCapture

  • xxdコマンドを使って、バイナリデータのcom.apple.metadata:kMDItemIsScreenCapture.plistとして書き出してみた。
$ xattr -p com.apple.metadata:kMDItemIsScreenCapture スクリーンショット_オリジナル.png | xxd -ps -r > com.apple.metadata:kMDItemIsScreenCapture.plist
  • バイナリ形式のplistをxmlに変換した。
$ plutil -convert xml1 -o com.apple.metadata:kMDItemIsScreenCapture.xml com.apple.metadata:kMDItemIsScreenCapture.plist
  • catコマンドで中身を確認してみると...
$ cat com.apple.metadata:kMDItemIsScreenCapture.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<true/>
</plist>

つまり「com.apple.metadata:kMDItemIsScreenCapture = true」ということ。

com.apple.metadata:kMDItemScreenCaptureType

  • もう一つのEAも、同じように確認してみる。
$ xattr -p com.apple.metadata:kMDItemScreenCaptureType スクリーンショット_オリジナル.png  | xxd -ps -r > com.apple.metadata:kMDItemScreenCaptureType.plist
$ plutil -convert xml1 -o com.apple.metadata:kMDItemScreenCaptureType.xml com.apple.metadata:kMDItemScreenCaptureType.plist 
$ cat com.apple.metadata:kMDItemScreenCaptureType.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<string>selection</string>
</plist>

つまり「com.apple.metadata:kMDItemScreenCaptureType = "selection"」ということ。

  • ちなみに、
    • command-shift-4とspaceでウィンドウ撮影すると、"selection"の部分は"window"に変化した。
    • command-shift-3で画面全体を撮影すると、"selection"の部分は"display"に変化した。

EAを削除する実験

では、怪しげな二つのEAを一つずつ削除してみることにした。

  • まずはcom.apple.metadata:kMDItemIsScreenCaptureを削除してみる。
$ cp スクリーンショット_オリジナル.png without_kMDItemIsScreenCapture.png

$ xattr -d com.apple.metadata:kMDItemIsScreenCapture without_kMDItemIsScreenCapture.png

$ xattr without_kMDItemIsScreenCapture.png
com.apple.metadata:kMDItemScreenCaptureType
com.apple.quarantine
  • プレビュー.appで開いてみると...

2倍サイズで拡大表示された!

  • 同様にcom.apple.metadata:kMDItemScreenCaptureTypeを削除してみた。
$ cp スクリーンショット_オリジナル.png without_kMDItemScreenCaptureType.png

$ xattr -d com.apple.metadata:kMDItemScreenCaptureType without_kMDItemScreenCaptureType.png

$ xattr without_kMDItemScreenCaptureType.png
com.apple.metadata:kMDItemIsScreenCapture
com.apple.quarantine
  • プレビュー.appで開いてみると...

元の大きさを維持した高解像度(144ピクセル/インチ)で表示された!


プレビュー.appやQuick Lookで、Retina環境を活かした高解像度で表示するためには、com.apple.metadata:kMDItemIsScreenCaptureが必須なようだ。

EAにplistを書き込む方法

  • では、com.apple.metadata:kMDItemIsScreenCaptureを画像ファイルに追記したい。
  • バイナリ形式のplistを、どうやったらEAに追記することができるのだろう?
  • テキスト形式のtrueであれば、以下のコマンドでtrueを書き込めるのだけど、
$ xattr -w com.apple.metadata:kMDItemIsScreenCapture true スクリーンショット_別名で保存.png

$ xattr -l スクリーンショット_別名で保存.png
com.apple.metadata:kMDItemIsScreenCapture: true
com.apple.quarantine: 0042;531bf978;Preview;

これでは高解像度(144ピクセル/インチ)にならない...。

  • そこで、xxdコマンドで先ほど書き出したcom.apple.metadata:kMDItemIsScreenCapture.plistを読み込んで、それを16進数データとして書き込んでみた。
$ xattr -wx com.apple.metadata:kMDItemIsScreenCapture "`xxd -ps com.apple.metadata:kMDItemIsScreenCapture.plist`" スクリーンショット_別名で保存.png
  • 確認してみると、com.apple.metadata:kMDItemIsScreenCaptureはバイナリ形式のplistのように見える。(バイトコードの並びは一致している)
$ xattr -l スクリーンショット_別名で保存.png
com.apple.metadata:kMDItemIsScreenCapture:
00000000  62 70 6C 69 73 74 30 30 09 08 00 00 00 00 00 00  |bplist00........|
00000010  01 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00 00 09                    |..........|
0000002a
com.apple.quarantine: 0042;531bf978;Preview;
  • プレビュー.appで開いてみると...

見事!高解像度(144ピクセル/インチ)で表示された!

  • しかし、毎回バイナリ形式のplistファイルを用意して書き込むのはちょっと手間である。
  • ワンライナーで完結する方法を考えてみると、`xxdコマンド`の部分は16進数データに置き換えられる訳なので、
  • その部分に直接、16進数データをハードコーディングしてしまっても良いと気付いた。
$ xattr -wx com.apple.metadata:kMDItemIsScreenCapture "62706c697374303009080000000000000101000000000000000100000000000000000000000000000009" スクリーンショット_別名で保存.png

これでplistファイルが不要になった!

おまけの実験

144dpi以外の解像度ではどうなるのか?
  • EAはそのままに解像度を変更してみた。
$ sips -s dpiWidth 72 -s dpiHeight 72 -o 72dpi.png スクリーンショット_オリジナル.png
$ xattr -wx com.apple.metadata:kMDItemIsScreenCapture "62706c697374303009080000000000000101000000000000000100000000000000000000000000000009" 72dpi.png

$ sips -s dpiWidth 300 -s dpiHeight 300 -o 300dpi.png スクリーンショット_オリジナル.png
$ xattr -wx com.apple.metadata:kMDItemIsScreenCapture "62706c697374303009080000000000000101000000000000000100000000000000000000000000000009" 300dpi.png

残念ながら、どちらも2倍サイズで拡大表示されてしまった...。
Retina環境では144dpiのみ、高解像度で表示されるようだ。

falseのplistを書き込むとどうなるのか?
  • falseのバイナリ形式plistを書き込んでみた。
$ cat << EOS > com.apple.metadata:kMDItemIsScreenCapture_false.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<false/>
</plist>
EOS

$ plutil -convert binary1 -o com.apple.metadata:kMDItemIsScreenCapture_false.plist com.apple.metadata:kMDItemIsScreenCapture_false.xml

$ xattr -wx com.apple.metadata:kMDItemIsScreenCapture "`xxd -ps com.apple.metadata:kMDItemIsScreenCapture_false.plist`" スクリーンショット_別名で保存.png

残念ながら、2倍サイズで拡大表示されてしまった...。
plistが「true」の場合のみ高解像度で表示される。

xml形式のplistを書き込むとどうなるのか?
  • trueのxml形式plistを書き込んでみた。
$ cat << EOS > com.apple.metadata:kMDItemIsScreenCapture_xml.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<true/>
</plist>
EOS

$ xattr -wx com.apple.metadata:kMDItemIsScreenCapture "`xxd -ps com.apple.metadata:kMDItemIsScreenCapture_xml.plist`" スクリーンショット_別名で保存.png

$ xattr -l スクリーンショット_別名で保存.png
com.apple.metadata:kMDItemIsScreenCapture: <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<true/>
</plist>

com.apple.quarantine: 0042;531bf978;Preview;

見事!高解像度(144ピクセル/インチ)で表示された!
trueのplistなら、バイナリ形式でも、xml形式でも、どちらでもOK。