#!/bin/ksh
# exif_date_adjust - Change the time in a file's EXIF metadata
# Author: Perette Barella
# Copyright 2018 Devious Fish.  All rights reserved.
VERSION='$Id: exif_date_adjust 61 2021-08-09 18:49:07Z perette $'

arg0=$(basename "$0")
# Validate that ksh supports the modern/extended getopts format.
# Author: Perette Barella 
# Copyright 2018 Devious Fish.  All rights reserved.
# $Id: modern_ksh_check 19 2018-07-28 23:40:39Z perette $  


function modern_ksh_check {
	if [[ $(getopts '[-][12:abc]' flag --abc; print -- 0$flag) != "012" ]]
	then
		print -- "$arg0${arg0+: }Outdated Korn shell." 1>&2
		exit 1
	fi
}
# extract_exif_date
# Author: Perette Barella
# Copyright 2018-2021 Devious Fish.  All rights reserved.
VERSION='$Id$'

# 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
}

require exiv2

typeset -r EXIF_DATE_ORDER_CAPTURE="Exif.Photo.DateTimeOriginal Exif.Photo.DateTimeDigitized Exif.Image.DateTime"
typeset -r EXIF_DATE_ORDER_MODIFICATION="Exif.Image.DateTime Exif.Photo.DateTimeDigitized Exif.Photo.DateTimeOriginal"

# Extract EXIF date information
#   $1 -- Filename
#   $2 -- Exif field name, or "capture" or "modification" to pick best available
# Return: 0 on success, 1 out failure.
#         Datetime on stdout, format: YYYYmmddHHMM.SS
function extract_exif_date {
	typeset file="$1" order="$2" tag date exif_order

	case "$order" in
		capture)	exif_order="$EXIF_DATE_ORDER_CAPTURE" ;;
		modification)	exif_order="$EXIF_DATE_ORDER_MODIFICATION" ;;
		Exif.Photo.DateTimeOriginal)
				exif_order="$order" ;;
		Exif.Photo.DateTimeDigitized)
				exif_order="$order" ;;
		Exif.Image.DateTime)
				exif_order="$order" ;;
		*)		print "extract_exif_date: $order: Unknown request." 1>&2
				return 1;
	esac
	# Check if the tag exists
	for tag in $exif_order
	do
		if date=$(exiv2 -K$tag -Pv "$file")
		then
			date=${date//:/}
			date=${date// /}
			if [[ ${#date} -eq 14 ]]
			then
				print -- "${date:0:12}.${date:12}"
				return 0
			fi
			print "$file: Corrupt EXIF date tag $tag: $date" 1>&2
		fi
	done
	print "$file: No date EXIF tags found." 1>&2
	return 1
}


modern_ksh_check

USAGE=$'
[-1?'$VERSION$']
[+NAME?exif_date_adjust - Adjust EXIF modification date]
[+DESCRIPTION?\b'$arg0$'\b adjusts the EXIF modification date of a
jpeg image.  This can be used to adjust timestamps where a camera had
an incorrect time, or to set the modification date to match original
capture time after being changed by graphic editing software.]
[?The \voffset\v parameter is a relative time, as accepted by
\vdate -d\v.]
[n:dry-run?Perform a dry-run, without actual changes.]
[v:verbose?Provide verbose output.]
[w:warnings?Treat missing EXIF data as a warning.  Omit this option if
missing data should not affect a successful exit status.]
[+EXIT STATUS?0 on success, 1 on error, 2 on warning (EXIF data not found).]
[+SEE ALSO?\bexif\b(1), \bexif_dates_to_file_dates\b(1), \bexif_where\b(1)]
[+CAVEATS?This utility is timezone naive.]

offset files

[-author?Perette Barella <perette@deviousfish.com>]
'

DRYRUN=false
VERBOSE=false
WARNINGS=false
while getopts -a "$arg0" "$USAGE" option
do
	case "$option" in
	    n)
		DRYRUN=true
		;;
	    v)
		VERBOSE=true
		;;
	    w)
		WARNINGS=true
		;;
	esac
done

shift $((OPTIND - 1))
if [ $# -lt 1 ]
then
	OPTIND=0
	getopts -a "$arg0" "$USAGE" option --short
	exit 1
fi

offset="$1"
shift
if [[ ${offset:0:1} != "-" && ${offset:0:1} != "+" ]]
then
	offset="+$offset"
fi


status=0
for file in "$@"
do
	if [[ ! -f "$file" ]]
	then
		print "$file: Does not exist or is not a file." 1>&2
		continue
	fi

	for datetype in Exif.Photo.DateTimeOriginal Exif.Photo.DateTimeDigitized Exif.Image.DateTime
	do
		if date=$(extract_exif_date "$file" "$datetype")
		then
			newdate=$(TZ="UTC0" date -d "${date:0:4}-${date:4:2}-${date:6:2} ${date:8:2}:${date:10:2}:${date:13:2}Z $offset" +'%Y:%m:%d %H:%M:%S')
			$VERBOSE && print -- "$file: $date --> $newdate"
			if ! $DRYRUN
			then
				exiv2 -M"set $datetype $newdate" modify "$file" || status=1
			fi
		elif $WARNINGS
		then
			[ $status -eq 0 ] && status=2
		fi
	done
done

exit $status
