#!/bin/bash # Script to convert WebM files to GIF with alpha transparency # Usage: ./webm_to_gif.sh [directory_path] [fps] [resize_factor] [duration] [background] [compression] # Function to display usage usage() { echo "Usage: $0 [directory_path] [fps] [resize_factor] [duration] [background] [compression]" echo " directory_path: Path to directory containing WebM files (default: current directory)" echo " fps: Target frames per second for GIF (default: 7)" echo " resize_factor: Scale factor for resizing (default: 0.2 = 5x smaller)" echo " duration: Duration in seconds to convert from start (default: 3)" echo " background: Background color for transparency (default: transparent)" echo " - 'transparent' for alpha transparency" echo " - Hex colors: '#000000', '#ffffff', '#ff0000', etc." echo " - Named colors: 'black', 'white', 'red', 'blue', etc." echo " compression: Compression level 1-5 (default: 3)" echo " - 1: Highest quality, largest files (256 colors)" echo " - 2: High quality (128 colors)" echo " - 3: Balanced (64 colors)" echo " - 4: Good compression (32 colors)" echo " - 5: Maximum compression (16 colors)" echo "" echo "Examples:" echo " $0 # All defaults" echo " $0 /path/to/files # Custom dir" echo " $0 /path/to/files 15 # Custom dir and fps" echo " $0 /path/to/files 15 0.5 # Custom dir, fps, and scale" echo " $0 /path/to/files 15 0.5 5 # All params except background/compression" echo " $0 /path/to/files 15 0.5 5 black # Black background" echo " $0 /path/to/files 15 0.5 5 black 5 # Black background, max compression" echo "" echo "This script will:" echo " - Find all .webm files in the specified directory" echo " - Convert to GIF format maintaining alpha transparency" echo " - Use VP9 decoder for optimal alpha preservation" echo " - Save results in a 'gif' subdirectory" exit 1 } # Check if ffmpeg is installed if ! command -v ffmpeg &> /dev/null; then echo "Error: ffmpeg is not installed or not in PATH" echo "Please install ffmpeg to use this script" exit 1 fi # Set default values DIRECTORY="." FPS=7 RESIZE_FACTOR=0.2 DURATION=3 BACKGROUND="transparent" COMPRESSION=3 # Parse arguments if [ $# -eq 0 ]; then DIRECTORY="." elif [ $# -eq 1 ]; then DIRECTORY="$1" elif [ $# -eq 2 ]; then DIRECTORY="$1" FPS="$2" elif [ $# -eq 3 ]; then DIRECTORY="$1" FPS="$2" RESIZE_FACTOR="$3" elif [ $# -eq 4 ]; then DIRECTORY="$1" FPS="$2" RESIZE_FACTOR="$3" DURATION="$4" elif [ $# -eq 5 ]; then DIRECTORY="$1" FPS="$2" RESIZE_FACTOR="$3" DURATION="$4" BACKGROUND="$5" elif [ $# -eq 6 ]; then DIRECTORY="$1" FPS="$2" RESIZE_FACTOR="$3" DURATION="$4" BACKGROUND="$5" COMPRESSION="$6" else echo "Error: Too many arguments" usage fi # Validate fps parameter if ! [[ "$FPS" =~ ^[0-9]+(\.[0-9]+)?$ ]] || (( $(echo "$FPS <= 0" | bc -l) )); then echo "Error: fps must be a positive number" exit 1 fi # Validate resize factor parameter if ! [[ "$RESIZE_FACTOR" =~ ^[0-9]+(\.[0-9]+)?$ ]] || (( $(echo "$RESIZE_FACTOR <= 0" | bc -l) )); then echo "Error: resize_factor must be a positive number" exit 1 fi # Validate duration parameter if ! [[ "$DURATION" =~ ^[0-9]+(\.[0-9]+)?$ ]] || (( $(echo "$DURATION <= 0" | bc -l) )); then echo "Error: duration must be a positive number" exit 1 fi # Validate background parameter if [ "$BACKGROUND" != "transparent" ]; then # Check if it's a valid hex color or named color if ! [[ "$BACKGROUND" =~ ^#[0-9a-fA-F]{6}$ ]] && ! [[ "$BACKGROUND" =~ ^[a-zA-Z]+$ ]]; then echo "Error: background must be 'transparent', a hex color (#000000), or a named color (black, white, etc.)" exit 1 fi fi # Validate compression parameter if ! [[ "$COMPRESSION" =~ ^[1-5]$ ]]; then echo "Error: compression must be between 1-5" exit 1 fi # Set compression values based on level case $COMPRESSION in 1) MAX_COLORS=256; DITHER_SCALE=2 ;; # Highest quality 2) MAX_COLORS=128; DITHER_SCALE=3 ;; # High quality 3) MAX_COLORS=64; DITHER_SCALE=4 ;; # Balanced (default) 4) MAX_COLORS=32; DITHER_SCALE=5 ;; # Good compression 5) MAX_COLORS=16; DITHER_SCALE=5 ;; # Maximum compression esac # Check if directory exists if [ ! -d "$DIRECTORY" ]; then echo "Error: Directory '$DIRECTORY' does not exist" exit 1 fi # Convert to absolute path DIRECTORY=$(realpath "$DIRECTORY") echo "Processing WebM files in: $DIRECTORY" echo "Target FPS: $FPS" echo "Resize factor: ${RESIZE_FACTOR}x ($(echo "scale=1; 1/$RESIZE_FACTOR" | bc)x smaller)" echo "Duration: first $DURATION seconds" echo "Background: $BACKGROUND" echo "Compression: Level $COMPRESSION ($MAX_COLORS colors, dither scale $DITHER_SCALE)" # Create gif output directory GIF_DIR="$DIRECTORY/gif" if [ ! -d "$GIF_DIR" ]; then mkdir -p "$GIF_DIR" echo "Created output directory: $GIF_DIR" else echo "Using existing output directory: $GIF_DIR" fi # Find all WebM files in the directory WEBM_FILES=($(find "$DIRECTORY" -maxdepth 1 -name "*.webm" -type f)) # Check if any WebM files were found if [ ${#WEBM_FILES[@]} -eq 0 ]; then echo "No WebM files found in '$DIRECTORY'" exit 0 fi echo "Found ${#WEBM_FILES[@]} WebM file(s)" echo "Note: Existing GIF files will be overwritten to ensure proper transparency" echo "" # Counter for processed files PROCESSED=0 FAILED=0 OVERWRITTEN=0 NEW_FILES=0 # Process each WebM file for webm_file in "${WEBM_FILES[@]}"; do # Get the base filename without path and extension base_name=$(basename "$webm_file" .webm) # Output GIF file path gif_output="$GIF_DIR/${base_name}.gif" echo "Processing: $(basename "$webm_file")" # Check if output file already exists FILE_EXISTS=false if [ -f "$gif_output" ]; then echo " → Overwriting existing file: ${base_name}.gif" FILE_EXISTS=true fi # Detect codec type (VP8 or VP9) to use correct decoder CODEC_INFO=$(ffprobe -v quiet -select_streams v:0 -show_entries stream=codec_name -of csv=p=0 "$webm_file" 2>/dev/null) # Set appropriate decoder based on codec (VP9 preferred for alpha) if [ "$CODEC_INFO" = "vp9" ]; then DECODER="libvpx-vp9" echo " → Using VP9 decoder (optimal for alpha preservation)" else DECODER="libvpx" # Default to VP8 decoder echo " → Using VP8 decoder" fi # Create temporary files for palette generation TEMP_DIR=$(mktemp -d) PALETTE_FILE="$TEMP_DIR/palette.png" echo " → Generating optimized palette with transparency support..." # Set up filter chains based on background setting if [ "$BACKGROUND" = "transparent" ]; then PALETTE_FILTER="fps=$FPS,scale=iw*$RESIZE_FACTOR:ih*$RESIZE_FACTOR:flags=lanczos,palettegen=transparency_color=ffffff:reserve_transparent=on:max_colors=$MAX_COLORS" CONVERT_FILTER="fps=$FPS,scale=iw*$RESIZE_FACTOR:ih*$RESIZE_FACTOR:flags=lanczos[x];[x][1:v]paletteuse=alpha_threshold=128:dither=bayer:bayer_scale=$DITHER_SCALE" echo " → Using transparent background (alpha channel preserved)" else PALETTE_FILTER="fps=$FPS,scale=iw*$RESIZE_FACTOR:ih*$RESIZE_FACTOR:flags=lanczos,split[a][b];[a]geq=r=0:g=0:b=0:a=255,drawbox=color=$BACKGROUND@1.0:replace=1:t=fill[bg];[bg][b]overlay=format=auto,palettegen=max_colors=$MAX_COLORS" CONVERT_FILTER="fps=$FPS,scale=iw*$RESIZE_FACTOR:ih*$RESIZE_FACTOR:flags=lanczos,split[a][b];[a]geq=r=0:g=0:b=0:a=255,drawbox=color=$BACKGROUND@1.0:replace=1:t=fill[bg];[bg][b]overlay=format=auto[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=$DITHER_SCALE" echo " → Using background color: $BACKGROUND (fills transparent areas only)" fi # Generate palette with transparency support if ffmpeg -c:v "$DECODER" \ -i "$webm_file" \ -t "$DURATION" \ -vf "$PALETTE_FILTER" \ -y \ "$PALETTE_FILE" \ -v quiet 2>/dev/null; then echo " → Converting to GIF..." # Convert to GIF using the generated palette if ffmpeg -c:v "$DECODER" \ -i "$webm_file" \ -i "$PALETTE_FILE" \ -t "$DURATION" \ -lavfi "$CONVERT_FILTER" \ -y \ "$gif_output" \ -v quiet 2>/dev/null; then if [ "$FILE_EXISTS" = true ]; then echo " ✓ Successfully overwritten: ${base_name}.gif" ((OVERWRITTEN++)) else echo " ✓ Successfully created: ${base_name}.gif" ((NEW_FILES++)) fi ((PROCESSED++)) else echo " ✗ Failed to convert to GIF: $(basename "$webm_file")" ((FAILED++)) fi else echo " ✗ Failed to generate palette for: $(basename "$webm_file")" ((FAILED++)) fi # Clean up temp directory rm -rf "$TEMP_DIR" echo "" done # Summary echo "=== Processing Complete ===" echo "Total files processed: $PROCESSED" if [ $NEW_FILES -gt 0 ]; then echo "New files created: $NEW_FILES" fi if [ $OVERWRITTEN -gt 0 ]; then echo "Existing files overwritten: $OVERWRITTEN" fi if [ $FAILED -gt 0 ]; then echo "Failed to process: $FAILED files" fi echo "Output directory: $GIF_DIR" echo "Settings used - FPS: $FPS, Scale: ${RESIZE_FACTOR}x, Duration: ${DURATION}s, Background: $BACKGROUND, Compression: $COMPRESSION" echo "" # List generated files if [ $PROCESSED -gt 0 ]; then echo "Generated GIF files:" ls -la "$GIF_DIR"/*.gif 2>/dev/null | while read -r line; do echo " $line" done fi