Created
February 1, 2025 10:13
-
-
Save GDXbsv/488e1fc891632cab2e5aa62e645b8689 to your computer and use it in GitHub Desktop.
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
| #!/bin/bash | |
| # # For flat structure (all files in one directory): | |
| # ./convert_to_jxl.sh /path/to/source/folder /path/to/destination flat | |
| # # For maintaining directory structure: | |
| # ./convert_to_jxl.sh /path/to/source/folder /path/to/destination structured | |
| # Check if correct number of arguments provided | |
| if [ "$#" -ne 3 ]; then | |
| echo "Usage: $0 <source_directory> <destination_directory> <flat|structured>" | |
| exit 1 | |
| fi | |
| # Check if parallel is installed | |
| if ! command -v parallel &> /dev/null; then | |
| echo "GNU parallel is not installed. Please install it first:" | |
| echo "sudo apt-get install parallel # For Debian/Ubuntu" | |
| echo "sudo yum install parallel # For CentOS/RHEL" | |
| exit 1 | |
| fi | |
| SOURCE_DIR="$1" | |
| DEST_DIR="$2" | |
| MODE="$3" | |
| # Create destination directory if it doesn't exist | |
| mkdir -p "$DEST_DIR" | |
| # Function to convert bytes to MB | |
| bytes_to_mb() { | |
| local bytes=$1 | |
| # Force use of dot as decimal separator and ensure proper number formatting | |
| LC_NUMERIC=C awk -v bytes="$bytes" 'BEGIN {printf "%.2f MB", bytes/1024/1024}' | |
| } | |
| get_extension() { | |
| local filename=$1 | |
| local ext=$(echo "$filename" | awk -F. '{ print tolower($NF) }') | |
| echo "$ext" | |
| } | |
| # Function to process files | |
| process_file() { | |
| local src_file="$1" | |
| # Get basename without any extension | |
| local base_name=$(basename "$src_file" | sed 's/\.[^.]*$//') | |
| local rel_path=$(dirname "${src_file#$SOURCE_DIR/}") | |
| # Create a temporary file for conversion | |
| local temp_file=$(mktemp --suffix=.jxl) | |
| local file_extension=$(get_extension "$src_file") | |
| # Convert to temporary file first | |
| echo "Converting: $src_file | ext: $file_extension" | |
| case "$file_extension" in | |
| jpg|jpeg|png|gif) | |
| cjxl --lossless_jpeg=0 -q 80 "$src_file" "$temp_file" | |
| ;; | |
| heic|heif) | |
| vips copy "$src_file" "$temp_file[Q=80]" | |
| ;; | |
| *) | |
| echo "The file extension is not one of the specified types." | |
| exit 0 | |
| ;; | |
| esac | |
| # Compare file sizes | |
| local original_size=$(stat -f%z "$src_file" 2>/dev/null || stat -c%s "$src_file") | |
| local converted_size=$(stat -f%z "$temp_file" 2>/dev/null || stat -c%s "$temp_file") | |
| # Calculate size differences | |
| local original_mb=$(bytes_to_mb $original_size) | |
| local converted_mb=$(bytes_to_mb $converted_size) | |
| local saved_mb=$(bytes_to_mb $((original_size-converted_size))) | |
| if [ "$converted_size" -lt "$original_size" ]; then | |
| # Only proceed if the converted file is smaller | |
| if [ "$MODE" = "flat" ]; then | |
| # For flat structure, put all files in destination directory | |
| dest_file="$DEST_DIR/${base_name}.jxl" | |
| # If file with same name exists, append a number | |
| if [ -f "$dest_file" ]; then | |
| counter=1 | |
| while [ -f "$DEST_DIR/${base_name}_${counter}.jxl" ]; do | |
| ((counter++)) | |
| done | |
| dest_file="$DEST_DIR/${base_name}_${counter}.jxl" | |
| fi | |
| else | |
| # For structured output, maintain directory structure | |
| dest_dir="$DEST_DIR/$rel_path" | |
| mkdir -p "$dest_dir" | |
| dest_file="$dest_dir/${base_name}.jxl" | |
| fi | |
| # Move the temporary file to final destination | |
| mv "$temp_file" "$dest_file" | |
| echo "✓ Saved: $dest_file (Original: $original_mb, Converted: $converted_mb, Saved: $saved_mb)" | |
| else | |
| # Remove temporary file if it's not smaller | |
| rm "$temp_file" | |
| echo "✗ Skipped: $src_file (Original: $original_mb, Converted: $converted_mb, No size reduction)" | |
| fi | |
| } | |
| export -f process_file | |
| export -f bytes_to_mb | |
| export -f get_extension | |
| export SOURCE_DIR DEST_DIR MODE | |
| # Find all jpg files and process them in parallel (3 jobs at a time) | |
| find "$SOURCE_DIR" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" -o -iname "*.JPG" -o -iname "*.JPEG" -o -iname "*.PNG" -o -iname "*.GIF" -o -iname "*.heic" -o -iname "*.heif" -o -iname "*.HEIC" -o -iname "*.HEIF" \) -print0 | \ | |
| parallel -0 -j 2 process_file | |
| echo "Conversion complete!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment