geo_concerns 0.0.1 → 0.0.2

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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/README.md +6 -1
  4. data/app/models/concerns/geo_concerns/file_set/derivatives.rb +5 -5
  5. data/app/models/concerns/geo_concerns/image_file_behavior.rb +1 -1
  6. data/app/models/concerns/geo_concerns/raster_file_behavior.rb +1 -1
  7. data/app/models/concerns/geo_concerns/vector_file_behavior.rb +1 -1
  8. data/app/processors/geo_concerns/processors/base_geo_processor.rb +44 -34
  9. data/app/processors/geo_concerns/processors/gdal.rb +49 -0
  10. data/app/processors/geo_concerns/processors/ogr.rb +19 -0
  11. data/app/processors/geo_concerns/processors/raster/aig.rb +13 -17
  12. data/app/processors/geo_concerns/processors/raster/base.rb +15 -49
  13. data/app/processors/geo_concerns/processors/raster/dem.rb +14 -31
  14. data/app/processors/geo_concerns/processors/raster/info.rb +52 -0
  15. data/app/processors/geo_concerns/processors/raster/processor.rb +0 -1
  16. data/app/processors/geo_concerns/processors/vector/base.rb +16 -42
  17. data/app/processors/geo_concerns/processors/vector/processor.rb +0 -1
  18. data/app/processors/geo_concerns/processors/vector/shapefile.rb +2 -2
  19. data/app/processors/geo_concerns/processors/zip.rb +2 -4
  20. data/geo_concerns.gemspec +7 -8
  21. data/lib/geo_concerns/version.rb +1 -1
  22. data/spec/controllers/image_works_controller_spec.rb +16 -0
  23. data/spec/processors/geo_concerns/processors/base_geo_processor_spec.rb +29 -25
  24. data/spec/processors/geo_concerns/processors/gdal_spec.rb +59 -0
  25. data/spec/processors/geo_concerns/processors/ogr_spec.rb +36 -0
  26. data/spec/processors/geo_concerns/processors/raster/aig_spec.rb +12 -5
  27. data/spec/processors/geo_concerns/processors/raster/base_spec.rb +15 -47
  28. data/spec/processors/geo_concerns/processors/raster/dem_spec.rb +14 -10
  29. data/spec/processors/geo_concerns/processors/raster/info_spec.rb +35 -0
  30. data/spec/processors/geo_concerns/processors/vector/base_spec.rb +15 -28
  31. data/spec/processors/geo_concerns/processors/vector/shapefile_spec.rb +1 -1
  32. 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
@@ -9,7 +9,6 @@ module GeoConcerns
9
9
  end
10
10
 
11
11
  # Returns a raster processor class based on mime type passed in the directives object.
12
- #
13
12
  # @return raster processing class
14
13
  def raster_processor_class
15
14
  case directives.fetch(:input_format)
@@ -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, options, output_file)
14
+ encode_vector(path, output_file, options)
13
15
  when :display_vector
14
- reproject_vector(path, options, output_file)
16
+ reproject_vector(path, output_file, options)
15
17
  end
16
18
  end
17
19
 
18
- def self.encode_vector(in_path, options, out_path)
19
- tiff_path = "#{File.dirname(in_path)}/out.tif"
20
- execute rasterize(in_path, options, tiff_path)
21
- execute translate(tiff_path, options, out_path)
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
- def self.reproject_vector(in_path, options, out_path)
27
- shapefile_path = intermediate_shapefile_path(out_path)
28
- execute reproject(in_path, options, shapefile_path)
29
- zip(shapefile_path, out_path)
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
- # Returns a formatted gdal_rasterize command. Used to rasterize vector
34
- # format into raster format.
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
- # Returns a formatted ogr2ogr command. Used to reproject a
46
- # vector dataset and save the output as a shapefile.
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
@@ -9,7 +9,6 @@ module GeoConcerns
9
9
  end
10
10
 
11
11
  # Returns a vector processor class based on mime type passed in the directives object.
12
- #
13
12
  # @return vector processing class
14
13
  def vector_processor_class
15
14
  case directives.fetch(:input_format)
@@ -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, options, output_file)
11
+ encode_vector(zip_path, output_file, options)
12
12
  when :display_vector
13
- reproject_vector(zip_path, options, output_file)
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 'rails', '~> 4.2.6'
22
- spec.add_dependency 'curation_concerns', '~> 0.14.0.pre1'
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
@@ -1,3 +1,3 @@
1
1
  module GeoConcerns
2
- VERSION = "0.0.1".freeze
2
+ VERSION = "0.0.2".freeze
3
3
  end
@@ -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) { { output_format: 'PNG', output_size: '150 150' } }
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
- describe '#translate' do
28
- it 'returns a gdal_translate command ' do
29
- expect(subject.class.translate(file_name, options, output_file))
30
- .to include('gdal_translate')
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 '#intermediate_file_path' do
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.intermediate_file_path(output_file))
37
- .to include('geo_temp.png')
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(:output_format,
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) { { output_format: 'PNG',
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 'returns a gdal_translate command with scaling' do
16
- expect(subject.class.translate(file_name, options, output_file))
17
- .to include('-scale 2.054 11.717 255 0')
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