Extracts one JPEG from each ZIP to check for the processing comment before doing a full extract/resize/rezip cycle. Shared constants moved to config.sh as single source of truth. Trap and cleanup extended to cover the sample temp file.
132 lines
3.5 KiB
Bash
Executable File
132 lines
3.5 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# zip_images_resize Resizing large JPGs in ZIPs
|
|
# Based on: https://shkspr.mobi/blog/2016/12/converting-rar-to-zip-in-linux/
|
|
#
|
|
# Usage: xxx.sh file [file ...]
|
|
|
|
if [ $# -eq 0 ]; then
|
|
echo "Usage: $0 file.zip [file2.zip ...]"
|
|
exit 1
|
|
fi
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
source "$SCRIPT_DIR/config.sh"
|
|
|
|
echo "Resizing large JPGs in ZIPs"
|
|
|
|
# Use RAM disk for temporary files.
|
|
WORKDIR="/dev/shm/"
|
|
|
|
# Cleanup function
|
|
cleanup_temp() {
|
|
if [ -n "$SAMPLE" ] && [ -f "$SAMPLE" ]; then
|
|
rm -f "$SAMPLE"
|
|
fi
|
|
if [ -n "$TEMPDIR" ] && [ -d "$TEMPDIR" ]; then
|
|
rm -r "$TEMPDIR"
|
|
fi
|
|
}
|
|
|
|
# Count total files
|
|
TOTAL_FILES=$#
|
|
CURRENT_FILE=0
|
|
|
|
for INFILE in "$@"; do
|
|
CURRENT_FILE=$((CURRENT_FILE + 1))
|
|
|
|
# Convert to absolute path
|
|
INFILE="$(realpath "$INFILE")"
|
|
echo "Processing file $CURRENT_FILE of $TOTAL_FILES: $INFILE"
|
|
|
|
SAMPLE=""
|
|
TEMPDIR=""
|
|
trap cleanup_temp EXIT INT TERM
|
|
|
|
# Check if already processed by sampling the first JPEG in the archive
|
|
FIRST_JPEG=$(unzip -l "$INFILE" 2>/dev/null | grep -iE '\.(jpg|jpeg)$' | head -1 | awk '{print $NF}')
|
|
if [ -n "$FIRST_JPEG" ]; then
|
|
SAMPLE=$(mktemp -p "$WORKDIR" --suffix=.jpg)
|
|
if unzip -p "$INFILE" "$FIRST_JPEG" > "$SAMPLE" 2>/dev/null; then
|
|
COMMENT=$(~/Applications/magick identify -format "%c" "$SAMPLE" 2>/dev/null)
|
|
rm -f "$SAMPLE"
|
|
SAMPLE=""
|
|
if [[ "$COMMENT" == "$MAGICK_COMMENT" ]]; then
|
|
echo "Skipping $INFILE: already processed"
|
|
trap - EXIT INT TERM
|
|
continue
|
|
fi
|
|
else
|
|
rm -f "$SAMPLE"
|
|
SAMPLE=""
|
|
fi
|
|
fi
|
|
|
|
OUTFILE="$(realpath "${INFILE%.zip}-compress.zip")"
|
|
|
|
# Remove output file if it already exists
|
|
if [ -e "${OUTFILE}" ]; then
|
|
rm "${OUTFILE}"
|
|
fi
|
|
|
|
# Set name for the temp dir. This directory will be created under WORKDIR
|
|
TEMPDIR=$(mktemp -p "$WORKDIR" -d)
|
|
|
|
# Create a temporary folder for unzipped files
|
|
echo "Extracting $INFILE"
|
|
|
|
# extract files from zip
|
|
if ! unzip "$INFILE" -d "$TEMPDIR"; then
|
|
echo "Error: Failed to extract $INFILE"
|
|
cleanup_temp
|
|
continue
|
|
fi
|
|
|
|
# resize
|
|
#convert '${TEMPDIR}/*.jpg' -set filename:fn '%[basename]' -resize 2800000@@\> -sampling-factor 4:2:0 -strip -quality 85% -colorspace RGB '%[filename:fn].jpg'
|
|
|
|
if ! pushd "$TEMPDIR" > /dev/null; then
|
|
echo "Error: Failed to change to temp directory"
|
|
cleanup_temp
|
|
continue
|
|
fi
|
|
"$SCRIPT_DIR/images_resize.sh"
|
|
popd > /dev/null
|
|
|
|
# Zip the files with no compression
|
|
pushd "$TEMPDIR" > /dev/null
|
|
if ! 7z a -tzip -mx=0 "$OUTFILE" ./*; then
|
|
echo "Error: Failed to create ZIP"
|
|
popd > /dev/null
|
|
cleanup_temp
|
|
continue
|
|
fi
|
|
popd > /dev/null
|
|
|
|
# Alternative. MUCH SLOWER, but better compression
|
|
# 7z a -mm=Deflate -mfb=258 -mpass=15 -r "$NEWNAME" *
|
|
|
|
# Preserve file modification time
|
|
touch -r "$INFILE" "$OUTFILE"
|
|
|
|
# Check that OUTFILE exists and is not empty before deleting INFILE
|
|
if [ ! -s "$OUTFILE" ]; then
|
|
echo "Error: Output file is empty or does not exist. Keeping original file."
|
|
cleanup_temp
|
|
continue
|
|
fi
|
|
|
|
rm "$INFILE"
|
|
mv "$OUTFILE" "$INFILE"
|
|
|
|
# Delete the temporary directory
|
|
cleanup_temp
|
|
trap - EXIT INT TERM
|
|
|
|
# OPTIONAL. Safe-remove the old file
|
|
#gio trash "$OLDFILE"
|
|
|
|
done
|
|
|
|
echo "Conversion Done"
|