きっかけ
スクリーンショットをQiita記事やSlackにそのまま貼ると、地味にファイルサイズが気になったり、アップロード容量制限にすぐに引っかかったり(記事用の3MB〜5MBのスクショを何も考えずにアップしていたら半月ほどで100MB制限に引っかかりました、、、)。
かといって毎回pngquantを手打ちしたり、tinypngのwebサービスに毎回アップするのも面倒です。
そこで、Claudeに相談して 「スクショを撮ったら自動的に画像容量圧縮する方法」 を聞いてみました。
質疑応答の末、一番シンプルだったのは「Desktopに置かれたpngを勝手に監視して圧縮しておく」という方式だった。ブラウザ拡張もNative Messagingも要らない。
fswatchでファイルの出現を検知して、pngquantとoxipngで圧縮し、launchdでログイン時から常駐させるだけで済ませられる、という代物です。
Windowsはこちらです
この記事でできるようになること
- Desktop(任意のフォルダ)にpngを置くと自動で圧縮版が生成される
- Macを再起動しても自動で監視が再開する
- ログイン中は常にバックグラウンドで動き続け、余計なログファイルも残らない
- 圧縮完了時にデスクトップ通知で削減率が分かる
準備するもの
brew install fswatch pngquant oxipng
fswatchはファイルシステムの変更をイベントとして拾うツール、pngquantは減色による圧縮、oxipngはロスレスな再最適化を担当する。この2つを組み合わせることで、見た目をほぼ保ったままファイルサイズをかなり削れるようです。
監視スクリプト
~/bin/png-compress-watch.sh として保存します。
#!/bin/bash
WATCH_DIR="$HOME/Desktop"
OUTPUT_DIR="$HOME/Desktop/compressed"
mkdir -p "$OUTPUT_DIR"
fswatch -0 --event Created --event Renamed "$WATCH_DIR" | while read -d "" event
do
case "$event" in
"$OUTPUT_DIR"*) continue ;;
*.png|*.PNG) ;;
*) continue ;;
esac
[ -f "$event" ] || continue
last_size=-1
while true; do
[ -f "$event" ] || break
current_size=$(stat -f%z "$event" 2>/dev/null)
if [ "$current_size" == "$last_size" ] && [ -n "$current_size" ]; then
break
fi
last_size=$current_size
sleep 0.3
done
[ -f "$event" ] || continue
filename=$(basename "$event")
output_path="$OUTPUT_DIR/$filename"
before_size=$(stat -f%z "$event")
pngquant --quality=65-85 --output "$output_path" --force "$event" 2>/dev/null
if [ $? -ne 0 ]; then
cp "$event" "$output_path"
fi
oxipng -o 4 -q "$output_path" 2>/dev/null
after_size=$(stat -f%z "$output_path")
reduced=$(echo "scale=1; 100 - ($after_size * 100 / $before_size)" | bc)
osascript -e "display notification \"${before_size}B → ${after_size}B (${reduced}%削減)\" with title \"PNG圧縮完了\" subtitle \"$filename\""
done
実行権限を付けます。
chmod +x ~/bin/png-compress-watch.sh
stat -f%z はmacOS(BSD系)のオプション。Linuxで動かす場合は stat -c%s に置き換える必要があるそうです。
launchdへの登録
~/Library/LaunchAgents/com.onuuuuuumax.pngcompress.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">
<dict>
<key>Label</key>
<string>LABEL_NAME</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>/Users/YOUR_USERNAME/bin/png-compress-watch.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
</dict>
</dict>
</plist>
LABEL_NAMEは任意で。例えば下記の用に軽く設定しておけば良いです。
<key>Label</key>
<string>com.onuuuuuumax.pngcompress</string>
YOUR_USERNAMEはwhoamiの結果に置き換えます。大抵は、/Users/****の**** に当たるところです。
LABEL_NAME.plist として登録します。例えば下記のようにです。
launchctl load ~/Library/LaunchAgents/com.onuuuuuumax.pngcompress.plist
動作確認
Desktopに適当なpngをコピーすると、数百ミリ秒後にcompressedフォルダへ圧縮版が生成され、削減率つきのデスクトップ通知が表示される。
初回だけ、システム設定の通知許可を求められることがある。表示されない場合は「システム設定 → 通知」から、スクリプトを実行しているアプリ(ターミナルやScript Editor扱いになることが多い)が許可されているか確認します。
常駐状態は以下で確認できます。
launchctl list | grep pngcompress
止めたい場合。
launchctl unload ~/Library/LaunchAgents/<LABEL_NAME>.plist
圧縮率について
pngquantの減色は、写真的なグラデーションが多い画像だと色の境目に若干の劣化が見える場合があります。
(確かに赤色系が劣化しているような雰囲気です)
スクリーンショットやアイコン、UIキャプチャのような単色面が多い画像では体感できる劣化はほとんどなく、削減率も50〜70%程度と大きいです。用途によっては--quality=65-85をもう少し上げて画質寄りに振ってもいいでしょう。
まとめ
- fswatch pngquant oxipngをインストール
- 監視スクリプトを作成
- launchdへ登録
成果
↓compressedに保存された圧縮されたpng
少し赤みが減って暗くなったような気もしますが、だいぶ圧縮されました!
これで長年悩まされてきた画像圧縮作業から解放されます!
スクショでなくても、圧縮対象を配置するフォルダや圧縮先フォルダの指定を要件に合わせてば色々と活用できそうです。



