94 lines
1.9 KiB
Bash
Executable File
94 lines
1.9 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
input="$1"
|
|
output="$2"
|
|
target_size_raw="$3"
|
|
|
|
if [[ -z "$input" || -z "$output" || -z "$target_size_raw" ]]; then
|
|
echo "Usage: $0 input output.jpg <target size>"
|
|
exit 1
|
|
fi
|
|
|
|
parse_size() {
|
|
local size="$1"
|
|
|
|
size=$(echo "$size" | tr '[:lower:]' '[:upper:]' | tr -d ' ')
|
|
|
|
if [[ "$size" =~ ^([0-9]+(\.[0-9]+)?)(B|KB|MB)?$ ]]; then
|
|
value="${BASH_REMATCH[1]}"
|
|
unit="${BASH_REMATCH[3]}"
|
|
|
|
case "$unit" in
|
|
""|"B") multiplier=1 ;;
|
|
"KB") multiplier=1024 ;;
|
|
"MB") multiplier=$((1024 * 1024)) ;;
|
|
*) echo "Invalid size unit: $unit"; exit 1 ;;
|
|
esac
|
|
|
|
awk "BEGIN {printf \"%d\", $value * $multiplier}"
|
|
else
|
|
echo "Invalid size format: $size"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
target_size=$(parse_size "$target_size_raw")
|
|
|
|
compress_and_get_size() {
|
|
local q=$1
|
|
magick "$work" -strip -interlace Plane -quality "$q" "$output"
|
|
stat -c%s "$output"
|
|
}
|
|
|
|
|
|
work=$(mktemp --suffix=.jpg)
|
|
cp "$input" "$work"
|
|
|
|
magick "$input" \
|
|
-auto-orient \
|
|
-colorspace sRGB \
|
|
-strip \
|
|
-background white -alpha remove -alpha off \
|
|
"$work"
|
|
|
|
echo "Trying to fit below $target_size bytes"
|
|
|
|
while true; do
|
|
|
|
# Binary search
|
|
low=1
|
|
high=95
|
|
best_q=1
|
|
|
|
while (( low <= high )); do
|
|
mid=$(((low + high) / 2))
|
|
size=$(compress_and_get_size "$mid")
|
|
|
|
echo " Quality $mid -> $size bytes"
|
|
|
|
best_size=$size
|
|
|
|
if (( size <= target_size )); then
|
|
best_q=$mid
|
|
low=$((mid + 1))
|
|
else
|
|
high=$((mid - 1))
|
|
fi
|
|
done
|
|
|
|
echo "Best quality this round: $best_q ($best_size bytes)"
|
|
|
|
if (( best_size <= target_size )); then
|
|
echo "DONE: $output is $best_size bytes"
|
|
break
|
|
fi
|
|
|
|
echo " Reducing resolution"
|
|
tmp=$(mktemp --suffix=.jpg)
|
|
|
|
magick "$work" -resize 75% -quality 85 "$tmp"
|
|
mv "$tmp" "$work"
|
|
done
|
|
|
|
rm -f "$work"
|