写真保存形式をjpgからwebpに切り替えた話
写真保存形式を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です。
1
2
brew install webp
cwebp -q 80 input.jpg -o output.webp
一つ一つやるのは大変なので既存のjpgファイルを一括でwebpに変換してみようと思い、自分で変換スクリプトを作成します。 Claude Codeでささっと。AIが作ると絵文字が多くなるのはなんでなんでしょうね。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#!/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 "=============================="
使い方
1
2
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はとてもおすすめの形式だと思います。