View Single Post
Posts: 67 | Thanked: 36 times | Joined on May 2010 @ Claremont (LA), California
#15
My script above fixes KML files from the buggy gpsjinni, but it's not very helpful if (like me) you tagged a bunch of pictures and then deleted the KML files.

So here's another script. This one requires exiftool and only runs on Linux, but it will correct the tags in pictures that were incorrectly tagged with the buggy version. In the simplest form, you stick it in a directory somewhere, chmod +x geotagfix, and run:

./geotagfix -v *.jpg

(it also works on cr2 files, and can easily be modified to accept crw, Nikon NEF, and such--just expand the case statement).

But what if (like me) you tagged some stuff with tracks from gpsjinni and others correctly with tools like ecoach or mappero? Well, if (like me) you were at a place where the longitude is greater than 90 (or greater than the maximum latitude you reached), you can fix only files with obviously bad coordinates:

./geotagfix -v -m 90 *.jpg

The script could easily be fixed to look for a minimum/maximum legal longitude/latitude range, but it's late and what I did is enough for my needs. So that's left as an exercise for the reader. :-)

if you're paranoid, the -n switch will tell you what files would be fixed, but will do nothing else.

Enjoy!

Code:
#!/bin/bash
#
# Fix geotags that were incorrectly input by gpsjinni.  This code
# depends on the assumption that I'm beyond 90 degrees either east or
# west.
#
USAGE="Usage: geotagfix [-m maxlat] [-v] files

The given files have their GPS data extracted.  The latitudes and
longitudes are interchanged, and the files are rewritten with the new
data.

    -m maxlat	Specify the (integer) maximum latitude found anywhere
		in the files (default 0).  Only images with
		"latitudes" greater than this value will be rewritten.
		For example, if you are shooting in most of the United
		States, specify -l 90 to only swap pictures that have
		a latitude greater than or equal to 90 degrees (which is
		impossible in a correct file).  The default, -m 0,
		will swap the coordinates in all files; in this case
		you must ensure that all input files actually need
		correction.
    -n		Report files that would be fixed, but don't fix them.
    -v		Report changed files."

maxlat=0
action=true
verbose=false
while (( $# > 0 ))
do
    case "$1" in
	-m)
	    maxlat="$2"
	    shift
	    ;;
	-n)
	    action=false
	    ;;
	-v)
	    verbose=true
	    ;;
	--)
	    shift
	    break
	    ;;
	-*)
	    echo "$USAGE" 1>&2
	    exit 2
	    ;;
	*)
	    break
	    ;;
    esac
    shift
done

TMP=/tmp/geotagfix.$$
trap "rm -f $TMP.*; exit 1" 1 2 15
trap "rm -f $TMP.*; exit 0" 13

for pic
do
    case "$pic" in
	*.jpg|*.cr2)
	    ;;
	*)
	    continue
	    ;;
    esac
    exiftool "$pic" \
      | egrep GPS \
      | sed '/^GPS Date/s/:/-/g' \
      > $TMP.a
    lat=$(grep 'GPS Latitude *:' $TMP.a | awk '{print $4}')
    if (( lat >= $maxlat ))
    then
	# Picture needs coordinate swapping.  Since exiftool refuses to
	# let us rewrite GPS tags, we need to create a dummy KML file
	# and use it to geotag the picture.
	#latref=$(sed -n 's/GPS Longitude Ref *: *//p' $TMP.a)
	#longref=$(sed -n 's/GPS Latitude Ref *: *//p' $TMP.a)
	awk '
	    /^GPS Time / \
		{
		tm = $NF
		}
	    /^GPS Date / \
		{
		dt = $NF
		}
	    /^GPS Altitude / \
		{
		alt = $4
		}
	    /^GPS Latitude / \
		{
		# This is actually the longitude.  We take advantage
		# of the fact that if you add zero to a string, awk
		# converts it to a number while ignoring any trailing
		# non-numeric information (in this case, single and
		# double quotes).
		d = $4
		m = $6 + 0
		s = $7 + 0
		dir = $8
		long = d + m / 60.0 + s / 3600.0
		if (dir == "S")
		    long = -long
		}
	    /^GPS Longitude / \
		{
		# This is actually the latitude.  See above about awk
		# numeric conversions.
		d = $4
		m = $6 + 0
		s = $7 + 0
		dir = $8
		lat = d + m / 60.0 + s / 3600.0
		if (dir == "W")
		    lat = -lat
		}
	    END \
		{
		# Make a fake GPX file to feed to exiftool.  I was
		# originally making a KML file, but in the process of
		# working around the exiftool bug I switched to GPX
		# and I was too lazy to switch back (especially
		# because GPX is simpler).
		print "<?xml version=\"1.0\"?>"
		print "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ec=\"eCoachGPXExtensionsV1\" version=\"1.1\" creator=\"ecoach\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd eCoachGPXExtensionsV1 /usr/share/ecoach/ec_gpx_ext_v1.xsd\">"
		print "<trk>"
		print "<name>Dummy</name>"
		print "<number>1</number>"
		print "<trkseg>"
		printf "<trkpt lat=\"%.12f\" lon=\"%.12f\">\n", lat, long
		printf "<ele>%.4f</ele>\n", alt
		printf "<time>%sT%sZ</time>\n", dt, tm
		print "</trkpt>"
		# A bug in exiftool requires at least two track points
		# with different times, else you get a divide by zero.
		# We hack this by faking a time far in the future.
		printf "<trkpt lat=\"%.12f\" lon=\"%.12f\">\n", lat, long
		printf "<ele>%.4f</ele>\n", alt
		print "<time>2038-01-01T00:00:00Z</time>"
		print "</trkpt>"
		print "</trkseg>"
		print "</trk>"
		print "</gpx>"
		}' \
	  $TMP.a \
	  > $TMP.gpx
	if $action
	then
	    exiftool -q -overwrite_original -geotag $TMP.gpx "$pic"
	    $verbose  &&  echo "Fixed $pic"
	else
	    echo "$pic needs fixing."
	fi
    fi
done

rm -f $TMP.*