Last active
March 6, 2025 20:54
-
-
Save claunia/5b7b77ee5c49cdb91d596cf29b579152 to your computer and use it in GitHub Desktop.
Losslessly convert all JPGs in current folder to JPEG-XL preserving EXIF and mtime. (Bash script)
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 | |
# Check files with `jpg` extension | |
if [[ -n $(shopt -s nullglob; echo *.jpg) ]]; then | |
# Create a directory to work in | |
mkdir -p wrk | |
# Move all files with `jpg` extension, as well as XMP sidecars to the working directory | |
mv ./*.jpg wrk | |
if [[ -n $(shopt -s nullglob; echo *.jpg.xmp) ]]; then | |
mv ./*.jpg.xmp wrk | |
fi | |
cd wrk || exit | |
# Convert all JPEG files to JPEG-XL format losslessly | |
parallel 'cjxl --num_threads 1 -j 1 -e 10 {} {.}.jxl' ::: *.jpg | |
# For each JPEG-XL file, copy metadata from the original JPEG file, and then delete the original JPEG file | |
if [[ -n $(shopt -s nullglob; echo *.jxl) ]]; then | |
parallel 'exiftool -m -overwrite_original -api compress=1 -tagsfromfile {.}.jpg {}; touch -r {.}.jpg {}; rm {.}.jpg' ::: *.jxl | |
fi | |
# If there are still non converted JPEG files | |
if [[ -n $(shopt -s nullglob; echo *.jpg) ]]; then | |
mkdir -p out | |
# Transform then, without changes, this usually remakes the Huffman tables, that is the most common source of errors when converting to JPEG-XL (commonly found in WhatsApp images) | |
parallel 'echo {}; jpegtran -copy all -optimize -perfect -strict -outfile out/{} {}' ::: *.jpg | |
# For each JPEG-XL file, copy metadata from the original JPEG file, and then delete the original JPEG file | |
if [[ -n $(shopt -s nullglob; echo out/*.jpg) ]]; then | |
parallel 'cjxl --num_threads 1 -j 1 -e 10 out/{} {.}.jxl; exiftool -m -overwrite_original -api compress=1 -tagsfromfile {} {.}.jxl; touch -r {} {.}.jxl; rm {} out/{}' ::: *.jpg | |
fi | |
rmdir out | |
fi | |
# Rename XMP sidecars to match the new JPEG-XL files, if any | |
if [[ -n $(shopt -s nullglob; echo *.jpg.xmp) ]]; then | |
for i in *.jpg.xmp | |
do k="${i%.jpg.xmp}.jxl.xmp" | |
if [[ -f "${i%.jpg.xmp}.jxl" ]]; then | |
mv "$i" "$k" | |
fi | |
done | |
fi | |
# Move all files back to the parent directory | |
find . -empty -delete | |
mv ./* .. | |
cd .. | |
rmdir wrk | |
fi | |
# Check files with `JPG` extension | |
if [[ -n $(shopt -s nullglob; echo *.JPG) ]]; then | |
# Create a directory to work in | |
mkdir -p wrk | |
# Move all files with `JPG` extension, as well as XMP sidecars to the working directory | |
mv ./*.JPG wrk | |
if [[ -n $(shopt -s nullglob; echo *.JPG.xmp) ]]; then | |
mv ./*.JPG.xmp wrk | |
fi | |
if [[ -n $(shopt -s nullglob; echo *.JPG.XMP) ]]; then | |
mv ./*.JPG.XMP wrk | |
fi | |
cd wrk || exit | |
# Convert all JPEG files to JPEG-XL format losslessly | |
parallel 'cjxl --num_threads 1 -j 1 -e 10 {} {.}.JXL' ::: *.JPG | |
# For each JPEG-XL file, copy metadata from the original JPEG file, and then delete the original JPEG file | |
if [[ -n $(shopt -s nullglob; echo *.JXL) ]]; then | |
parallel 'exiftool -m -overwrite_original -api compress=1 -tagsfromfile {.}.JPG {}; touch -r {.}.JPG {}; rm {.}.JPG' ::: *.JXL | |
fi | |
# If there are still non converted JPEG files | |
if [[ -n $(shopt -s nullglob; echo *.JPG) ]]; then | |
mkdir -p out | |
# Transform then, without changes, this usually remakes the Huffman tables, that is the most common source of errors when converting to JPEG-XL (commonly found in WhatsApp images) | |
parallel 'echo {}; jpegtran -copy all -optimize -perfect -strict -outfile out/{} {}' ::: *.JPG | |
# For each JPEG-XL file, copy metadata from the original JPEG file, and then delete the original JPEG file | |
if [[ -n $(shopt -s nullglob; echo out/*.JPG) ]]; then | |
parallel 'cjxl --num_threads 1 -j 1 -e 10 out/{} {.}.JXL; exiftool -m -overwrite_original -api compress=1 -tagsfromfile {} {.}.JXL; touch -r {} {.}.JXL; rm {} out/{}' ::: *.JPG | |
fi | |
rmdir out | |
fi | |
# Rename XMP sidecars to match the new JPEG-XL files, if any | |
if [[ -n $(shopt -s nullglob; echo *.JPG.xmp) ]]; then | |
for i in *.JPG.xmp | |
do k="${i%.JPG.xmp}.JXL.xmp" | |
if [[ -f "${i%.JPG.xmp}.JXL" ]]; then | |
mv "$i" "$k" | |
fi | |
done | |
fi | |
if [[ -n $(shopt -s nullglob; echo *.JPG.XMP) ]]; then | |
for i in *.JPG.XMP | |
do k="${i%.JPG.XMP}.JXL.XMP" | |
if [[ -f "${i%.JPG.XMP}.JXL" ]]; then | |
mv "$i" "$k" | |
fi | |
done | |
fi | |
# Move all files back to the parent directory | |
find . -empty -delete | |
mv ./* .. | |
cd .. | |
rmdir wrk | |
fi | |
# Check files with `jpeg` extension | |
if [[ -n $(shopt -s nullglob; echo *.jpeg) ]]; then | |
# Create a directory to work in | |
mkdir -p wrk | |
# Move all files with `jpeg` extension, as well as XMP sidecars to the working directory | |
mv ./*.jpeg wrk | |
if [[ -n $(shopt -s nullglob; echo *.jpeg.xmp) ]]; then | |
mv ./*.jpeg.xmp wrk | |
fi | |
cd wrk || exit | |
# Convert all JPEG files to JPEG-XL format losslessly | |
parallel 'cjxl --num_threads 1 -j 1 -e 10 {} {.}.jxl' ::: *.jpeg | |
# For each JPEG-XL file, copy metadata from the original JPEG file, and then delete the original JPEG file | |
if [[ -n $(shopt -s nullglob; echo *.jxl) ]]; then | |
parallel 'exiftool -m -overwrite_original -api compress=1 -tagsfromfile {.}.jpeg {}; touch -r {.}.jpeg {}; rm {.}.jpeg' ::: *.jxl | |
fi | |
# If there are still non converted JPEG files | |
if [[ -n $(shopt -s nullglob; echo *.jpeg) ]]; then | |
mkdir -p out | |
# Transform then, without changes, this usually remakes the Huffman tables, that is the most common source of errors when converting to JPEG-XL (commonly found in WhatsApp images) | |
parallel 'echo {}; jpegtran -copy all -optimize -perfect -strict -outfile out/{} {}' ::: *.jpeg | |
# For each JPEG-XL file, copy metadata from the original JPEG file, and then delete the original JPEG file | |
if [[ -n $(shopt -s nullglob; echo out/*.jpeg) ]]; then | |
parallel 'cjxl --num_threads 1 -j 1 -e 10 out/{} {.}.jxl; exiftool -m -overwrite_original -api compress=1 -tagsfromfile {} {.}.jxl; touch -r {} {.}.jxl; rm {} out/{}' ::: *.jpeg | |
fi | |
rmdir out | |
fi | |
# Rename XMP sidecars to match the new JPEG-XL files, if any | |
if [[ -n $(shopt -s nullglob; echo *.jpeg.xmp) ]]; then | |
for i in *.jpeg.xmp | |
do k="${i%.jpeg.xmp}.jxl.xmp" | |
if [[ -f "${i%.jpeg.xmp}.jxl" ]]; then | |
mv "$i" "$k" | |
fi | |
done | |
fi | |
# Move all files back to the parent directory | |
find . -empty -delete | |
mv ./* .. | |
cd .. | |
rmdir wrk | |
fi | |
# Check files with `JPEG` extension | |
if [[ -n $(shopt -s nullglob; echo *.JPEG) ]]; then | |
# Create a directory to work in | |
mkdir -p wrk | |
# Move all files with `JPEG` extension, as well as XMP sidecars to the working directory | |
mv ./*.JPEG wrk | |
if [[ -n $(shopt -s nullglob; echo *.JPEG.xmp) ]]; then | |
mv ./*.JPEG.xmp wrk | |
fi | |
if [[ -n $(shopt -s nullglob; echo *.JPEG.XMP) ]]; then | |
mv ./*.JPEG.XMP wrk | |
fi | |
cd wrk || exit | |
# Convert all JPEG files to JPEG-XL format losslessly | |
parallel 'cjxl --num_threads 1 -j 1 -e 10 {} {.}.JXL' ::: *.JPEG | |
# For each JPEG-XL file, copy metadata from the original JPEG file, and then delete the original JPEG file | |
if [[ -n $(shopt -s nullglob; echo *.JXL) ]]; then | |
parallel 'exiftool -m -overwrite_original -api compress=1 -tagsfromfile {.}.JPEG {}; touch -r {.}.JPEG {}; rm {.}.JPEG' ::: *.JXL | |
fi | |
# If there are still non converted JPEG files | |
if [[ -n $(shopt -s nullglob; echo *.JPEG) ]]; then | |
mkdir -p out | |
# Transform then, without changes, this usually remakes the Huffman tables, that is the most common source of errors when converting to JPEG-XL (commonly found in WhatsApp images) | |
parallel 'echo {}; jpegtran -copy all -optimize -perfect -strict -outfile out/{} {}' ::: *.JPEG | |
# For each JPEG-XL file, copy metadata from the original JPEG file, and then delete the original JPEG file | |
if [[ -n $(shopt -s nullglob; echo out/*.JPEG) ]]; then | |
parallel 'cjxl --num_threads 1 -j 1 -e 10 out/{} {.}.JXL; exiftool -m -overwrite_original -api compress=1 -tagsfromfile {} {.}.JXL; touch -r {} {.}.JXL; rm {} out/{}' ::: *.JPEG | |
fi | |
rmdir out | |
fi | |
# Rename XMP sidecars to match the new JPEG-XL files, if any | |
if [[ -n $(shopt -s nullglob; echo *.JPEG.xmp) ]]; then | |
for i in *.JPEG.xmp | |
do k="${i%.JPEG.xmp}.JXL.xmp" | |
if [[ -f "${i%.JPEG.xmp}.JXL" ]]; then | |
mv "$i" "$k" | |
fi | |
done | |
fi | |
if [[ -n $(shopt -s nullglob; echo *.JPEG.XMP) ]]; then | |
for i in *.JPEG.XMP | |
do k="${i%.JPEG.XMP}.JXL.XMP" | |
if [[ -f "${i%.JPEG.XMP}.JXL" ]]; then | |
mv "$i" "$k" | |
fi | |
done | |
fi | |
# Move all files back to the parent directory | |
find . -empty -delete | |
mv ./* .. | |
cd .. | |
rmdir wrk | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment