geo_concerns 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/README.md +6 -1
- data/app/models/concerns/geo_concerns/file_set/derivatives.rb +5 -5
- data/app/models/concerns/geo_concerns/image_file_behavior.rb +1 -1
- data/app/models/concerns/geo_concerns/raster_file_behavior.rb +1 -1
- data/app/models/concerns/geo_concerns/vector_file_behavior.rb +1 -1
- data/app/processors/geo_concerns/processors/base_geo_processor.rb +44 -34
- data/app/processors/geo_concerns/processors/gdal.rb +49 -0
- data/app/processors/geo_concerns/processors/ogr.rb +19 -0
- data/app/processors/geo_concerns/processors/raster/aig.rb +13 -17
- data/app/processors/geo_concerns/processors/raster/base.rb +15 -49
- data/app/processors/geo_concerns/processors/raster/dem.rb +14 -31
- data/app/processors/geo_concerns/processors/raster/info.rb +52 -0
- data/app/processors/geo_concerns/processors/raster/processor.rb +0 -1
- data/app/processors/geo_concerns/processors/vector/base.rb +16 -42
- data/app/processors/geo_concerns/processors/vector/processor.rb +0 -1
- data/app/processors/geo_concerns/processors/vector/shapefile.rb +2 -2
- data/app/processors/geo_concerns/processors/zip.rb +2 -4
- data/geo_concerns.gemspec +7 -8
- data/lib/geo_concerns/version.rb +1 -1
- data/spec/controllers/image_works_controller_spec.rb +16 -0
- data/spec/processors/geo_concerns/processors/base_geo_processor_spec.rb +29 -25
- data/spec/processors/geo_concerns/processors/gdal_spec.rb +59 -0
- data/spec/processors/geo_concerns/processors/ogr_spec.rb +36 -0
- data/spec/processors/geo_concerns/processors/raster/aig_spec.rb +12 -5
- data/spec/processors/geo_concerns/processors/raster/base_spec.rb +15 -47
- data/spec/processors/geo_concerns/processors/raster/dem_spec.rb +14 -10
- data/spec/processors/geo_concerns/processors/raster/info_spec.rb +35 -0
- data/spec/processors/geo_concerns/processors/vector/base_spec.rb +15 -28
- data/spec/processors/geo_concerns/processors/vector/shapefile_spec.rb +1 -1
- metadata +37 -42
@@ -0,0 +1,52 @@
|
|
1
|
+
module GeoConcerns
|
2
|
+
module Processors
|
3
|
+
module Raster
|
4
|
+
class Info
|
5
|
+
attr_accessor :doc
|
6
|
+
attr_writer :min_max, :size
|
7
|
+
|
8
|
+
def initialize(path)
|
9
|
+
@doc = gdalinfo(path)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns the min and max values for a raster.
|
13
|
+
# @return [String] computed min and max values
|
14
|
+
def min_max
|
15
|
+
@min_max ||= raster_min_max
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the raster size.
|
19
|
+
# @return [Array] raster size
|
20
|
+
def size
|
21
|
+
@size ||= raster_size
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Runs the gdalinfo command and returns the result as a string.
|
27
|
+
# @param path [String] path to raster file
|
28
|
+
# @return [String] output of gdalinfo
|
29
|
+
def gdalinfo(path)
|
30
|
+
stdout, _stderr, _status = Open3.capture3("gdalinfo -mm #{path}")
|
31
|
+
stdout
|
32
|
+
end
|
33
|
+
|
34
|
+
# Given an output string from the gdalinfo command, returns
|
35
|
+
# a formatted string for the computed min and max values.
|
36
|
+
# @return [String] computed min and max values
|
37
|
+
def raster_min_max
|
38
|
+
match = %r{(?<=Computed Min/Max=).*?(?=\s)}.match(doc)
|
39
|
+
match ? match[0].tr(',', ' ') : ''
|
40
|
+
end
|
41
|
+
|
42
|
+
# Given an output string from the gdalinfo command, returns
|
43
|
+
# an array containing the raster width and height as strings.
|
44
|
+
# @return [String] raster size
|
45
|
+
def raster_size
|
46
|
+
match = /(?<=Size is ).*/.match(doc)
|
47
|
+
match ? match[0].tr(',', '') : ''
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -4,63 +4,37 @@ module GeoConcerns
|
|
4
4
|
class Base < Hydra::Derivatives::Processors::Processor
|
5
5
|
include Hydra::Derivatives::Processors::ShellBasedProcessor
|
6
6
|
include GeoConcerns::Processors::BaseGeoProcessor
|
7
|
+
include GeoConcerns::Processors::Ogr
|
8
|
+
include GeoConcerns::Processors::Gdal
|
7
9
|
include GeoConcerns::Processors::Zip
|
8
10
|
|
9
11
|
def self.encode(path, options, output_file)
|
10
12
|
case options[:label]
|
11
13
|
when :thumbnail
|
12
|
-
encode_vector(path,
|
14
|
+
encode_vector(path, output_file, options)
|
13
15
|
when :display_vector
|
14
|
-
reproject_vector(path,
|
16
|
+
reproject_vector(path, output_file, options)
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
File.unlink(tiff_path)
|
23
|
-
File.unlink("#{out_path}.aux.xml")
|
20
|
+
# Set of commands to run to encode the vector thumbnail.
|
21
|
+
# @return [Array] set of command name symbols
|
22
|
+
def self.encode_queue
|
23
|
+
[:rasterize, :convert]
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
FileUtils.rm_rf(shapefile_path)
|
26
|
+
# Set of commands to run to reproject the vector.
|
27
|
+
# @return [Array] set of command name symbols
|
28
|
+
def self.reproject_queue
|
29
|
+
[:reproject, :zip]
|
31
30
|
end
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
# @param in_path [String] file input path
|
37
|
-
# #param options [Hash] creation options
|
38
|
-
# @param out_path [String] processor output file path
|
39
|
-
# @return [String] command for rasterizing vector dataset
|
40
|
-
def self.rasterize(in_path, options, out_path)
|
41
|
-
"gdal_rasterize -q -burn 0 -init 255 -ot Byte -ts "\
|
42
|
-
"#{options[:output_size]} -of GTiff #{in_path} #{out_path}"
|
32
|
+
def self.encode_vector(in_path, out_path, options)
|
33
|
+
run_commands(in_path, out_path, encode_queue, options)
|
43
34
|
end
|
44
35
|
|
45
|
-
|
46
|
-
|
47
|
-
#
|
48
|
-
# @param in_path [String] file input path
|
49
|
-
# #param options [Hash] creation options
|
50
|
-
# @param out_path [String] processor output file path
|
51
|
-
# @return [String] command for reprojecting vector data
|
52
|
-
def self.reproject(in_path, options, out_path)
|
53
|
-
"env SHAPE_ENCODING= ogr2ogr -q -nln #{options[:basename]} "\
|
54
|
-
"-f 'ESRI Shapefile' -t_srs #{options[:output_srid]} '#{out_path}' '#{in_path}'"
|
55
|
-
end
|
56
|
-
|
57
|
-
# Returns a path to an intermediate shape file directory.
|
58
|
-
#
|
59
|
-
# @param path [String] file path to base temp path on
|
60
|
-
# @return [String] tempfile path
|
61
|
-
def self.intermediate_shapefile_path(path)
|
62
|
-
ext = File.extname(path)
|
63
|
-
"#{File.dirname(path)}/#{File.basename(path, ext)}/"
|
36
|
+
def self.reproject_vector(in_path, out_path, options)
|
37
|
+
run_commands(in_path, out_path, reproject_queue, options)
|
64
38
|
end
|
65
39
|
end
|
66
40
|
end
|
@@ -8,9 +8,9 @@ module GeoConcerns
|
|
8
8
|
unzip(path, output_file) do |zip_path|
|
9
9
|
case options[:label]
|
10
10
|
when :thumbnail
|
11
|
-
encode_vector(zip_path,
|
11
|
+
encode_vector(zip_path, output_file, options)
|
12
12
|
when :display_vector
|
13
|
-
reproject_vector(zip_path,
|
13
|
+
reproject_vector(zip_path, output_file, options)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -7,10 +7,9 @@ module GeoConcerns
|
|
7
7
|
# Unzips a file, invokes a block, and then deletes the unzipped file(s).
|
8
8
|
# Use to wrap processor methods for geo file formats that
|
9
9
|
# are zipped before uploading.
|
10
|
-
#
|
11
10
|
# @param in_path [String] file input path
|
12
11
|
# @param output_file [String] processor output file path
|
13
|
-
def self.unzip(in_path, output_file)
|
12
|
+
def self.unzip(in_path, output_file, _options = {})
|
14
13
|
basename = File.basename(output_file, File.extname(output_file))
|
15
14
|
zip_out_path = "#{File.dirname(output_file)}/#{basename}_out"
|
16
15
|
execute "unzip -qq -j -d \"#{zip_out_path}\" \"#{in_path}\""
|
@@ -19,10 +18,9 @@ module GeoConcerns
|
|
19
18
|
end
|
20
19
|
|
21
20
|
# Zips a file or directory.
|
22
|
-
#
|
23
21
|
# @param in_path [String] file input path
|
24
22
|
# @param output_file [String] output zip file
|
25
|
-
def self.zip(in_path, output_file)
|
23
|
+
def self.zip(in_path, output_file, _options = {})
|
26
24
|
execute "zip -j -qq -r \"#{output_file}\" \"#{in_path}\""
|
27
25
|
end
|
28
26
|
end
|
data/geo_concerns.gemspec
CHANGED
@@ -18,19 +18,18 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency '
|
22
|
-
spec.add_dependency '
|
23
|
-
spec.add_dependency 'leaflet-rails'
|
21
|
+
spec.add_dependency 'curation_concerns', '~> 0.14.0.pre4'
|
22
|
+
spec.add_dependency 'leaflet-rails', '~> 0.7'
|
24
23
|
|
25
24
|
spec.add_development_dependency 'sqlite3'
|
26
25
|
spec.add_development_dependency 'rspec-rails'
|
27
|
-
spec.add_development_dependency 'engine_cart'
|
28
|
-
spec.add_development_dependency 'solr_wrapper'
|
26
|
+
spec.add_development_dependency 'engine_cart', '~> 0.8'
|
27
|
+
spec.add_development_dependency 'solr_wrapper', '~> 0.10'
|
29
28
|
spec.add_development_dependency 'fcrepo_wrapper', '~> 0.1'
|
30
29
|
spec.add_development_dependency 'pry-byebug'
|
31
30
|
spec.add_development_dependency 'database_cleaner', '< 1.1.0'
|
32
|
-
spec.add_development_dependency 'rubocop'
|
33
|
-
spec.add_development_dependency 'rubocop-rspec'
|
31
|
+
spec.add_development_dependency 'rubocop', '~> 0.39'
|
32
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 1.4.1'
|
34
33
|
spec.add_development_dependency 'factory_girl'
|
35
|
-
spec.add_development_dependency 'capybara'
|
34
|
+
spec.add_development_dependency 'capybara', '~> 2.7'
|
36
35
|
end
|
data/lib/geo_concerns/version.rb
CHANGED
@@ -22,4 +22,20 @@ describe CurationConcerns::ImageWorksController, type: :controller do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
describe '#create' do
|
27
|
+
let(:user) { FactoryGirl.create(:admin) }
|
28
|
+
before do
|
29
|
+
sign_in user
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when create is successful' do
|
33
|
+
let(:work) { FactoryGirl.create(:image_work, user: user) }
|
34
|
+
it 'creates an image work' do
|
35
|
+
allow(controller).to receive(:curation_concern).and_return(work)
|
36
|
+
post :create, image_work: { title: ['a title'] }
|
37
|
+
expect(response).to redirect_to main_app.curation_concerns_image_work_path(work)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
25
41
|
end
|
@@ -4,6 +4,7 @@ describe GeoConcerns::Processors::BaseGeoProcessor do
|
|
4
4
|
before do
|
5
5
|
class TestProcessor
|
6
6
|
include GeoConcerns::Processors::BaseGeoProcessor
|
7
|
+
include GeoConcerns::Processors::Gdal
|
7
8
|
def directives
|
8
9
|
end
|
9
10
|
|
@@ -22,19 +23,38 @@ describe GeoConcerns::Processors::BaseGeoProcessor do
|
|
22
23
|
let(:directives) { { format: 'png', size: '200x400' } }
|
23
24
|
let(:output_file) { 'output/geo.png' }
|
24
25
|
let(:file_name) { 'files/geo.tif' }
|
25
|
-
let(:options) { {
|
26
|
+
let(:options) { { output_size: '150 150' } }
|
27
|
+
|
28
|
+
describe '#run_commands' do
|
29
|
+
let(:method_queue) { [:translate, :warp, :compress] }
|
30
|
+
it 'calls the methods in the queue and cleans up temp files' do
|
31
|
+
expect(subject.class).to receive(:translate)
|
32
|
+
expect(subject.class).to receive(:warp)
|
33
|
+
expect(subject.class).to receive(:compress)
|
34
|
+
expect(FileUtils).to receive(:rm_rf).twice
|
35
|
+
subject.class.run_commands(file_name, output_file, method_queue, options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#convert' do
|
40
|
+
let(:image) { double }
|
26
41
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
42
|
+
before do
|
43
|
+
allow(MiniMagick::Image).to receive(:open).and_return(image)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'transforms the image and saves it as a jpeg' do
|
47
|
+
expect(image).to receive(:format).with('jpg')
|
48
|
+
expect(image).to receive(:combine_options)
|
49
|
+
expect(image).to receive(:write).with(output_file)
|
50
|
+
subject.class.convert(file_name, output_file, options)
|
31
51
|
end
|
32
52
|
end
|
33
53
|
|
34
|
-
describe '#
|
54
|
+
describe '#temp_path' do
|
35
55
|
it 'returns a path to a temporary file based on the input file' do
|
36
|
-
expect(subject.class.
|
37
|
-
.to include('
|
56
|
+
expect(subject.class.temp_path(output_file))
|
57
|
+
.to include('geo')
|
38
58
|
end
|
39
59
|
end
|
40
60
|
|
@@ -53,21 +73,6 @@ describe GeoConcerns::Processors::BaseGeoProcessor do
|
|
53
73
|
end
|
54
74
|
end
|
55
75
|
|
56
|
-
describe '#output_format' do
|
57
|
-
context 'when given jpg as a format' do
|
58
|
-
let(:directives) { { format: 'jpg' } }
|
59
|
-
it 'returns JPEG' do
|
60
|
-
expect(subject.output_format).to eq('JPEG')
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
context 'when given png as a format' do
|
65
|
-
it 'returns PNG' do
|
66
|
-
expect(subject.output_format).to eq('PNG')
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
76
|
describe '#output_size' do
|
72
77
|
context 'when given a size string with an x' do
|
73
78
|
it 'returns a size string with a space instead' do
|
@@ -99,8 +104,7 @@ describe GeoConcerns::Processors::BaseGeoProcessor do
|
|
99
104
|
|
100
105
|
describe '#options_for' do
|
101
106
|
it 'returns a hash that includes output size and format' do
|
102
|
-
expect(subject.options_for("a")).to include(:
|
103
|
-
:output_size,
|
107
|
+
expect(subject.options_for("a")).to include(:output_size,
|
104
108
|
:label,
|
105
109
|
:output_srid,
|
106
110
|
:basename)
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GeoConcerns::Processors::BaseGeoProcessor do
|
4
|
+
before do
|
5
|
+
class TestProcessor
|
6
|
+
include Hydra::Derivatives::Processors::ShellBasedProcessor
|
7
|
+
include GeoConcerns::Processors::Gdal
|
8
|
+
def directives
|
9
|
+
end
|
10
|
+
|
11
|
+
def source_path
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
allow(subject).to receive(:directives).and_return(directives)
|
16
|
+
allow(subject).to receive(:source_path).and_return(file_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
after { Object.send(:remove_const, :TestProcessor) }
|
20
|
+
|
21
|
+
subject { TestProcessor.new }
|
22
|
+
|
23
|
+
let(:directives) { { format: 'png', size: '200x400' } }
|
24
|
+
let(:output_file) { 'output/geo.png' }
|
25
|
+
let(:file_name) { 'files/geo.tif' }
|
26
|
+
let(:options) { { output_size: '150 150', output_srid: 'EPSG:4326' } }
|
27
|
+
|
28
|
+
describe '#translate' do
|
29
|
+
it 'executes a gdal_translate command' do
|
30
|
+
command = "gdal_translate -q -ot Byte -of GTiff \"files/geo.tif\" output/geo.png"
|
31
|
+
expect(subject.class).to receive(:execute).with command
|
32
|
+
subject.class.translate(file_name, output_file, options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#warp' do
|
37
|
+
it 'executes a reproject command' do
|
38
|
+
command = "gdalwarp -q -r bilinear -t_srs EPSG:4326 files/geo.tif output/geo.png -co 'COMPRESS=NONE'"
|
39
|
+
expect(subject.class).to receive(:execute).with command
|
40
|
+
subject.class.warp(file_name, output_file, options)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#compress' do
|
45
|
+
it 'returns a gdal_translate command with a compress option' do
|
46
|
+
command = "gdal_translate -q -ot Byte -a_srs EPSG:4326 files/geo.tif output/geo.png -co 'COMPRESS=LZW'"
|
47
|
+
expect(subject.class).to receive(:execute).with command
|
48
|
+
subject.class.compress(file_name, output_file, options)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#rasterize' do
|
53
|
+
it 'executes a rasterize command' do
|
54
|
+
command = "gdal_rasterize -q -burn 0 -init 255 -ot Byte -ts 150 150 -of GTiff files/geo.tif output/geo.png"
|
55
|
+
expect(subject.class).to receive(:execute).with command
|
56
|
+
subject.class.rasterize(file_name, output_file, options)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GeoConcerns::Processors::BaseGeoProcessor do
|
4
|
+
before do
|
5
|
+
class TestProcessor
|
6
|
+
include Hydra::Derivatives::Processors::ShellBasedProcessor
|
7
|
+
include GeoConcerns::Processors::Ogr
|
8
|
+
def directives
|
9
|
+
end
|
10
|
+
|
11
|
+
def source_path
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
allow(subject).to receive(:directives).and_return(directives)
|
16
|
+
allow(subject).to receive(:source_path).and_return(file_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
after { Object.send(:remove_const, :TestProcessor) }
|
20
|
+
|
21
|
+
subject { TestProcessor.new }
|
22
|
+
|
23
|
+
let(:directives) { { format: 'png', size: '200x400' } }
|
24
|
+
let(:output_file) { 'output/geo.png' }
|
25
|
+
let(:file_name) { 'files/geo.zip' }
|
26
|
+
let(:options) { { output_size: '150 150', output_srid: 'EPSG:4326' } }
|
27
|
+
|
28
|
+
describe '#reproject' do
|
29
|
+
it 'executes a reproject command' do
|
30
|
+
command = "env SHAPE_ENCODING= ogr2ogr -q -nln -f 'ESRI Shapefile' "\
|
31
|
+
"-t_srs EPSG:4326 'output/geo.png' 'files/geo.zip'"
|
32
|
+
expect(subject.class).to receive(:execute).with command
|
33
|
+
subject.class.reproject(file_name, output_file, options)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -3,8 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe GeoConcerns::Processors::Raster::Aig do
|
4
4
|
let(:output_file) { 'output/geo.png' }
|
5
5
|
let(:file_name) { 'files/aig.zip' }
|
6
|
-
let(:options) { {
|
7
|
-
output_size: '150 150',
|
6
|
+
let(:options) { { output_size: '150 150',
|
8
7
|
min_max: '2.054 11.717',
|
9
8
|
label: :thumbnail }
|
10
9
|
}
|
@@ -12,9 +11,17 @@ describe GeoConcerns::Processors::Raster::Aig do
|
|
12
11
|
subject { described_class.new(file_name, {}) }
|
13
12
|
|
14
13
|
describe '#translate' do
|
15
|
-
it '
|
16
|
-
|
17
|
-
|
14
|
+
it 'executes a gdal_translate command with scaling' do
|
15
|
+
command = "gdal_translate -scale 2.054 11.717 255 0 -q -ot Byte -of "\
|
16
|
+
"GTiff \"files/aig.zip\" output/geo.png"
|
17
|
+
expect(subject.class).to receive(:execute).with command
|
18
|
+
subject.class.translate(file_name, output_file, options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#reproject_queue' do
|
23
|
+
it 'returns an array of command name symbols' do
|
24
|
+
expect(subject.class.reproject_queue).to include :warp
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|