spatial_features 3.12.0 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/spatial_features/download.rb +9 -7
- data/lib/spatial_features/importers/exif_photo.rb +62 -0
- data/lib/spatial_features/version.rb +1 -1
- data/lib/spatial_features.rb +1 -0
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b36a07cd400459369dcdaedd71899954e1a4687d94db1ac1d62e987a17c9552
|
|
4
|
+
data.tar.gz: '02101805b5ad1fee94e726fde4c24bba09e79641cc575361ff25ff51779f0fbc'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3bf6e8b22a387558f09ec940d080403535ecfe89c178b8ddb3233f1d55c8107e312d6cd0f3300d43176f52d06fa41f4f490d7dc0a4c1fb3131268fdd5a3a7185
|
|
7
|
+
data.tar.gz: ef898f88ad2b999c4d363312ae6527e5cd05ba4e7a14ef8f43330862da8e6e9a73b48515ad21ab3539aa267d87bdded6d4817630a95edf2b7832c3b844e369b8
|
|
@@ -34,17 +34,19 @@ module SpatialFeatures
|
|
|
34
34
|
fetch(path_or_url).read
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
# Returns an open
|
|
37
|
+
# Returns an open file for each source in `path_or_url`, unwrapping an archive when
|
|
38
38
|
# `unzip` is given a pattern its entries can match.
|
|
39
|
+
#
|
|
40
|
+
# @note A remote or IO-backed source is held in a `Tempfile`, which unlinks its path
|
|
41
|
+
# when it is garbage collected. The `Tempfile` itself is returned, rather than a fresh
|
|
42
|
+
# `File` opened on its path, so the path stays valid for as long as the caller holds
|
|
43
|
+
# the result. Entries extracted from an archive are ordinary files on disk and are
|
|
44
|
+
# opened by path.
|
|
39
45
|
def open_each(path_or_url, unzip: nil, **unzip_options)
|
|
40
46
|
file = Download.open(path_or_url)
|
|
41
|
-
|
|
42
|
-
find_in_zip(file, find: unzip, **unzip_options)
|
|
43
|
-
else
|
|
44
|
-
[file]
|
|
45
|
-
end
|
|
47
|
+
return [file] unless unzip && Unzip.is_zip?(file)
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
find_in_zip(file, find: unzip, **unzip_options).map { |path| File.open(path) }
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
def normalize_file(file)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'exifr/jpeg'
|
|
2
|
+
require 'ostruct'
|
|
3
|
+
|
|
4
|
+
module SpatialFeatures
|
|
5
|
+
module Importers
|
|
6
|
+
class ExifPhoto < Base
|
|
7
|
+
JPEG_PATTERN = /\.jpe?g\z/i.freeze
|
|
8
|
+
NO_PHOTOS = "This archive doesn't contain any JPEG photos.".freeze
|
|
9
|
+
UNREADABLE_PHOTO = "This photo couldn't be read. It may be damaged, or saved in a JPEG format we don't support.".freeze
|
|
10
|
+
|
|
11
|
+
def self.create_all(data, **options)
|
|
12
|
+
Download.open_each(data, unzip: JPEG_PATTERN, tmpdir: options[:tmpdir]).map do |file|
|
|
13
|
+
new(file.path, **options)
|
|
14
|
+
end
|
|
15
|
+
rescue Unzip::PathNotFound
|
|
16
|
+
raise ImportError, NO_PHOTOS
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def initialize(data, **options)
|
|
20
|
+
options[:source_identifier] ||= ::File.basename(data.to_s)
|
|
21
|
+
super(data, **options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def cache_key
|
|
25
|
+
@cache_key ||= Digest::MD5.file(@data).hexdigest
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def each_record
|
|
31
|
+
photo = EXIFR::JPEG.new(@data)
|
|
32
|
+
gps = photo.gps
|
|
33
|
+
unless usable_gps?(gps)
|
|
34
|
+
@warnings << 'No usable GPS coordinates were found in this photo.'
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
yield OpenStruct.new(
|
|
39
|
+
name: ::File.basename(@data),
|
|
40
|
+
geog: "POINT(#{gps.longitude} #{gps.latitude})",
|
|
41
|
+
metadata: metadata_from(photo, gps),
|
|
42
|
+
importable_image_paths: [@data]
|
|
43
|
+
)
|
|
44
|
+
rescue EXIFR::MalformedImage
|
|
45
|
+
raise ImportError, UNREADABLE_PHOTO
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def usable_gps?(gps)
|
|
49
|
+
gps && gps.latitude.is_a?(Numeric) && gps.longitude.is_a?(Numeric) &&
|
|
50
|
+
(-90..90).cover?(gps.latitude) && (-180..180).cover?(gps.longitude)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def metadata_from(photo, gps)
|
|
54
|
+
{
|
|
55
|
+
'capture_time' => photo.date_time_original&.strftime('%Y-%m-%d %H:%M:%S'),
|
|
56
|
+
'altitude' => gps.altitude&.to_s,
|
|
57
|
+
'camera_model' => photo.model.presence
|
|
58
|
+
}.compact
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/lib/spatial_features.rb
CHANGED
|
@@ -21,6 +21,7 @@ require 'spatial_features/has_spatial_features/queued_spatial_processing'
|
|
|
21
21
|
require 'spatial_features/has_spatial_features/feature_import'
|
|
22
22
|
|
|
23
23
|
require 'spatial_features/importers/base'
|
|
24
|
+
require 'spatial_features/importers/exif_photo'
|
|
24
25
|
require 'spatial_features/importers/file'
|
|
25
26
|
require 'spatial_features/importers/geo_json'
|
|
26
27
|
require 'spatial_features/importers/esri_geo_json'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spatial_features
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Wallace
|
|
@@ -114,6 +114,20 @@ dependencies:
|
|
|
114
114
|
- - ">="
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
116
|
version: '0'
|
|
117
|
+
- !ruby/object:Gem::Dependency
|
|
118
|
+
name: exifr
|
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
type: :runtime
|
|
125
|
+
prerelease: false
|
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '0'
|
|
117
131
|
- !ruby/object:Gem::Dependency
|
|
118
132
|
name: rails
|
|
119
133
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -204,6 +218,7 @@ files:
|
|
|
204
218
|
- lib/spatial_features/has_spatial_features/queued_spatial_processing.rb
|
|
205
219
|
- lib/spatial_features/importers/base.rb
|
|
206
220
|
- lib/spatial_features/importers/esri_geo_json.rb
|
|
221
|
+
- lib/spatial_features/importers/exif_photo.rb
|
|
207
222
|
- lib/spatial_features/importers/file.rb
|
|
208
223
|
- lib/spatial_features/importers/geo_json.rb
|
|
209
224
|
- lib/spatial_features/importers/geomark.rb
|