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"