#!/bin/ksh
# sanesize - Adjust image files to a sane size
# Author: Perette Barella
# @(#) $Id: sanesize 94 2023-11-07 17:07:38Z perette $
# Copyright 2018 Devious Fish.  All rights reserved.

arg0=$(basename "$0")

# Korn shell/zsh require
# Author: Perette Barella
# Copyright 2018 Devious Fish.  All rights reserved.
# $Id: require 61 2021-08-09 18:49:07Z perette $

function require {
	typeset requirement
	integer result=0
	for requirement
	do
		if ! whence -p "${requirement%:*}" >/dev/null 2>&1
		then
			print -- "$arg0${arg0+: }${requirement#*:} not found; please install." 1>&2
			result=1
		fi
	done
	(( $result != 0 )) && exit $result
	return 0
}


function adjusted_size {
	typeset scaler="$1" limiter="$2" width="$3" height="$4" scaled limited
	typeset last_formula=""
	for formula in '' '*2/3' '/2' '/3' '/4' '/5' '/6' '/7' '/8' '/9' '/10'
	do
		let "scaled=scaler $formula"
		let "limited=limiter $formula"
		if [ $limited -lt 1024 -o $scaled -lt 1280 ]
		then
			# Image is oddly proportional, maybe panoramic.
			# Limit on how much we shrink the narrower dimension,
			# regardless of larger dimension.
			let "width=width $last_formula"
			let "height=height $last_formula"
			print "${width}x${height}"
			return 0
		fi
		if [ $scaled -lt 1536 ]
		then
			# We've got the larger dimension down to a good size.
			# Go with this.
			let "width=width $formula"
			let "height=height $formula"
			print "${width}x${height}"
			return 0
		fi
		last_formula="$formula"
	done
	print "Crazy image size ${width}x${height}" 1>&2
	print "${width}x${height}"
	return 1
}

function get_rotation_to_standard {
	typeset file="$1"
	typeset -l value
	integer rotation
	value=$(exiv2 -K Exif.Image.Orientation -Pv "$file") || return 1
	case "${value}" in
	    1|2)	rotation=0 ;;
	    3|4)	rotation=180 ;;
	    5|6)	rotation=90  ;;
	    7|8)	rotation=270 ;;
	    *)		
		print "$file: Invalid orientation: $value" 1>&2
		return 1
		;;
	esac
	print $rotation
	return 0
}

if [ "$1" = "-?" ]
then
	print "Usage: $arg0 [-n | -c] imagefile ...
Options:
  -c      Commit.  Overwrites original files after reduction is complete.
  -n      Trial run.  Indicates what is to be done, but does no work."
	exit 1
fi

COMMIT=false
ACTION=true

if [ "$1" = "-n" ]
then
	shift
	ACTION=false
fi
if [ "$1" = "-c" ]
then
	shift
	COMMIT=true
fi

require exiv2 identify:ImageMagick convert:ImageMagick

for file
do
	if [ $(dirname "$file") != "." ]
	then
		print -- "$file: Must not include path."
		exit 1
	fi
done

if $ACTION && ! mkdir Smaller
then
	print "$arg0: 'Smaller' directory already exists."
	exit 1
fi

for file
do
	if [ -f "$file" ] && data=$(identify "$file")
	then
		command=""
		explanation=""
		fix_orientation=false

		# Adjust the geometry/size
		print -- "$data" | read name type geometry junk
		width=$(print -- "$geometry" | cut -dx -f1)
		height=$(print -- "$geometry" | cut -dx -f2)
		if [[ $width != [1-9]*([0-9]) ]] || [[ $height != [1-9]*([0-9]) ]]
		then
			print -- "$file: Cannot identify image size." 1>&2
			continue
		fi
			
		if [ $width -gt $height ]
		then
			new_geom=$(adjusted_size $width $height $width $height)
		else
			new_geom=$(adjusted_size $height $width $width $height)
		fi
		if [ $? -eq 0 -a "$new_geom" != "$geometry" ]
		then
			explanation="$explanation${explanation:+, }$geometry -> $new_geom"
			command="$command -resize '$new_geom'"
		fi

		# Rotate the image into standard orientation
		rotation=$(get_rotation_to_standard "$file")
		if [ $? -eq 0 ] && [ $rotation -ne 0 ]
		then
			explanation="$explanation${explanation:+, }rotate $rotation"
			command="$command -auto-orient"
			fix_orientation=true
		fi

		dots=${file//[^.]/}
		filetype=$(basename "$file" | cut -d. -f${#dots})
		base=$(basename "$file" | cut -d. -f1-${#dots})
		outfile="Smaller/$base.jpeg"

		if [ "$filetype" != "jpeg" -a "$filetype" != "jpg" -a "$filetype" != "JPG" -a "$filetype" != "JPEG" ]
		then
			# Add a space to engage convert to change format.
			command="$command "
		fi

		if [ "$command" != "" ]
		then
			print -- "$file: $explanation" 1>&2
			$ACTION && eval "convert '$file' $command '$outfile'"
			if $ACTION && $fix_orientation
			then
				exiv2 -M"del Exif.Image.Orientation" -M"del Exif.Thumbnail.Orientation" modify "$outfile"
			fi
		else
			$ACTION && ln "$file" "$outfile"
		fi
	else
		print -- "$file: Not a file." 1>&2
	fi
done

if $ACTION && $COMMIT
then
	mv Smaller/* .
	rmdir Smaller
fi

