Last active
August 19, 2025 05:24
-
-
Save kkotaro0111/d991041ceafef7110099260f38f364e3 to your computer and use it in GitHub Desktop.
cwebpで指定したフォルダ内の画像を再圧縮する( 非可逆 / ほぼロスレス / ロスレス モードはオプションで切り替え)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # エラーが発生した場合、およびパイプラインでエラーが発生した場合にスクリプトを終了する | |
| set -e | |
| set -o pipefail | |
| # --- ヘルプメッセージ --- | |
| usage() { | |
| cat <<EOF | |
| Usage: $(basename "$0") [OPTIONS] <directory> <quality> | |
| Converts all JPG/PNG files in a directory to WebP format. | |
| Original files are moved to a subdirectory named '_original'. | |
| Arguments: | |
| <directory> The target directory containing JPG/PNG files. | |
| <quality> The WebP quality level (0-100) or compression level (0-9) for lossless, | |
| or near-lossless value (0-99) for near-lossless mode. | |
| Options: | |
| -n, --dry-run Show what would be done, without actually modifying any files. | |
| -l, --lossless Use lossless compression (quality = compression level 0-9). | |
| -nl, --near-lossless Use near-lossless mode (quality = preprocessing 0-99). | |
| -h, --help Display this help message and exit. | |
| Modes: | |
| Default: Lossy compression with quality 0-100 | |
| --lossless: Lossless compression with level 0-9 (0=fast, 9=best) | |
| --near-lossless: Near-lossless with preprocessing 0-99 (0=best quality) | |
| EOF | |
| exit 1 | |
| } | |
| # --- 初期値 --- | |
| DRY_RUN=0 | |
| LOSSLESS=0 | |
| NEAR_LOSSLESS=0 | |
| # --- オプション解析 --- | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| -n|--dry-run) | |
| DRY_RUN=1 | |
| shift | |
| ;; | |
| -l|--lossless) | |
| LOSSLESS=1 | |
| shift | |
| ;; | |
| -nl|--near-lossless) | |
| NEAR_LOSSLESS=1 | |
| shift | |
| ;; | |
| -h|--help) | |
| usage | |
| ;; | |
| --) | |
| shift | |
| break | |
| ;; | |
| -*) | |
| echo "Unknown option: $1" | |
| usage | |
| ;; | |
| *) | |
| break | |
| ;; | |
| esac | |
| done | |
| # --- 引数のチェック --- | |
| if [ "$#" -ne 2 ]; then | |
| echo "Error: Missing directory or quality argument." | |
| usage | |
| fi | |
| TARGET_DIR=$1 | |
| QUALITY=$2 | |
| CONVERT_DIR="$(dirname "$TARGET_DIR")/$(basename "$TARGET_DIR")_compressed" | |
| # --- 依存関係のチェック --- | |
| for cmd in cwebp find mv mkdir basename; do | |
| if ! command -v "$cmd" &> /dev/null; then | |
| echo "Error: Required command '$cmd' is not available in your PATH." | |
| if [ "$cmd" = "cwebp" ]; then | |
| echo "Please install WebP tools:" | |
| echo " Ubuntu/Debian: sudo apt install webp" | |
| echo " CentOS/RHEL: sudo yum install libwebp-tools" | |
| echo " macOS: brew install webp" | |
| echo " Arch Linux: sudo pacman -S libwebp" | |
| fi | |
| exit 1 | |
| fi | |
| done | |
| # --- 入力値の検証 --- | |
| if [ ! -d "$TARGET_DIR" ]; then | |
| echo "Error: Directory '$TARGET_DIR' not found." | |
| exit 1 | |
| fi | |
| # モードの排他チェック | |
| mode_count=0 | |
| if [ "$LOSSLESS" -eq 1 ]; then mode_count=$((mode_count + 1)); fi | |
| if [ "$NEAR_LOSSLESS" -eq 1 ]; then mode_count=$((mode_count + 1)); fi | |
| if [ "$mode_count" -gt 1 ]; then | |
| echo "Error: Cannot use multiple compression modes simultaneously." | |
| exit 1 | |
| fi | |
| # 品質値の検証 | |
| if [ "$LOSSLESS" -eq 1 ]; then | |
| if ! [[ "$QUALITY" =~ ^[0-9]+$ ]] || [ "$QUALITY" -lt 0 ] || [ "$QUALITY" -gt 9 ]; then | |
| echo "Error: Lossless compression level must be between 0 and 9." | |
| exit 1 | |
| fi | |
| elif [ "$NEAR_LOSSLESS" -eq 1 ]; then | |
| if ! [[ "$QUALITY" =~ ^[0-9]+$ ]] || [ "$QUALITY" -lt 0 ] || [ "$QUALITY" -gt 99 ]; then | |
| echo "Error: Near-lossless value must be between 0 and 99." | |
| exit 1 | |
| fi | |
| else | |
| if ! [[ "$QUALITY" =~ ^[0-9]+$ ]] || [ "$QUALITY" -lt 0 ] || [ "$QUALITY" -gt 100 ]; then | |
| echo "Error: Quality must be a number between 0 and 100." | |
| exit 1 | |
| fi | |
| fi | |
| # --- ドライランの表示 --- | |
| if [ "$DRY_RUN" -eq 1 ]; then | |
| echo "*** This is a DRY RUN. No files will be changed. ***" | |
| echo "----------------------------------------------------" | |
| fi | |
| echo "Target directory: $TARGET_DIR" | |
| if [ "$LOSSLESS" -eq 1 ]; then | |
| echo "Compression mode: Lossless (level: $QUALITY)" | |
| elif [ "$NEAR_LOSSLESS" -eq 1 ]; then | |
| echo "Compression mode: Near-lossless (value: $QUALITY)" | |
| else | |
| echo "Compression mode: Lossy (quality: $QUALITY)" | |
| fi | |
| echo "Convert directory: $CONVERT_DIR" | |
| echo "" | |
| # --- 処理の実行 --- | |
| if [ "$DRY_RUN" -eq 0 ] ; then | |
| mkdir -p "$CONVERT_DIR" | |
| fi | |
| processed_files=0 | |
| # JPG/JPEG/PNG ファイルを検索 | |
| mapfile -t -d '' files < <(find "$TARGET_DIR" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) -print0) | |
| for file in "${files[@]}"; do | |
| filename=$(basename "$file") | |
| # 拡張子を取得して webp に変更 | |
| base_name="${filename%.*}" | |
| relative_path="${file#$TARGET_DIR/}" | |
| relative_dir=$(dirname "$relative_path") | |
| # 作業ファイルのパス | |
| convert_file="${CONVERT_DIR}/${relative_path}" | |
| working_dir=$(dirname "$convert_file") | |
| # WebP ファイルのパス | |
| webp_file="${working_dir}/${base_name}.webp" | |
| if [ "$DRY_RUN" -eq 1 ]; then | |
| if [ "$LOSSLESS" -eq 1 ]; then | |
| echo "[DRY RUN] Would convert '$file' to '$webp_file' (lossless level: $QUALITY)" | |
| elif [ "$NEAR_LOSSLESS" -eq 1 ]; then | |
| echo "[DRY RUN] Would convert '$file' to '$webp_file' (near-lossless: $QUALITY)" | |
| else | |
| echo "[DRY RUN] Would convert '$file' to '$webp_file' (quality: $QUALITY)" | |
| fi | |
| echo "[DRY RUN] Would move original to '$convert_file'" | |
| else | |
| echo "Processing: $relative_path" | |
| # WebP に変換 | |
| if [ "$LOSSLESS" -eq 1 ]; then | |
| convert_cmd="cwebp -lossless -z $QUALITY" | |
| mode_desc="lossless level $QUALITY" | |
| elif [ "$NEAR_LOSSLESS" -eq 1 ]; then | |
| convert_cmd="cwebp -near_lossless $QUALITY -z 9" | |
| mode_desc="near-lossless $QUALITY" | |
| else | |
| convert_cmd="cwebp -q $QUALITY" | |
| mode_desc="quality $QUALITY" | |
| fi | |
| # 作業ディレクトリを作成 | |
| if ! mkdir -p "$working_dir"; then | |
| echo "Error: Failed to create working directory '$working_dir'" | |
| continue | |
| fi | |
| if $convert_cmd "$file" -o "$webp_file" &>/dev/null; then | |
| echo "✓ Successfully converted: $relative_path → ${base_name}.webp ($mode_desc)" | |
| else | |
| echo "Error: Failed to convert '$file' to '$webp_file'" | |
| continue | |
| fi | |
| fi | |
| processed_files=$((processed_files + 1)) | |
| done | |
| echo "----------------------------------------------------" | |
| if [ "$processed_files" -eq 0 ]; then | |
| echo "No JPG/PNG files found to process." | |
| else | |
| if [ "$DRY_RUN" -eq 1 ]; then | |
| echo "Dry run complete. Found $processed_files image file(s)." | |
| else | |
| echo "Successfully converted $processed_files image file(s) to WebP format." | |
| fi | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment