Script to Convert Images to Webp

Script to Convert Images to Webp

I needed a script to convert a director of image files to .webp format where image quality is defined by the source file name.

In addition, the script,

  • Add the image dimensions

  • Strips out all meta data (e.g. geo-location except for ICC Profile for colour accuracy)

  • Embeds copyright meta data.

  • Etc… that’s in the file description

This is hardly perfect but it does the job.

#!/bin/bash ######################################################################### # convert-to-webp.sh — Version 1.7.1 # # Description: # Converts image files in the current directory to .webp format using cwebp. # - Skips .webp files and non-image files # - Processes JPEG, PNG, GIF only # - Uses -QXX- tag to determine quality if present, otherwise default or CLI arg # - Cleans up filenames, replaces spaces, trims long names # - Adds dimensions from `sips` # - Uses exiftool to embed metadata (if installed) # # Requirements: # - macOS 10.14.6 / Bash 3.2 # - Install via Homebrew: `brew install webp coreutils` # - Install ExifTool manually from https://exiftool.org/ # ######################################################################### # Constants DEFAULT_QUALITY=75 LOGFILE="./webp_conversion.log" MAX_FILENAME_LENGTH=100 OUTPUT_DIR="webp" # Metadata AUTHOR="John Carter" COPYRIGHT="© 2026 John Carter" WEBSTATEMENT="https://thewatchout.com/about/" SITEURL="https://www.acme.com" # Parameters QUALITY_ARG=$1 DEBUG=false [ "$2" = "debug" ] && DEBUG=true # Check for required tools for tool in cwebp sips file; do if ! command -v "$tool" >/dev/null 2>&1; then echo "❌ Required tool '$tool' is not installed. Exiting." exit 1 fi done # Check for optional tool: exiftool EXIFTOOL_AVAILABLE=false if command -v exiftool >/dev/null 2>&1; then EXIFTOOL_AVAILABLE=true else echo "⚠️ exiftool not found — metadata will not be added" fi # Logging functions log_info() { echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOGFILE"; } log_debug() { [ "$DEBUG" = true ] && echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOGFILE"; } # Prepare environment mkdir -p "$OUTPUT_DIR" touch "$LOGFILE" log_info "🟢 Starting WebP conversion (param quality=$QUALITY_ARG, debug=$DEBUG)" # Counter COUNT=0 # File loop for file in *; do [[ ! -f "$file" ]] && continue lowercase_file=$(echo "$file" | tr '[:upper:]' '[:lower:]') [[ "$lowercase_file" == *.webp ]] && continue mimetype=$(file --mime-type -b "$file") case "$mimetype" in image/jpeg|image/png|image/gif) ;; *) log_debug "Skipping non-image: $file"; continue ;; esac original_name="$file" base_name="${file%.*}" extension="${file##*.}" safe_name="${base_name// /-}" # Remove existing dimension and quality tags safe_name=$(echo "$safe_name" | sed -E 's/-Q[0-9]{2}-//g') safe_name=$(echo "$safe_name" | sed -E 's/-[0-9]+x[0-9]+$//') # Clean problematic characters if echo "$safe_name" | grep -q '[&><#%?"'"'"']'; then suggested_name=$(echo "$safe_name" | sed -E 's/[&><#%?\"'"'"']/_/g') echo "⚠️ Problematic characters in: \"$file\"" echo " Suggested filename: \"$suggested_name\"" read -p " Use suggested name? (y/n): " choice if [ "$choice" = "y" ]; then safe_name="$suggested_name" else read -p " Enter new safe name: " user_input safe_name="$user_input" fi fi # Determine quality if [ -z "$QUALITY_ARG" ]; then if echo "$base_name" | grep -q -- '-Q[0-9][0-9]-'; then QUALITY=$(echo "$base_name" | sed -n 's/.*-Q\([0-9][0-9]\)-.*/\1/p') log_debug "Extracted quality from filename: $QUALITY" else QUALITY=$DEFAULT_QUALITY log_debug "No quality tag found — using default: $QUALITY" fi else QUALITY=$QUALITY_ARG fi QUALITY_TAG="-Q${QUALITY}-" safe_name="${safe_name}${QUALITY_TAG}" # Get image dimensions DIMENSIONS=$(sips -g pixelWidth -g pixelHeight "$file" 2>/dev/null | awk '/pixelWidth/ {w=$2} /pixelHeight/ {h=$2} END {print w "x" h}') [ -z "$DIMENSIONS" ] && DIMENSIONS="unknown" safe_name="${safe_name}${DIMENSIONS}" # Replace any accidental double hyphens safe_name=$(echo "$safe_name" | sed -E 's/--+/-/g') # Trim long names if [ "${#safe_name}" -gt "$MAX_FILENAME_LENGTH" ]; then safe_name=$(echo "$safe_name" | cut -c1-"$MAX_FILENAME_LENGTH") log_info "Filename too long, shortened to $safe_name" fi # Build output name target="${safe_name}.webp" version=1 while [ -f "$OUTPUT_DIR/$target" ]; do target="${safe_name}.v${version}.webp" version=$((version + 1)) done # Convert echo "🛠️ Converting: $file → $target" # Preserve ONLY the ICC profile (color accuracy) while stripping all other metadata for privacy if cwebp -q "$QUALITY" -metadata icc "$original_name" -o "$OUTPUT_DIR/$target" >> "$LOGFILE" 2>&1; then log_info "✅ Success: $target" ((COUNT++)) if [ "$EXIFTOOL_AVAILABLE" = true ]; then exiftool -overwrite_original -quiet \ -Artist="$AUTHOR" \ -Copyright="$COPYRIGHT" \ -WebStatement="$WEBSTATEMENT" \ -XMP-dc:Source="$SITEURL" \ -GPS*="" \ "$OUTPUT_DIR/$target" log_info "✅ Metadata added to $target" echo " metadata embedded" fi else log_info "❌ Conversion failed: $file" fi done log_info "✅ Conversion complete" echo "✅ $COUNT image(s) converted. See log: $LOGFILE"