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