-
Notifications
You must be signed in to change notification settings - Fork 1
/
photo-mapper.rb
executable file
·135 lines (113 loc) · 3.84 KB
/
photo-mapper.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env ruby
# This Ruby script generates two Keyhole Markup Language files:
# 1. points.kml - a point for every photo with GPS coords
# 2. route.kml - a single line that joins every photo with GPS coords
#
# from a folder (and sub-folders) of digital photos
#
# The intention is to create a chronological map of
# photographed destinations from the digital photos themselves
#
# Usage: ruby photo-mapper.rb starting_directory
# e.g.: ruby photo-mapper.rb Photos
#
# Author: Andrew Freemantle http://www.fatlemon.co.uk/photo-mapper
require 'exifr'
require 'exifr/jpeg'
require 'date'
# The Panasonic DMC-TZ40 always saves GPS coords. Even indoors. Exclude photos with these coords..
INVALID_GPS_COORDS = [17056881.853375, 17056881.666666668]
# Exclude the following directories when traversing..
IGNORE_DIR = ['.', '..', '.git', '.DS_Store', '@eaDir']
# List of supported photo filename extensions..
ALLOWED_EXTENSIONS = ['.jpg', '.JPG', '.jpeg', '.JPEG']
# Directory traversing class
# initialized with a starting path, it recursively descends through
# any directories it finds that aren't in the IGNORE_DIR array above
class Traverse
def initialize(path, pointsFile, routeFile)
puts "in " + path
@files = Dir.entries(path).sort
@files.each do |f|
if !IGNORE_DIR.include? f
if File.directory?(File.join(path, f))
@t = Traverse.new(File.join(path, f), pointsFile, routeFile)
elsif File.file?(File.join(path, f))
# Is this an allowed file?
if ALLOWED_EXTENSIONS.include? File.extname(f)
# Does this file have Geo coords?
puts "Got allowed file #{File.join(path,f)}"
begin
the_url = File.join(path, f)
@file = EXIFR::JPEG.new(the_url)
if @file.exif?()
# We have EXIF, but do we have sensible Lat & Long?
if @file.gps != nil
if !INVALID_GPS_COORDS.include? @file.gps.latitude
#puts @file.gps
pointsFile.puts("<Placemark><name>#{f}</name><Point><coordinates>#{@file.gps.longitude},#{@file.gps.latitude},#{@file.gps.altitude}</coordinates></Point></Placemark>")
routeFile.puts("#{@file.gps.longitude},#{@file.gps.latitude},0 ")
else
puts "No GPS in " + ARGV[0]
end
end
else
puts "No EXIF in " + ARGV[0]
end
rescue EOFError
# End Of File can happen for partially copied or uploaded photos
# and there's nothing we can do here but report out and skip
puts "Reached EOF for #{File.join(path,f)} - skipped."
end
end
end
end
end
pointsFile.flush()
routeFile.flush()
end
end
# Start the two output files:
pointsFile = File.open('points.kml', 'w')
routeFile = File.open('route.kml', 'w')
date = Date.today
# write the file headers
pointsFile.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<kml xmlns=\"http://www.opengis.net/kml/2.2\">
<Folder>
<name>points</name>
<description>Generated on #{date.strftime('%a %-d %b %Y')} by photo-mapper - http://www.fatlemon.co.uk/photo-mapper</description>
<open>1</open>")
routeFile.puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<kml xmlns=\"http://www.opengis.net/kml/2.2\">
<Folder>
<name>route</name>
<description>Generated on #{date.strftime('%a %-d %b %Y')} by photo-mapper - http://www.fatlemon.co.uk/photo-mapper</description>
<open>1</open>
<Style id=\"linestyle\">
<LineStyle>
<color>ff000000</color>
<width>2</width>
</LineStyle>
</Style>
<Placemark>
<name>Route</name>
<styleUrl>#linestyle</styleUrl>
<LineString>
<extrude>1</extrude>
<tessellate>1</tessellate>
<coordinates>")
go = Traverse.new(File.absolute_path(ARGV[0]), pointsFile, routeFile)
# Close the files
pointsFile.puts("
</Folder>
</kml>")
pointsFile.flush()
routeFile.puts("</coordinates>
</LineString>
</Placemark>
</Folder>
</kml>")
routeFile.flush()
# Done :o)
puts "Done"