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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dd19ec74fed0ecc262ba3f2edd8e2023d49ae84a
4
- data.tar.gz: 3c8f983b7b6390540be758426c50e398b9726026
3
+ metadata.gz: d850f85f49b98f05f74464b49214d41d56e2d374
4
+ data.tar.gz: 156c5df7de4895edc978638b2ac909f072419ad9
5
5
  SHA512:
6
- metadata.gz: e50e69b852f8f347e2b1f13e521b074004bf605ca51c2711a87356f3b51bc782585f93aac6b7a50be653a05edeea418886e63d2e14d6ac2796498796171621b5
7
- data.tar.gz: e9f12811b2c8c7472dadf4cce7075ebc580db63ddca8e649fe58cffad0b283052f4a7d87a1d60fd34e9a47130925d7377044de416d9315571404bf0097ab3c77
6
+ metadata.gz: 13b2fd98b15f4532db299158a4839bca07c6f67454a9273997040a340baad74aa3be1ba56fe4e0c09a33a5e927b1a573776de3814615a78c5761d13559ef0cf0
7
+ data.tar.gz: df553728f7d7cb4bd8a478bcda5c203668b5d9112617540f7c9e68db927a954b0e80c50bdb52c0799874702acc10b8f6dcca45d3517b8cf0b3f6c2bcce8db4be
data/.rubocop.yml CHANGED
@@ -1,3 +1,5 @@
1
+ require: rubocop-rspec
2
+
1
3
  Rails:
2
4
  Enabled: true
3
5
 
data/README.md CHANGED
@@ -11,7 +11,12 @@ Rails application for developing Hydra Geo models. Built around Curation Concern
11
11
 
12
12
  ## Dependencies
13
13
 
14
- * [GDAL](http://www.gdal.org/)
14
+ 1. Solr
15
+ 1. [Fedora Commons](http://www.fedora-commons.org/) digital repository
16
+ 1. A SQL RDBMS (MySQL, PostgreSQL), though **note** that SQLite will be used by default if you're looking to get up and running quickly
17
+ 1. [Redis](http://redis.io/), a key-value store
18
+ 1. [ImageMagick](http://www.imagemagick.org/) with JPEG-2000 support
19
+ 1. [GDAL](http://www.gdal.org/)
15
20
  * You can install it on Mac OSX with `brew install gdal`.
16
21
  * On Ubuntu, use `sudo apt-get install gdal-bin`.
17
22
 
@@ -19,7 +19,7 @@ module GeoConcerns
19
19
  def image_derivatives(filename)
20
20
  Hydra::Derivatives::ImageDerivatives
21
21
  .create(filename, outputs: [{ label: :thumbnail,
22
- format: 'png',
22
+ format: 'jpg',
23
23
  size: '200x150>',
24
24
  url: derivative_url('thumbnail') }])
25
25
  end
@@ -32,8 +32,8 @@ module GeoConcerns
32
32
  url: derivative_url('display_raster') },
33
33
  { input_format: mime_type,
34
34
  label: :thumbnail,
35
- format: 'png',
36
- size: '150x150',
35
+ format: 'jpg',
36
+ size: '200x150',
37
37
  url: derivative_url('thumbnail') }])
38
38
  end
39
39
 
@@ -45,8 +45,8 @@ module GeoConcerns
45
45
  url: derivative_url('display_vector') },
46
46
  { input_format: mime_type,
47
47
  label: :thumbnail,
48
- format: 'png',
49
- size: '150x150',
48
+ format: 'jpg',
49
+ size: '200x150',
50
50
  url: derivative_url('thumbnail') }])
51
51
  end
52
52
 
@@ -6,7 +6,7 @@ module GeoConcerns
6
6
  # Retrieve the Image Work of which this Object is a member
7
7
  # @return [GeoConcerns::ImageWork]
8
8
  def image_work
9
- generic_works.select do |parent|
9
+ parents.select do |parent|
10
10
  parent.class.included_modules.include?(::GeoConcerns::ImageWorkBehavior)
11
11
  end.to_a
12
12
  end
@@ -6,7 +6,7 @@ module GeoConcerns
6
6
  # Retrieve the Raster Work of which this Object is a member
7
7
  # @return [GeoConcerns::Raster]
8
8
  def raster_work
9
- generic_works.select do |parent|
9
+ parents.select do |parent|
10
10
  parent.class.included_modules.include?(::GeoConcerns::RasterWorkBehavior)
11
11
  end.to_a
12
12
  end
@@ -6,7 +6,7 @@ module GeoConcerns
6
6
  # Retrieve the Vector Work of which this Object is a member
7
7
  # @return [GeoConcerns::VectorWork]
8
8
  def vector_work
9
- generic_works.select do |parent|
9
+ parents.select do |parent|
10
10
  parent.class.included_modules.include?(::GeoConcerns::VectorWorkBehavior)
11
11
  end.to_a
12
12
  end
@@ -1,36 +1,66 @@
1
+ require 'mini_magick'
2
+
1
3
  module GeoConcerns
2
4
  module Processors
3
5
  module BaseGeoProcessor
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  included do
7
- # Returns a formatted gdal_translate command. Used to translate a raster
8
- # format into a different format. Also used in generating thumbnails
9
- # from vector data.
9
+ # Chains together and recursively runs a set of commands.
10
+ # Except for the last command in the queue, a temp file
11
+ # is created as output and is then fed into the input of the next.
12
+ # Temp files are deleted in reverse order after the last command
13
+ # is run. The commands must have the same method signature:
14
+ # command_name(in_path, out_path, options)
10
15
  #
11
16
  # @param in_path [String] file input path
12
- # #param options [Hash] creation options
13
17
  # @param out_path [String] processor output file path
14
- # @return [String] command for transforming a raster dataset
15
- def self.translate(in_path, options, out_path)
16
- "gdal_translate -outsize #{options[:output_size]} -q -ot Byte "\
17
- "-of #{options[:output_format]} \"#{in_path}\" #{out_path}"
18
+ # @param method_queue [Array] set of commands to run
19
+ # @param options [Hash] creation options to pass
20
+ def self.run_commands(in_path, out_path, method_queue, options)
21
+ next_step = method_queue.shift
22
+ if method_queue.empty?
23
+ method(next_step).call(in_path, out_path, options)
24
+ else
25
+ temp = temp_path(out_path)
26
+ method(next_step).call(in_path, temp, options)
27
+ run_commands(temp, out_path, method_queue, options)
28
+ FileUtils.rm_rf(temp)
29
+ end
18
30
  end
19
31
 
20
- # Returns a path to an intermediate temp file.
21
- #
32
+ # Returns a path to an intermediate temp file or directory.
22
33
  # @param path [String] input file path to base temp path on
23
34
  # @return [String] tempfile path
24
- def self.intermediate_file_path(path)
25
- ext = File.extname(path)
26
- "#{File.dirname(path)}/#{File.basename(path, ext)}_temp#{ext}"
35
+ def self.temp_path(path)
36
+ time = (Time.now.to_f * 1000).to_i
37
+ "#{File.dirname(path)}/#{File.basename(path, File.extname(path))}_#{time}"
38
+ end
39
+
40
+ # Uses imagemagick to resize an image and convert it to jpeg format.
41
+ # Keeps the aspect ratio of the original image and adds padding to
42
+ # to the ouput image.
43
+ # @param in_path [String] file input path
44
+ # @param out_path [String] processor output file path
45
+ # @param options [Hash] creation options
46
+ def self.convert(in_path, out_path, options)
47
+ size = options[:output_size].tr(' ', 'x')
48
+ # byebug
49
+ image = MiniMagick::Image.open(in_path)
50
+ image.format 'jpg'
51
+ image.combine_options do |i|
52
+ i.resize size
53
+ i.background 'white'
54
+ i.gravity 'center'
55
+ i.extent size
56
+ end
57
+ image.write(out_path)
27
58
  end
28
59
  end
29
60
 
30
61
  def options_for(_format)
31
62
  {
32
63
  label: label,
33
- output_format: output_format,
34
64
  output_size: output_size,
35
65
  output_srid: output_srid,
36
66
  basename: basename
@@ -38,29 +68,12 @@ module GeoConcerns
38
68
  end
39
69
 
40
70
  # Returns the label directive or an empty string.
41
- #
42
71
  # @return [Sting] output label
43
72
  def label
44
73
  directives.fetch(:label, '')
45
74
  end
46
75
 
47
- # Tranforms the format directive into a GDAL output format.
48
- #
49
- # @return [Sting] derivative output format
50
- def output_format
51
- format = directives.fetch(:format, '').upcase
52
- case format
53
- when 'JPG'
54
- 'JPEG'
55
- when 'TIF'
56
- 'GTiff'
57
- else
58
- format
59
- end
60
- end
61
-
62
76
  # Tranforms the size directive into a GDAL size parameter.
63
- #
64
77
  # @return [String] derivative size
65
78
  def output_size
66
79
  return unless directives[:size]
@@ -68,15 +81,12 @@ module GeoConcerns
68
81
  end
69
82
 
70
83
  # Gets srid for reprojection derivative or returns WGS 84.
71
- #
72
84
  # @return [String] spatial reference code
73
85
  def output_srid
74
86
  directives.fetch(:srid, 'EPSG:4326')
75
- # directives[:srid] ? directives[:srid] : 'EPSG:4326'
76
87
  end
77
88
 
78
89
  # Extracts the base file name (without extension) from the source file path.
79
- #
80
90
  # @return [String] base file name for source
81
91
  def basename
82
92
  File.basename(source_path, File.extname(source_path))
@@ -0,0 +1,49 @@
1
+ module GeoConcerns
2
+ module Processors
3
+ module Gdal
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # Executes a gdal_translate command. Used to translate a raster
8
+ # format into a different format. Also used in generating thumbnails
9
+ # from vector data.
10
+ # @param in_path [String] file input path
11
+ # @param out_path [String] processor output file path
12
+ # @param options [Hash] creation options
13
+ def self.translate(in_path, out_path, _options)
14
+ execute "gdal_translate -q -ot Byte -of GTiff \"#{in_path}\" #{out_path}"
15
+ end
16
+
17
+ # Executes a gdalwarp command. Used to transform a raster
18
+ # from one projection into another.
19
+ # @param in_path [String] file input path
20
+ # @param out_path [String] processor output file path
21
+ # @param options [Hash] creation options
22
+ def self.warp(in_path, out_path, options)
23
+ execute "gdalwarp -q -r bilinear -t_srs #{options[:output_srid]} "\
24
+ "#{in_path} #{out_path} -co 'COMPRESS=NONE'"
25
+ end
26
+
27
+ # Executes a gdal_translate command. Used to compress
28
+ # a previously uncompressed raster.
29
+ # @param in_path [String] file input path
30
+ # @param out_path [String] processor output file path
31
+ # @param options [Hash] creation options
32
+ def self.compress(in_path, out_path, options)
33
+ execute "gdal_translate -q -ot Byte -a_srs #{options[:output_srid]} "\
34
+ "#{in_path} #{out_path} -co 'COMPRESS=LZW'"
35
+ end
36
+
37
+ # Executes a gdal_rasterize command. Used to rasterize vector
38
+ # format into raster format.
39
+ # @param in_path [String] file input path
40
+ # #param options [Hash] creation options
41
+ # @param out_path [String] processor output file path
42
+ def self.rasterize(in_path, out_path, options)
43
+ execute "gdal_rasterize -q -burn 0 -init 255 -ot Byte -ts "\
44
+ "#{options[:output_size]} -of GTiff #{in_path} #{out_path}"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ module GeoConcerns
2
+ module Processors
3
+ module Ogr
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # Executes a ogr2ogr command. Used to reproject a
8
+ # vector dataset and save the output as a shapefile
9
+ # @param in_path [String] file input path
10
+ # #param options [Hash] creation options
11
+ # @param out_path [String] processor output file path
12
+ def self.reproject(in_path, out_path, options)
13
+ execute "env SHAPE_ENCODING= ogr2ogr -q -nln #{options[:basename]} -f 'ESRI Shapefile'"\
14
+ " -t_srs #{options[:output_srid]} '#{out_path}' '#{in_path}'"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -6,37 +6,33 @@ module GeoConcerns
6
6
 
7
7
  def self.encode(path, options, output_file)
8
8
  unzip(path, output_file) do |zip_path|
9
- info = gdalinfo(zip_path)
10
- options[:min_max] = get_raster_min_max(info)
9
+ info = Info.new(zip_path)
10
+ options[:min_max] = info.min_max
11
11
  case options[:label]
12
12
  when :thumbnail
13
- encode_raster(zip_path, options, output_file)
13
+ encode_raster(zip_path, output_file, options)
14
14
  when :display_raster
15
- reproject_raster(zip_path, options, output_file)
15
+ reproject_raster(zip_path, output_file, options)
16
16
  end
17
17
  end
18
18
  end
19
19
 
20
- def self.reproject_raster(in_path, options, out_path)
21
- options[:output_size] = '100% 100%'
22
- intermediate_file = intermediate_file_path(out_path)
23
- execute warp(in_path, options, intermediate_file)
24
- execute translate(intermediate_file, options, out_path)
25
- FileUtils.rm_rf(intermediate_file)
20
+ # Set of commands to run to reproject the AIG.
21
+ # @return [Array] set of command name symbols
22
+ def self.reproject_queue
23
+ [:warp, :translate]
26
24
  end
27
25
 
28
- # Returns a formatted gdal_translate command to translate a raster
26
+ # Executes a gdal_translate command to translate a raster
29
27
  # format into a different format with a scaling options. This command
30
28
  # scales the min and max values of the raster into the 0 to 255 range.
31
29
  # Scale is inverted (255 to 0) to create a better visualization.
32
- #
33
30
  # @param in_path [String] file input path
34
- # #param options [Hash] creation options
35
31
  # @param out_path [String] processor output file path
36
- # @return [String] command for tranforming a usgs dem dataset
37
- def self.translate(in_path, options, out_path)
38
- "gdal_translate -scale #{options[:min_max]} 255 0 -outsize #{options[:output_size]} "\
39
- "-q -ot Byte -of #{options[:output_format]} \"#{in_path}\" #{out_path}"
32
+ # @param options [Hash] creation options
33
+ def self.translate(in_path, out_path, options)
34
+ execute "gdal_translate -scale #{options[:min_max]} 255 0 "\
35
+ "-q -ot Byte -of GTiff \"#{in_path}\" #{out_path}"
40
36
  end
41
37
  end
42
38
  end
@@ -4,69 +4,35 @@ 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::Gdal
7
8
 
8
9
  def self.encode(path, options, output_file)
9
10
  case options[:label]
10
11
  when :thumbnail
11
- encode_raster(path, options, output_file)
12
+ encode_raster(path, output_file, options)
12
13
  when :display_raster
13
- reproject_raster(path, options, output_file)
14
+ reproject_raster(path, output_file, options)
14
15
  end
15
16
  end
16
17
 
17
- def self.encode_raster(in_path, options, out_path)
18
- execute translate(in_path, options, out_path)
19
- File.unlink("#{out_path}.aux.xml")
18
+ # Set of commands to run to encode the raster thumbnail.
19
+ # @return [Array] set of command name symbols
20
+ def self.encode_queue
21
+ [:translate, :convert]
20
22
  end
21
23
 
22
- def self.reproject_raster(in_path, options, out_path)
23
- intermediate_file = intermediate_file_path(out_path)
24
- execute warp(in_path, options, intermediate_file)
25
- execute compress(intermediate_file, options, out_path)
26
- FileUtils.rm_rf(intermediate_file)
24
+ # Set of commands to run to reproject the raster.
25
+ # @return [Array] set of command name symbols
26
+ def self.reproject_queue
27
+ [:warp, :compress]
27
28
  end
28
29
 
29
- # Returns a formatted gdalwarp. Used to transform a raster
30
- # from one projection into another.
31
- #
32
- # @param in_path [String] file input path
33
- # #param options [Hash] creation options
34
- # @param out_path [String] processor output file path
35
- # @return [String] command for reprojecting a raster
36
- def self.warp(in_path, options, out_path)
37
- "gdalwarp -q -r bilinear -t_srs #{options[:output_srid]} "\
38
- " #{in_path} #{out_path} -co 'COMPRESS=NONE'"
30
+ def self.encode_raster(in_path, out_path, options)
31
+ run_commands(in_path, out_path, encode_queue, options)
39
32
  end
40
33
 
41
- # Returns a formatted gdal_translate command. Used compress
42
- # an previously uncompressed raster.
43
- #
44
- # @param in_path [String] file input path
45
- # #param options [Hash] creation options
46
- # @param out_path [String] processor output file path
47
- # @return [String] command for compressing a raster dataset
48
- def self.compress(in_path, options, out_path)
49
- "gdal_translate -q -ot Byte -a_srs #{options[:output_srid]} "\
50
- "\"#{in_path}\" #{out_path} -co 'COMPRESS=LZW'"
51
- end
52
-
53
- # Given an output string from the gdalinfo command, returns
54
- # a formatted string for the computed min and max values.
55
- #
56
- # @param info_string [String] ouput from gdalinfo
57
- # @return [String] computed min and max values
58
- def self.get_raster_min_max(info_string)
59
- match = %r{(?<=Computed Min/Max=).*?(?=\s)}.match(info_string)
60
- match ? match[0].tr(',', ' ') : ''
61
- end
62
-
63
- # Runs the gdalinfo command and returns the result as a string.
64
- #
65
- # @param path [String] path to raster file
66
- # @return [String] output of gdalinfo
67
- def self.gdalinfo(path)
68
- stdout, _stderr, _status = Open3.capture3("gdalinfo -mm #{path}")
69
- stdout
34
+ def self.reproject_raster(in_path, out_path, options)
35
+ run_commands(in_path, out_path, reproject_queue, options)
70
36
  end
71
37
  end
72
38
  end
@@ -2,43 +2,26 @@ module GeoConcerns
2
2
  module Processors
3
3
  module Raster
4
4
  class Dem < GeoConcerns::Processors::Raster::Base
5
- def self.encode_raster(in_path, options, out_path)
6
- intermediate_file = intermediate_file_path(out_path)
7
- execute translate(in_path, options, intermediate_file)
8
- execute hillshade(intermediate_file, options, out_path)
9
- FileUtils.rm_rf(intermediate_file)
10
- File.unlink("#{out_path}.aux.xml")
5
+ # Set of commands to run to encode the DEM thumbnail.
6
+ # @return [Array] set of command name symbols
7
+ def self.encode_queue
8
+ [:hillshade, :convert]
11
9
  end
12
10
 
13
- def self.reproject_raster(in_path, options, out_path)
14
- intermediate_file = intermediate_file_path(out_path)
15
- execute hillshade(in_path, options, intermediate_file)
16
- execute warp(intermediate_file, options, out_path)
17
- FileUtils.rm_rf(intermediate_file)
11
+ # Set of commands to run to reproject the DEM.
12
+ # @return [Array] set of command name symbols
13
+ def self.reproject_queue
14
+ [:hillshade, :warp]
18
15
  end
19
16
 
20
- # Returns a formatted gdal_translate command to translate a vector
21
- # in USGS DEM format into a different format.
22
- #
23
- # @param in_path [String] file input path
24
- # #param options [Hash] creation options
25
- # @param out_path [String] processor output file path
26
- # @return [String] command for tranforming a usgs dem dataset
27
- def self.translate(in_path, options, out_path)
28
- "gdal_translate -outsize #{options[:output_size]} -q -ot Byte "\
29
- "-of USGSDEM #{in_path} #{out_path}"
30
- end
31
-
32
- # Returns a formatted gdal hillshade command. Calculates hillshade
17
+ # Executes a gdal hillshade command. Calculates hillshade
33
18
  # on a raster that contains elevation data.
34
- #
35
19
  # @param in_path [String] file input path
36
- # #param options [Hash] creation options
37
- # @param output_file [String] processor output file path
38
- # @return [String] command for generating a hillshade
39
- def self.hillshade(in_path, options, out_path)
40
- "gdaldem hillshade -q "\
41
- "-of #{options[:output_format]} \"#{in_path}\" #{out_path}"
20
+ # @param out_path [String] processor output file path
21
+ # @param options [Hash] creation options
22
+ def self.hillshade(in_path, out_path, _options)
23
+ execute "gdaldem hillshade -q "\
24
+ "-of GTiff \"#{in_path}\" #{out_path}"
42
25
  end
43
26
  end
44
27
  end