]> git.street.me.uk Git - andy/viking.git/blame - tools/images2waypoints.pl
Add link to HERE Maps.
[andy/viking.git] / tools / images2waypoints.pl
CommitLineData
ae417ab2
RN
1#! /usr/bin/perl -w
2# Copyright (C) 2010 Rob Norris <rw_norris@hotmail.com>
a1362474
GB
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17#
18
ae417ab2
RN
19
20=head1 Overview
21
22A script to auto generate basic Viking .vik files for directories containing images.
23
24Simply recursively search down the directory tree (from the current location) for suitable image files
25 [normally jpg|JPG (probably photographs)] and then extract any location data from the EXIF part.
26
27For each directory this info is output to a file into either Viking (default) or GPX data file formats.
28Output filename is waypoints.vik (or waypoints.gpx in GPX mode) unless the -o option is specified.
29
30Options:
31-g put into outputting GPX file mode
32-o <name> - specify output base filename (overriding 'waypoints')
33-r make waypoint image filenames relative (rather than absolute)
34
35Required programs:
36. exiftool - getting location data from EXIF (Debian package libimage-exiftool-perl)
37
38Recommended programs:
39. viking - Obviously when viking mode used to view the output [can view gpx as well]
40. gpscorrelate[-gui] - Correlates digital photos with GPS data filling EXIF fields
41 i.e. something to put EXIF info into files to begin with
42
43Various improvements can be:
44. Command line options to control things eg:
45 .which symbol to use for each point
46 .which Viking Map / other viking defaults
47 .a non recursive mode
48 .a mode to generate one massive file instead of one per directory
49
50. Work out zoom factor to see all points in Viking
51. Metadata bounds for gpx
52
53. Any Speed optimizations - deciding which files to process could be improved
54. Maybe better control of which files to analyse - maybe any - not just files named .jpg
55. Is even doing this in Perl the best tool for the job [consider python, C, etc...]?
56
57=cut
58
59# ************ START OF CODE *******************
60
61use strict;
62use File::Find;
63use Image::ExifTool qw(:Public);
64
65# Output modes
66use constant VIKING => 1;
67use constant GPX => 2;
68
69use constant RELATIVE => 1;
70use constant ABSOLUTE => 2;
71
72#################################
73# Some global variables
74# Create a new Image::ExifTool object
75my $exifTool = new Image::ExifTool;
76
77my @waypoint = ("","","","","","");
78my @position = ("0.0", "0.0"); # lat / long
79
80my $out_file;
81
82# Default mode
83my $mode = VIKING;
84my $imagefilemode = ABSOLUTE;
85
86#################################
87
88# Write header first part of .vik file
89sub Header_Viking {
90
91 return <<END;
92#VIKING GPS Data file http://viking.sf.net/
93
94~Layer Map
95name=Map
96mode=13
97directory=
98alpha=255
99autodownload=f
100mapzoom=0
101~EndLayer
102
103
104~Layer TrackWaypoint
105name=TrackWaypoint
106tracks_visible=f
107waypoints_visible=t
beb6407f 108routes_visible=f
ae417ab2
RN
109drawmode=0
110drawlines=t
111drawpoints=t
112drawelevation=f
113elevation_factor=30
114drawstops=f
115stop_length=60
116line_thickness=1
117bg_line_thickness=0
118trackbgcolor=#ffffff
ae417ab2
RN
119drawlabels=t
120wpcolor=#000000
121wptextcolor=#ffffff
122wpbgcolor=#8383c4
123wpbgand=t
124wpsymbol=0
125wpsize=4
126wpsyms=t
127drawimages=t
128image_size=64
129image_alpha=255
130image_cache_size=300
131
132
133~LayerData
134type="waypointlist"
135END
136#
137#
138}
139
140# Write header first part of .gpx file
141sub Header_GPX {
142 return <<END;
143<?xml version="1.0" encoding="UTF-8"?>
144<gpx
145 version="1.1"
146creator="$0"
147xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
148xmlns="http://www.topografix.com/GPX/1/1"
149xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
150END
151# TODO consider metadata time & bounds info
152}
153
154sub Footer_GPX {
155 return "</gpx>\n";
156}
157
158sub My_Process_File {
159 my ($dir, $file) = @_;
160
161 ## Start
162 ##
163
164 # Only do files we are interested in
165 unless ($file =~ m/\.(?:JPG|jpg)$/) {
166 return;
167 }
168 #print "My_Process_File $file\n";
169
170 @waypoint = ("","","","","","");
171
172 # Extract meta information from an image
173 my $info = $exifTool->ImageInfo("$dir/$file");
174
175 #DateTimeOriginal
176 #GPSVersionID
177 #GPSAltitude
178 #GPSLatitude (1)
179 #GPSLongitude (1)
180
181 foreach (sort keys %$info) {
182 #print "$file: $_ => $$info{$_}\n";
183
184 # If we can make the sort in reverse
185
186 #if (/GPSVersionID/) {
187 # unless ("$$info{$_}" eq "2.0.0.0") {
188 # # Only handle version 2 Ids
189 # return;
190 # }
191 #}
192
193 # Assume datum is in WGS-84
194 if (/^GPSLatitude\ /) {
195 $waypoint[0] = $$info{$_};
196 next;
197 }
198
199 if (/^GPSLatitudeRef/) {
200 $waypoint[1] = $$info{$_};
201 next;
202 }
203
204 if (/^GPSLongitude\ /) {
205 $waypoint[2] = $$info{$_};
206 next;
207 }
208
209 if (/^GPSLongitudeRef/) {
210 $waypoint[3] = $$info{$_};
211 next;
212 }
213
214 if (/^GPSAltitude\ /) {
215 my @row = split / /, $$info{$_};
216 $waypoint[4] = $row[0]; #hopefully in metres
217 next;
218 }
219
220 if (/^DateTimeOriginal$/) {
221 $waypoint[5] = $$info{$_};
222 next;
223 }
224
225 }
226
227 # Check for South
228 if ($waypoint[1] eq "South" && $waypoint[0] ne "") {
229 $waypoint[0] = '-'."$waypoint[0]";
230 }
231
232 # Check for West
233 if ($waypoint[3] eq "West" && $waypoint[2] ne "") {
234 $waypoint[2] = '-'."$waypoint[2]";
235 }
236
237 # At least lat/long
238 if ($waypoint[0] ne "" && $waypoint[2] ne "") {
239 # Update position so can track where to center map
240 $position[0] = $waypoint[0];
241 $position[1] = $waypoint[2];
242 my ($name, $path) = File::Basename::fileparse ($file, qr/\.[^.]*/);
243 my $filename = "$file"; # Relative filename
244 if ($mode == VIKING) {
245 # ATM, Viking (0.9.94) wp image loading only works if absolute
246 # See SF 2998555
247 # Create absolute filename
248 if ($imagefilemode == ABSOLUTE) {
249 my ($abs_path) = File::Spec->rel2abs("$path", "$dir");
250 $filename = "$abs_path/$file";
251 }
dade5f87 252 return "type=\"waypoint\" latitude=\"$waypoint[0]\" longitude=\"$waypoint[2]\" name=\"$name\" altitude=\"$waypoint[4]\" comment=\"$waypoint[5]\" image=\"$filename\" symbol=\"scenic area\"\n";
ae417ab2
RN
253 }
254 else {
dade5f87 255 return "<wpt lat=\"$waypoint[0]\" lon=\"$waypoint[2]\">\n <name>$name</name>\n <ele>$waypoint[4]</ele>\n <desc>$waypoint[5]</desc>\n <sym>scenic area</sym>\n</wpt>";
ae417ab2
RN
256 }
257
258 }
259
260 return "";
261 ## END
262 ##
263}
264
265sub Footer_Viking {
266 return <<END;
267type="waypointlistend"
268~EndLayerData
269~EndLayer
270
271xmpp=32.000000
272ympp=32.000000
273lat=$position[0]
274lon=$position[1]
275mode=mercator
276color=#cccccc
277drawscale=t
278drawcentermark=t
279
280END
281}
282
283#
284sub My_Process_Dir {
285 my ($dir) = @_;
286 my $FTT = 1; # First Time Through flag to mark first pass
287 my $has_location = 0;
288
289 #print "My_Process_Dir $dir\n";
290 opendir(DIR, $dir) or die "$0: can't opendir $dir: $!\n";
291
292 my $line;
293 while (defined(my $file = readdir(DIR))) {
294 next if $file =~ /^\.\.?$/; # skip . and ..
295 $line = My_Process_File($dir, $file);
296 # At least one file with location data exists
297 if (defined ($line)) {
298 if ($line ne "" && $FTT == 1) {
299 $FTT = 0;
300 open (FILE, ">$dir/$out_file") or die "$0: Can not open $!\n";
301
302 if ($mode == VIKING) {
303 print FILE Header_Viking();
304 }
305 else {
306 print FILE Header_GPX();
307 }
308 $has_location = 1; # Remember that we have found something
309 }
310 if ($line ne "") {
311 print FILE $line;
312 }
313 }
314 }
315
316 if ($has_location) {
317 if ($mode == VIKING) {
318 print FILE Footer_Viking();
319 }
320 else {
321 print FILE Footer_GPX();
322 }
323 close (FILE);
324 }
325 closedir(DIR);
326}
327
328#
329sub Process_File {
330 my $file = $_;
331 unless (-d $file) {
332 return;
333 }
334 return if $file =~ /^\.\.$/; # Ensure skip ..
335 print "$0: Doing directory $file\n";
336 My_Process_Dir($file);
337}
338
339############ START ##################
340
341# Default filename
342my $out_file_start = "waypoints";
343
344if (defined @ARGV) {
345 for (my $arg=0; $arg < $#ARGV+1; $arg++) {
346 if ("$ARGV[$arg]" eq "-o") {
347 # Set filename to next arg
348 if ($arg < $#ARGV) {
349 $out_file_start = $ARGV[$arg + 1];
350 }
351 }
352 if ("$ARGV[$arg]" eq "-g") {
353 $mode = GPX;
354 }
355 if ("$ARGV[$arg]" eq "-r") {
356 $imagefilemode = RELATIVE;
357 }
358 }
359}
360#print "$0: Mode is $mode\n";
361
362if ($mode == VIKING) {
363 $out_file = "$out_file_start".".vik";
364}
365else {
366 $out_file = "$out_file_start".".gpx";
367}
368#print "$0: File output is $out_file\n";
369
370$exifTool->Options(CoordFormat => q{%.6f});
371$exifTool->Options(FastScan => 1);
372
373# Only get information in Standard EXIF
374$exifTool->Options(Group0 => ['EXIF']);
375
376find(\&Process_File, ".");
377
378#end