skills/compressing-epub-images/SKILL.md
EPUB ファイル内の画像(主にスキャン本の JPEG)を再エンコード・リサイズしてファイルサイズを削減するスキル。AskUserQuestion で圧縮レベル選択フローを提供し、実測サンプリングから予測サイズを提示してからユーザーに選ばせる。 Use when: EPUB ファイルが大きく画像圧縮で削減したい時、スキャン本(画像ベース EPUB)の容量を減らしたい時、Kindle などの電子書籍リーダーに転送する前にサイズ最適化したい時。 画像ベース EPUB(スキャン本)と通常 EPUB の両方に対応。書誌情報・xhtml・css は触らず画像のみ再エンコード。
npx skillsauth add sumik5/sumik-claude-plugin compressing-epub-imagesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
EPUB ファイルの容量の 95% 以上は画像(JPEG)が占めるケースが多い。特にスキャン本(資格試験対策本・学術書・技術書)は 1 ページ 1 JPEG で構成されているため、JPEG 品質値(quality)を下げるだけで劇的にサイズが削減できる。
代表的な効果の例:
ただし JPEG の再エンコードは不可逆処理。元ファイルは必ず保持すること。
EPUB は ZIP 形式のアーカイブ。unzip で展開する。
EPUB_PATH="/path/to/book.epub"
WORK_DIR=$(mktemp -d)
unzip -q "$EPUB_PATH" -d "$WORK_DIR"
echo "展開先: $WORK_DIR"
画像ファイルの枚数・代表解像度・現在の quality を確認する。
# JPEG・PNG の一覧と枚数
find "$WORK_DIR" -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' | wc -l
# 代表的な 3 枚の解像度と現在の quality を確認
find "$WORK_DIR" -iname '*.jpg' -o -iname '*.jpeg' | head -3 | while read f; do
magick identify -verbose "$f" | grep -E "Image:|Geometry:|Quality:"
done
# ファイルサイズの合計(MB)
find "$WORK_DIR" -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \
-exec du -k {} + | awk '{sum+=$1} END {printf "画像合計: %.1f MB\n", sum/1024}'
10 枚程度の代表サンプルを複数の圧縮設定で実測し、全体のサイズを予測する。
# 均等サンプリング(10 枚)
TOTAL=$(find "$WORK_DIR" -iname '*.jpg' -o -iname '*.jpeg' | wc -l)
STEP=$(( TOTAL / 10 ))
SAMPLES=$(find "$WORK_DIR" -iname '*.jpg' -o -iname '*.jpeg' | sort | awk "NR % $STEP == 0")
# 各圧縮レベルで実測(サンプル 10 枚の合計サイズ → 全体予測)
SAMPLE_ORIG=0
SAMPLE_Q70=0
SAMPLE_Q60=0
SAMPLE_R1080Q70=0
SAMPLE_R1080Q60=0
SAMPLE_TMP=$(mktemp -d)
for f in $SAMPLES; do
orig=$(du -k "$f" | cut -f1)
SAMPLE_ORIG=$((SAMPLE_ORIG + orig))
base=$(basename "$f")
magick "$f" -quality 70 "$SAMPLE_TMP/q70_${base}.new" && mv "$SAMPLE_TMP/q70_${base}.new" "$SAMPLE_TMP/q70_${base}"
magick "$f" -quality 60 "$SAMPLE_TMP/q60_${base}.new" && mv "$SAMPLE_TMP/q60_${base}.new" "$SAMPLE_TMP/q60_${base}"
magick "$f" -resize '1080x1530>' -quality 70 "$SAMPLE_TMP/r70_${base}.new" && mv "$SAMPLE_TMP/r70_${base}.new" "$SAMPLE_TMP/r70_${base}"
magick "$f" -resize '1080x1530>' -quality 60 "$SAMPLE_TMP/r60_${base}.new" && mv "$SAMPLE_TMP/r60_${base}.new" "$SAMPLE_TMP/r60_${base}"
SAMPLE_Q70=$((SAMPLE_Q70 + $(du -k "$SAMPLE_TMP/q70_${base}" | cut -f1)))
SAMPLE_Q60=$((SAMPLE_Q60 + $(du -k "$SAMPLE_TMP/q60_${base}" | cut -f1)))
SAMPLE_R1080Q70=$((SAMPLE_R1080Q70 + $(du -k "$SAMPLE_TMP/r70_${base}" | cut -f1)))
SAMPLE_R1080Q60=$((SAMPLE_R1080Q60 + $(du -k "$SAMPLE_TMP/r60_${base}" | cut -f1)))
done
# 全体サイズ(JPEG 合計)から予測
EPUB_SIZE=$(du -m "$EPUB_PATH" | cut -f1)
RATIO_Q70=$(awk "BEGIN {printf \"%.2f\", $SAMPLE_Q70 / $SAMPLE_ORIG}")
RATIO_Q60=$(awk "BEGIN {printf \"%.2f\", $SAMPLE_Q60 / $SAMPLE_ORIG}")
RATIO_R70=$(awk "BEGIN {printf \"%.2f\", $SAMPLE_R1080Q70 / $SAMPLE_ORIG}")
RATIO_R60=$(awk "BEGIN {printf \"%.2f\", $SAMPLE_R1080Q60 / $SAMPLE_ORIG}")
echo "軽圧縮(q70) 予測: $(awk "BEGIN {printf \"%.0f\", $EPUB_SIZE * $RATIO_Q70}") MB"
echo "標準圧縮(q60) 予測: $(awk "BEGIN {printf \"%.0f\", $EPUB_SIZE * $RATIO_Q60}") MB"
echo "強圧縮+リサイズ(1080p+q70) 予測: $(awk "BEGIN {printf \"%.0f\", $EPUB_SIZE * $RATIO_R70}") MB"
echo "最大圧縮(1080p+q60) 予測: $(awk "BEGIN {printf \"%.0f\", $EPUB_SIZE * $RATIO_R60}") MB"
rm -rf "$SAMPLE_TMP"
サンプリング結果をもとに AskUserQuestion を呼び出す。
AskUserQuestion 第 1 問: 圧縮レベル
question: |
EPUB の圧縮レベルを選択してください。
現在のサイズ: 203 MB(例)
options:
- value: "light"
label: "軽圧縮"
preview: |
解像度 : 維持(元のまま)
品質 : quality 70
予測 : 145 MB(29% 削減)
削減量 : 58 MB
用途 : 印刷・PC 閲覧・画質優先
- value: "standard"
label: "標準圧縮"
preview: |
解像度 : 維持(元のまま)
品質 : quality 60
予測 : 130 MB(36% 削減)
削減量 : 73 MB
用途 : タブレット閲覧・バランス重視
- value: "strong"
label: "強圧縮 + リサイズ"
preview: |
解像度 : 1080px に縮小(大きい画像のみ)
品質 : quality 70
予測 : 104 MB(49% 削減)
削減量 : 99 MB
用途 : スマートフォン・Kindle・容量節約
- value: "max"
label: "最大圧縮"
preview: |
解像度 : 1080px に縮小(大きい画像のみ)
品質 : quality 60
予測 : 91 MB(55% 削減)
削減量 : 112 MB
用途 : ストレージ最優先・転送用途
AskUserQuestion 第 2 問: 出力方式
question: 出力方式を選択してください。
options:
- value: "new_file"
label: "別ファイルに保存(推奨)"
preview: |
元ファイルを保持したまま
book_compressed.epub を新規作成
元に戻せる(安全)
- value: "overwrite"
label: "上書き"
preview: |
元ファイルを置き換える
元に戻せない
ストレージを節約したい場合に
- value: "backup_overwrite"
label: "バックアップ後に上書き"
preview: |
book.epub.bak を作成してから上書き
中間的な安全策
ストレージに余裕がある場合に推奨
# ---- 圧縮レベルに応じた MAGICK_ARGS を設定 ----
case "$COMPRESS_LEVEL" in
light) MAGICK_ARGS="-quality 70" ;;
standard) MAGICK_ARGS="-quality 60" ;;
strong) MAGICK_ARGS="-resize 1080x1530> -quality 70" ;;
max) MAGICK_ARGS="-resize 1080x1530> -quality 60" ;;
esac
# ---- 全 JPEG を並列圧縮(8 並列)----
find "$WORK_DIR" -iname '*.jpg' -o -iname '*.jpeg' | \
xargs -P 8 -I{} bash -c \
'magick "$1" '"$MAGICK_ARGS"' "$1.new" && mv "$1.new" "$1"' _ {}
# ---- mimetype を先頭・無圧縮格納で再 zip ----
# !! EPUB 規格: mimetype は必ず先頭・無圧縮でなければならない !!
OUTPUT_EPUB="/path/to/book_compressed.epub"
cd "$WORK_DIR"
zip -X0 "$OUTPUT_EPUB" mimetype # 先頭・無圧縮(-X: extra field 除去, -0: 圧縮なし)
zip -r "$OUTPUT_EPUB" . --exclude mimetype # 残りのファイルを追加
echo "完了: $OUTPUT_EPUB"
du -mh "$OUTPUT_EPUB"
preview 文字列はモノスペース的な整形で 5〜8 行に収めること。長すぎると UI で表示が崩れる。
各オプションの preview に必ず含めるべき 5 要素:
実測ベースの予測値を提示することで、ユーザーが期待値を持って選択できる。
# 正しい手順
zip -X0 output.epub mimetype # mimetype を先頭・無圧縮で追加
zip -rq output.epub . --exclude mimetype # 残りのファイルを圧縮で追加
# NG: 通常の zip は mimetype を圧縮してしまう(EPUB リーダーが拒否)
zip -r output.epub .
EPUB 規格(OPS 2.0 / EPUB 3)では mimetype ファイルを ZIP 内の最初のエントリとして非圧縮で格納することが必須。これを破ると Kindle・楽天 kobo・iBooks 等の主要リーダーがファイルを開けなくなる。
既に quality=76 で保存された JPEG を quality=76 で再エンコードしても画質は元通りにならない(劣化は蓄積する)。必ずオリジナルファイルを保持した上で圧縮すること。
magick input.jpg -quality 70 input.jpg のように同じパスを指定すると、処理途中にファイルが壊れることがある。必ず .new サフィックスを経由して mv する。
# 正しいパターン
magick "$f" -quality 70 "$f.new" && mv "$f.new" "$f"
# 危険なパターン(破損リスクあり)
magick "$f" -quality 70 "$f"
JPEG 圧縮とは別に pngquant で処理する。
# PNG は pngquant で圧縮
find "$WORK_DIR" -iname '*.png' | \
xargs -P 4 -I{} pngquant --force --quality=65-80 --output {} {}
> 修飾子で「大きい画像のみ縮小」を保証-resize 1080x1530 は画像を必ず指定サイズに変更する。元画像が既に小さい場合に拡大されてしまう。> を付けることで「それより大きい場合のみ縮小」という挙動になる。
# 正しい: 大きい画像のみ縮小
magick "$f" -resize '1080x1530>' -quality 70 "$f.new"
# NG: 小さい画像も拡大してしまう
magick "$f" -resize '1080x1530' -quality 70 "$f.new"
EPUB_PATH="/path/to/book.epub"
WORK_DIR=$(mktemp -d)
unzip -q "$EPUB_PATH" -d "$WORK_DIR"
ls "$WORK_DIR"
SAMPLE_TMP=$(mktemp -d)
find "$WORK_DIR" -iname '*.jpg' | sort | awk 'NR%10==0' | head -10 > /tmp/samples.txt
while IFS= read -r f; do
base=$(basename "$f")
for cfg in "q70:-quality 70" "q60:-quality 60" \
"r70:-resize 1080x1530> -quality 70" \
"r60:-resize 1080x1530> -quality 60"; do
label="${cfg%%:*}"
args="${cfg#*:}"
magick "$f" $args "$SAMPLE_TMP/${label}_${base}.new" \
&& mv "$SAMPLE_TMP/${label}_${base}.new" "$SAMPLE_TMP/${label}_${base}"
done
done < /tmp/samples.txt
# 各レベルの合計サイズ(KB)
for label in q70 q60 r70 r60; do
total=$(find "$SAMPLE_TMP" -name "${label}_*" -exec du -k {} + | awk '{s+=$1} END{print s}')
echo "$label: ${total} KB(サンプル 10 枚合計)"
done
rm -rf "$SAMPLE_TMP"
# JPEG のみ quality 70 で圧縮
find "$WORK_DIR" -iname '*.jpg' -o -iname '*.jpeg' | \
xargs -P 8 -I{} bash -c \
'magick "$1" -quality 70 "$1.new" && mv "$1.new" "$1"' _ {}
# 1080px に縮小(大きい画像のみ)+ quality 60
find "$WORK_DIR" -iname '*.jpg' -o -iname '*.jpeg' | \
xargs -P 8 -I{} bash -c \
'magick "$1" -resize '"'"'1080x1530>'"'"' -quality 60 "$1.new" && mv "$1.new" "$1"' _ {}
OUTPUT_EPUB="book_compressed.epub"
cd "$WORK_DIR"
# 1. mimetype を先頭・無圧縮(-X0)で追加
zip -X0 "$OUTPUT_EPUB" mimetype
# 2. mimetype 以外をすべて追加
zip -rq "$OUTPUT_EPUB" . --exclude mimetype
# 3. 検証: mimetype が先頭にあることを確認
unzip -l "$OUTPUT_EPUB" | head -5
cd -
find "$WORK_DIR" -iname '*.png' | \
xargs -P 4 -I{} pngquant --force --quality=65-80 --output {} {}
| 用途 | 推奨 quality | 備考 | |------|-------------|------| | スキャン本(資格試験・学術書) | 65〜70 | quality 65 以下で文字判読性が低下し始める | | マンガ・イラスト本 | 70〜75 | 線や色の再現性が重要 | | 写真集・ビジュアル本 | 80 | 劣化が視覚的に目立ちやすい | | Kindle 転送用(最小化優先) | 60 | 文字主体なら実用上問題ない範囲 |
| ツール | 用途 | インストール |
|-------|------|------------|
| unzip / zip | EPUB 展開・再 zip | OS 標準または brew install zip |
| magick(ImageMagick) | JPEG 再エンコード・リサイズ | brew install imagemagick |
| pngquant | PNG 圧縮 | brew install pngquant |
| xargs | 並列実行 | OS 標準 |
macOS の場合、magick は brew install imagemagick でインストールできる。convert コマンドは ImageMagick v7 以降では magick に統合されている。
case "$OUTPUT_MODE" in
new_file)
OUTPUT_EPUB="${EPUB_PATH%.epub}_compressed.epub"
;;
overwrite)
OUTPUT_EPUB="$EPUB_PATH"
;;
backup_overwrite)
cp "$EPUB_PATH" "${EPUB_PATH}.bak"
OUTPUT_EPUB="$EPUB_PATH"
;;
esac
development
Google Cloud guide: Cloud Run, GCP security (IAM/VPC/KMS/Zero Trust), data engineering (BigQuery/Dataflow/pipelines/governance/lakehouse), networking (VPC/LB/CDN), Memorystore, enterprise architecture, compute selection (GCE/GKE/GAE/Run/Functions), GKE, GAE, monitoring (SLO/SLI), BigQuery analytics (SQL/window functions/GA4), BigQuery ops (editions/HA-DR/slots), workflow (Composer/Dataform/Data Fusion), BI (Looker/Looker Studio/BI Engine), ingestion (DTS/Datastream CDC/GA4), real-time (Pub/Sub/Dataflow streaming), ML (BigQuery ML/Vertex AI/GIS). MUST load when google-cloud packages, cloudbuild.yaml, BigQuery/Dataflow/Memorystore/Looker/Dataplex detected. For Docker→practicing-devops. For monitoring→implementing-observability. For OWASP→securing-code. For CQRS→architecting-data. For AWS→developing-aws. For GenAI→designing-genai-patterns. For Firebase (Auth/Firestore/Storage/Functions/Hosting)→developing-firebase.
development
Comprehensive Go development guide covering clean code practices, design patterns (GoF/concurrency/DDD), and internals (type system/memory/reflection). MUST load when go.mod is detected or Go code is being written. Covers naming, error handling, concurrency, testing, project structure, function design, data structures, refactoring strategies, GoF patterns, architectural patterns, type system internals, and performance optimization. For application logging design and structured logging patterns, use implementing-observability. For language-agnostic clean code/SOLID and refactoring, use writing-clean-code. For Clean Architecture/DDD strategic design, use applying-clean-architecture. For algorithm/data-structure complexity analysis, use solving-algorithms.
development
Full-stack JavaScript development covering backend (NestJS/Express), frontend (React), deployment (CI/CD), and quality; also covers JavaScript language fundamentals (types, closures, prototypes, async/await, modules, and metaprogramming). MUST load when package.json contains Express, NestJS, or similar backend frameworks. Covers API design, state management, caching, and testing. Also use when working with JavaScript language-level concerns — type coercion, scoping, this binding, Promise patterns, Proxy/Reflect, or iterator protocols. Also covers V8 engine internals (hidden classes, inline caches, string/number repr), event loop model, JS/Node error model, and Express 5 + Drizzle ORM CRUD APIs.
tools
Firebase platform development guide covering Authentication (email/social/session), Firestore & Realtime Database (modeling/queries/security rules), Cloud Storage, Cloud Functions (triggers/scheduling), Hosting, Analytics (events/BigQuery), FCM push notifications, Remote Config, Test Lab, Performance Monitoring, Dynamic Links, App Distribution, AdMob, and Extensions. MUST load when firebase, @firebase, or firebase-admin packages detected, or firebaseConfig/firebase.json/firestore.rules files present. For GCP infra→developing-google-cloud. For Next.js integration→developing-nextjs. For REST API design→developing-web-apis.