← すべての記事

写真保存形式をjpgからwebpに切り替えた

これまで、写真の保存形式としては主に`jpg`(JPEG)を使っていました。扱いやすく、ほとんどの環境で問題なく開くことができるため、特に疑問も持たずに長年使い続けていたのです。

写真保存形式をjpgからwebpに切り替えた#

はじめに#

これまで、写真の保存形式としては主にjpg(JPEG)を使っていました。扱いやすく、ほとんどの環境で問題なく開くことができるため、特に疑問も持たずに長年使い続けていたのです。

ところが最近、「webp」という画像形式を見かける機会が増えてきました。Googleが開発した形式で、主にWebの高速表示を目的としているそうです。少し気になったので、自分の環境でも試してみることにしました。

webp形式のメリット#

調べてみたところ、webpにはいくつかの魅力的な特長があることがわかりました。

  • ファイルサイズが小さい:同じ画質で保存した場合でも、jpgより圧縮率が高く、容量がかなり抑えられます。
  • 画質も良好:圧縮による劣化が目立ちにくく、自然な見た目を保てます。
  • 透過対応:pngと同様に背景を透明にできるため、用途の幅が広がります。
  • アニメーション対応:gifの代替としても利用可能です。

対応状況も年々改善されており、主要なブラウザやモダンなOSではほとんど問題なく再生・表示が可能になってきています。

Macでのwebp対応状況#

私が特に驚いたのは、macOSがwebp形式をいつの間にか標準でサポートしていたという点です。

Finderでのサムネイル表示やQuick Look(スペースキーによるプレビュー)も対応しており、Preview.appでも問題なく開けました。普段使っている画像ビューアと変わらない使い心地で、非常にスムーズでした。

jpgからwebpへの変換自動化#

brewに入っているので、以下のコマンドでOKです。

Terminal window
brew install webp
cwebp -q 80 input.jpg -o output.webp

一つ一つやるのは大変なので既存のjpgファイルを一括でwebpに変換してみようと思い、自分で変換スクリプトを作成します。 Claude Codeでささっと。AIが作ると絵文字が多くなるのはなんでなんでしょうね。

#!/bin/bash
# JPG/PNG/JPEGファイルをWebPに再帰的に変換するスクリプト
# 使用方法: ./image-to-webp-converter.sh /path/to/directory [quality]
# 引数チェック
if [ $# -lt 1 ]; then
echo "使用方法: $(basename "$0") <ディレクトリパス> [品質(0-100、デフォルト:70)]"
echo "例: $(basename "$0") '/home/user/pictures with spaces' 85"
echo "例: $(basename "$0") /home/user/pictures 85"
exit 1
fi
TARGET_DIR="$1"
QUALITY="${2:-70}"
# ディレクトリの存在チェック
if [ ! -d "$TARGET_DIR" ]; then
echo "エラー: ディレクトリ '$TARGET_DIR' が存在しません"
exit 1
fi
# cwebpコマンドの存在チェック
if ! command -v cwebp &> /dev/null; then
echo "エラー: cwebpコマンドが見つかりません"
echo "WebPツールをインストールしてください"
exit 1
fi
# 品質の範囲チェック
if ! [[ "$QUALITY" =~ ^[0-9]+$ ]] || [ "$QUALITY" -lt 0 ] || [ "$QUALITY" -gt 100 ]; then
echo "エラー: 品質は0-100の数値で指定してください"
exit 1
fi
# ディレクトリ全体のサイズを計算する関数
get_directory_size() {
local dir="$1"
if command -v du >/dev/null 2>&1; then
# macOSとLinux両対応
local size_kb=$(du -sk "$dir" 2>/dev/null | cut -f1)
if [ -n "$size_kb" ] && [ "$size_kb" -gt 0 ]; then
echo $((size_kb * 1024)) # KBをBに変換
else
echo "0"
fi
else
echo "0"
fi
}
# ファイルサイズを人間が読みやすい形式に変換する関数
human_readable_size() {
local size=$1
if [ "$size" -ge 1073741824 ]; then
echo "$(echo "scale=2; $size / 1073741824" | bc -l) GB"
elif [ "$size" -ge 1048576 ]; then
echo "$(echo "scale=2; $size / 1048576" | bc -l) MB"
elif [ "$size" -ge 1024 ]; then
echo "$(echo "scale=2; $size / 1024" | bc -l) KB"
else
echo "${size} B"
fi
}
# 圧縮率を計算する関数
calculate_compression_ratio() {
local original=$1
local compressed=$2
if [ "$original" -gt 0 ]; then
echo "$(echo "scale=1; (($original - $compressed) * 100) / $original" | bc -l)"
else
echo "0"
fi
}
echo "=== 画像 to WebP 変換スクリプト ==="
echo "対象ディレクトリ: $TARGET_DIR"
echo "品質設定: $QUALITY"
echo "対応形式: JPG, JPEG, PNG"
echo "==============================="
# 指定されたディレクトリに移動して処理を実行
cd "$TARGET_DIR" || {
echo "エラー: ディレクトリ '$TARGET_DIR' に移動できません"
exit 1
}
# 変換前のディレクトリサイズを取得
echo ""
echo "📁 変換前のディレクトリサイズを計算中..."
initial_dir_size=$(get_directory_size ".")
echo "変換前ディレクトリサイズ: $(human_readable_size $initial_dir_size)"
echo ""
# 一時ファイルでカウンターとサイズを管理
temp_dir=$(mktemp -d)
trap "rm -rf '$temp_dir'" EXIT # スクリプト終了時に一時ディレクトリを削除
converted_count_file="$temp_dir/converted_count"
failed_count_file="$temp_dir/failed_count"
total_original_size_file="$temp_dir/total_original_size"
total_converted_size_file="$temp_dir/total_converted_size"
echo "0" > "$converted_count_file"
echo "0" > "$failed_count_file"
echo "0" > "$total_original_size_file"
echo "0" > "$total_converted_size_file"
# findコマンドで再帰的に検索・変換(JPG、JPEG、PNGに対応)
while IFS= read -r -d '' file; do
# 出力ファイル名を生成(拡張子をwebpに変更)
output="${file%.*}.webp"
# 元ファイルのサイズを取得
if [ -f "$file" ]; then
original_size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null || echo "0")
else
original_size=0
fi
# ファイル形式を判定してcwebpのオプションを調整
file_ext=$(echo "${file##*.}" | tr '[:upper:]' '[:lower:]')
# PNGの場合は可逆圧縮オプションも提供
if [ "$file_ext" = "png" ]; then
# PNGの場合、透明度がある可能性があるのでアルファチャンネルを保持
cwebp_options="-q $QUALITY -alpha_cleanup"
# 可逆圧縮を試してみて、サイズが小さくなるかチェック
temp_lossless="${output}.temp_lossless"
cwebp -lossless "$file" -o "$temp_lossless" 2>/dev/null
if [ -f "$temp_lossless" ]; then
lossless_size=$(stat -f%z "$temp_lossless" 2>/dev/null || stat -c%s "$temp_lossless" 2>/dev/null || echo "0")
else
lossless_size=999999999 # 失敗した場合は非常に大きい値
fi
else
cwebp_options="-q $QUALITY"
lossless_size=999999999
fi
echo "変換中: $file ($(human_readable_size $original_size))"
# WebPに変換
if cwebp $cwebp_options "$file" -o "$output" 2>/dev/null; then
# 変換後ファイルのサイズを取得
if [ -f "$output" ]; then
converted_size=$(stat -f%z "$output" 2>/dev/null || stat -c%s "$output" 2>/dev/null || echo "0")
else
converted_size=0
fi
# PNGの場合、可逆圧縮の方が小さければそちらを使用
if [ "$file_ext" = "png" ] && [ "$lossless_size" -lt "$converted_size" ] && [ -f "$temp_lossless" ]; then
mv "$temp_lossless" "$output"
converted_size=$lossless_size
compression_type="可逆圧縮"
else
compression_type="品質$QUALITY"
[ -f "$temp_lossless" ] && rm "$temp_lossless"
fi
# 圧縮率を計算
compression_ratio=$(calculate_compression_ratio $original_size $converted_size)
# 変換成功時は元ファイルを削除
if rm "$file"; then
echo "✓ 変換完了: $file -> $output ($compression_type)"
echo " サイズ: $(human_readable_size $original_size) -> $(human_readable_size $converted_size) (${compression_ratio}% 圧縮)"
# カウンターを一時ファイルに記録
converted_count=$(cat "$converted_count_file")
total_original_size=$(cat "$total_original_size_file")
total_converted_size=$(cat "$total_converted_size_file")
echo $((converted_count + 1)) > "$converted_count_file"
echo $((total_original_size + original_size)) > "$total_original_size_file"
echo $((total_converted_size + converted_size)) > "$total_converted_size_file"
else
echo "✗ 元ファイルの削除に失敗: $file"
# 削除に失敗した場合は変換ファイルも削除
[ -f "$output" ] && rm "$output"
[ -f "$temp_lossless" ] && rm "$temp_lossless"
failed_count=$(cat "$failed_count_file")
echo $((failed_count + 1)) > "$failed_count_file"
fi
else
echo "✗ 変換失敗: $file"
# 失敗時は不完全なWebPファイルがあれば削除
[ -f "$output" ] && rm "$output"
[ -f "$temp_lossless" ] && rm "$temp_lossless"
failed_count=$(cat "$failed_count_file")
echo $((failed_count + 1)) > "$failed_count_file"
fi
echo "" # 空行で区切り
done < <(find . -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) -print0)
# 一時ファイルから最終結果を読み取り
converted_count=$(cat "$converted_count_file")
failed_count=$(cat "$failed_count_file")
total_original_size=$(cat "$total_original_size_file")
total_converted_size=$(cat "$total_converted_size_file")
echo "==============================="
echo "変換完了: ${converted_count}ファイル"
echo "変換失敗: ${failed_count}ファイル"
# 変換後のディレクトリサイズを取得
echo ""
echo "📁 変換後のディレクトリサイズを計算中..."
final_dir_size=$(get_directory_size ".")
echo ""
echo "=== 最終結果 ==="
echo "変換前ディレクトリサイズ: $(human_readable_size $initial_dir_size)"
echo "変換後ディレクトリサイズ: $(human_readable_size $final_dir_size)"
if [ $converted_count -gt 0 ]; then
echo ""
echo "=== 詳細なサイズ比較・圧縮効果 ==="
echo "【変換対象ファイルのみ】"
echo "変換前総サイズ: $(human_readable_size $total_original_size)"
echo "変換後総サイズ: $(human_readable_size $total_converted_size)"
if [ $total_original_size -gt 0 ]; then
saved_size=$((total_original_size - total_converted_size))
total_compression_ratio=$(calculate_compression_ratio $total_original_size $total_converted_size)
# ディレクトリ全体での節約サイズ
if [ $initial_dir_size -gt 0 ] && [ $final_dir_size -gt 0 ]; then
dir_saved_size=$((initial_dir_size - final_dir_size))
dir_compression_ratio=$(calculate_compression_ratio $initial_dir_size $final_dir_size)
else
dir_saved_size=0
dir_compression_ratio="0"
fi
echo ""
echo "🎉 圧縮効果 🎉"
echo "【変換ファイルのみ】"
echo " 節約されたサイズ: $(human_readable_size $saved_size)"
echo " 圧縮率: ${total_compression_ratio}%"
echo "【ディレクトリ全体】"
echo " ディレクトリ容量削減: $(human_readable_size $dir_saved_size)"
echo " ディレクトリ圧縮率: ${dir_compression_ratio}%"
echo " 🎯 合計ストレージ節約効果: $(human_readable_size $dir_saved_size)"
# パーセンテージでの節約効果も表示
if [ $total_original_size -gt 0 ]; then
savings_percentage=$(echo "scale=1; ($saved_size * 100) / $total_original_size" | bc -l)
echo " 変換ファイル削減率: ${savings_percentage}%"
fi
if [ $initial_dir_size -gt 0 ] && [ $dir_saved_size -gt 0 ]; then
dir_savings_percentage=$(echo "scale=1; ($dir_saved_size * 100) / $initial_dir_size" | bc -l)
echo " ディレクトリ全体削減率: ${dir_savings_percentage}%"
fi
fi
fi
echo "=============================="

使い方

Terminal window
chmod u+x jpg2webp.sh
./jpg2webp ./images

圧縮率や画質の検証#

実際に、100枚ほどのjpg画像をwebp形式に変換して比較してみたところ:

  • 平均で40〜60%ほどのファイルサイズ削減が見られました。
  • 肉眼で見た限り、ほとんど画質の違いは感じませんでした。
  • 特に風景写真や物撮り画像などは、webpとの相性がとても良い印象です。

という感じで圧縮効果がかなりあります。古い端末だと見えないかもしれないので、まだ完全に置き換えるのは難しそうですが、、、

画像圧縮ツールの一つであるjpeg mini proとの併用も検討しています。たとえば、まずjpgをjpeg mini proで圧縮してからwebpに変換すると、さらに無駄のないファイルサイズが実現できそうです。

まとめ#

今回、jpgからwebpへの移行を実際に行ってみて、非常に満足しています。

  • 表示速度が向上し、Webページのパフォーマンスにも好影響
  • ストレージ容量の節約にもつながる
  • 自動化スクリプトの作成によって画像管理の効率化も実現

まだすべての用途に適しているとは言い切れませんが、**「画像を軽量化したい」「でも画質は保ちたい」**と考えている方には、webpはとてもおすすめの形式だと思います。