riiif 1.7.1 → 2.0.0.beta1

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +15 -41
  3. data/Gemfile +1 -37
  4. data/app/models/riiif/file.rb +19 -12
  5. data/app/models/riiif/image.rb +13 -12
  6. data/app/models/riiif/image_information.rb +4 -0
  7. data/app/models/riiif/transformation.rb +35 -0
  8. data/{lib → app/resolvers}/riiif/abstract_file_system_resolver.rb +0 -0
  9. data/{lib → app/resolvers}/riiif/akubra_system_file_resolver.rb +0 -0
  10. data/{lib → app/resolvers}/riiif/file_system_file_resolver.rb +0 -0
  11. data/{lib → app/resolvers}/riiif/http_file_resolver.rb +0 -0
  12. data/app/services/riiif/command_runner.rb +2 -0
  13. data/app/services/riiif/crop.rb +54 -0
  14. data/app/services/riiif/imagemagick_command_factory.rb +20 -19
  15. data/app/services/riiif/imagemagick_transformer.rb +8 -0
  16. data/app/services/riiif/kakadu_command_factory.rb +63 -0
  17. data/app/services/riiif/link_name_service.rb +8 -0
  18. data/{lib → app/services}/riiif/nil_authorization_service.rb +0 -0
  19. data/app/services/riiif/option_decoder.rb +11 -11
  20. data/app/services/riiif/region/absolute.rb +23 -0
  21. data/app/services/riiif/region/full.rb +23 -0
  22. data/app/services/riiif/region/percentage.rb +68 -0
  23. data/app/services/riiif/region/square.rb +45 -0
  24. data/app/services/riiif/resize.rb +45 -0
  25. data/app/services/riiif/size/absolute.rb +39 -0
  26. data/app/services/riiif/size/best_fit.rb +18 -0
  27. data/app/services/riiif/size/full.rb +17 -0
  28. data/app/services/riiif/size/height.rb +24 -0
  29. data/app/services/riiif/size/percent.rb +44 -0
  30. data/app/services/riiif/size/width.rb +24 -0
  31. data/app/transformers/riiif/abstract_transformer.rb +30 -0
  32. data/app/transformers/riiif/imagemagick_transformer.rb +8 -0
  33. data/app/transformers/riiif/kakadu_transformer.rb +39 -0
  34. data/lib/riiif.rb +4 -7
  35. data/lib/riiif/engine.rb +4 -3
  36. data/lib/riiif/version.rb +1 -1
  37. data/riiif.gemspec +1 -1
  38. data/spec/models/riiif/image_spec.rb +6 -3
  39. data/spec/models/riiif/transformation_spec.rb +42 -0
  40. data/spec/services/riiif/imagemagick_command_factory_spec.rb +6 -4
  41. data/spec/services/riiif/kakadu_command_factory_spec.rb +85 -0
  42. data/spec/services/riiif/region/absolute_spec.rb +17 -0
  43. data/spec/services/riiif/size/absolute_spec.rb +17 -0
  44. data/spec/services/riiif/size/height_spec.rb +13 -0
  45. data/spec/services/riiif/size/width_spec.rb +13 -0
  46. data/spec/transformers/riiif/kakadu_transformer_spec.rb +143 -0
  47. metadata +45 -22
  48. data/app/services/riiif/region/imagemagick/absolute_decoder.rb +0 -21
  49. data/app/services/riiif/region/imagemagick/full_decoder.rb +0 -14
  50. data/app/services/riiif/region/imagemagick/percentage_decoder.rb +0 -33
  51. data/app/services/riiif/region/imagemagick/square_decoder.rb +0 -25
  52. data/app/services/riiif/size/imagemagick/absolute_decoder.rb +0 -20
  53. data/app/services/riiif/size/imagemagick/best_fit_decoder.rb +0 -19
  54. data/app/services/riiif/size/imagemagick/full_decoder.rb +0 -14
  55. data/app/services/riiif/size/imagemagick/height_decoder.rb +0 -19
  56. data/app/services/riiif/size/imagemagick/percent_decoder.rb +0 -19
  57. data/app/services/riiif/size/imagemagick/width_decoder.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b906efd99f3e05a2fd678fc4f94f7d91c97c726b
4
- data.tar.gz: 157ee4a7c84affe1bc6816ad8d22c1bfade9ae9c
3
+ metadata.gz: cd3265a72519ab497b58fcd9314509a8bac800c4
4
+ data.tar.gz: 51c4d65cd6e0488a5ae225cb7c3d9917fd427033
5
5
  SHA512:
6
- metadata.gz: d5ec226ff4794db61495802d724cdbb40adcf0f412b44d413f343e2755c0700790de1e84c429c6ab983bf103b5ea8fb68c4ffdfe4f5a546b134467524236dc54
7
- data.tar.gz: 07e3b30f166d5f6e944ed7a785b504970e1e970284fe71a85939337c0dca115660f91b9ff05bbc6b717a06392a142db26d09862fba16ebbe677bd09e415a7681
6
+ metadata.gz: 28447a5eadf4b943759bc3cf3df145aacff7a122528438b2f542779ad8ac06ab6ab1da4567d2cebaeea6d8148b92a3c895b2d077c2c5bee1eaee1a966df2eb8e
7
+ data.tar.gz: c0b443453bdfe6935f146fd7afa7b2377c239a189888660756406245746aba906a85bdb0c17e22c7d608b4e4fcc3e96901a05e9b8e54c543c1712fcd7bf8e224
data/.rubocop_todo.yml CHANGED
@@ -1,33 +1,18 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2018-05-14 11:34:53 -0500 using RuboCop version 0.47.1.
3
+ # on 2017-04-11 15:07:00 -0500 using RuboCop version 0.47.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 2
10
- # Configuration parameters: Include.
11
- # Include: **/Gemfile, **/gems.rb
12
- Bundler/DuplicatedGem:
13
- Exclude:
14
- - 'Gemfile'
15
-
16
- # Offense count: 1
17
- # Cop supports --auto-correct.
18
- # Configuration parameters: Include.
19
- # Include: **/Gemfile, **/gems.rb
20
- Bundler/OrderedGems:
21
- Exclude:
22
- - 'Gemfile'
23
-
24
9
  # Offense count: 9
25
10
  # Configuration parameters: AllowSafeAssignment.
26
11
  Lint/AssignmentInCondition:
27
12
  Exclude:
28
13
  - 'app/models/riiif/file.rb'
29
14
  - 'app/services/riiif/option_decoder.rb'
30
- - 'lib/riiif/http_file_resolver.rb'
15
+ - 'app/resolvers/riiif/http_file_resolver.rb'
31
16
 
32
17
  # Offense count: 1
33
18
  Lint/HandleExceptions:
@@ -39,7 +24,7 @@ Lint/UselessAssignment:
39
24
  Exclude:
40
25
  - 'app/models/riiif/file.rb'
41
26
 
42
- # Offense count: 6
27
+ # Offense count: 5
43
28
  Metrics/AbcSize:
44
29
  Max: 29
45
30
 
@@ -47,17 +32,21 @@ Metrics/AbcSize:
47
32
  Metrics/CyclomaticComplexity:
48
33
  Max: 8
49
34
 
50
- # Offense count: 103
35
+ # Offense count: 96
51
36
  # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
52
37
  # URISchemes: http, https
53
38
  Metrics/LineLength:
54
- Max: 153
39
+ Max: 117
55
40
 
56
41
  # Offense count: 6
57
42
  # Configuration parameters: CountComments.
58
43
  Metrics/MethodLength:
59
44
  Max: 18
60
45
 
46
+ Metrics/ParameterLists:
47
+ Exclude:
48
+ - 'app/services/riiif/imagemagick_command_factory.rb'
49
+
61
50
  # Offense count: 1
62
51
  # Configuration parameters: EnforcedStyle, SupportedStyles.
63
52
  # SupportedStyles: nested, compact
@@ -65,7 +54,7 @@ Style/ClassAndModuleChildren:
65
54
  Exclude:
66
55
  - 'lib/riiif/rails/routes.rb'
67
56
 
68
- # Offense count: 13
57
+ # Offense count: 14
69
58
  Style/Documentation:
70
59
  Exclude:
71
60
  - 'spec/**/*'
@@ -73,27 +62,12 @@ Style/Documentation:
73
62
  - 'app/controllers/riiif/images_controller.rb'
74
63
  - 'app/models/riiif/file.rb'
75
64
  - 'app/models/riiif/image.rb'
65
+ - 'app/resolvers/riiif/abstract_file_system_resolver.rb'
66
+ - 'app/resolvers/riiif/akubra_system_file_resolver.rb'
67
+ - 'app/resolvers/riiif/file_system_file_resolver.rb'
68
+ - 'app/resolvers/riiif/http_file_resolver.rb'
69
+ - 'app/services/riiif/nil_authorization_service.rb'
76
70
  - 'lib/riiif.rb'
77
- - 'lib/riiif/abstract_file_system_resolver.rb'
78
- - 'lib/riiif/akubra_system_file_resolver.rb'
79
71
  - 'lib/riiif/engine.rb'
80
- - 'lib/riiif/file_system_file_resolver.rb'
81
- - 'lib/riiif/http_file_resolver.rb'
82
- - 'lib/riiif/nil_authorization_service.rb'
83
72
  - 'lib/riiif/rails/routes.rb'
84
73
  - 'lib/riiif/routes.rb'
85
-
86
- # Offense count: 1
87
- # Cop supports --auto-correct.
88
- # Configuration parameters: AllowForAlignment.
89
- Style/SpaceAroundOperators:
90
- Exclude:
91
- - 'Gemfile'
92
-
93
- # Offense count: 1
94
- # Cop supports --auto-correct.
95
- # Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline.
96
- # SupportedStyles: single_quotes, double_quotes
97
- Style/StringLiterals:
98
- Exclude:
99
- - 'Gemfile'
data/Gemfile CHANGED
@@ -1,41 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'byebug'
3
4
  # Specify your gem's dependencies in riiif.gemspec
4
5
  gemspec
5
-
6
- ENV['ENGINE_CART_RAILS_OPTIONS']="--skip-bootsnap"
7
-
8
- # BEGIN ENGINE_CART BLOCK
9
- # engine_cart: 2.0.1
10
- # engine_cart stanza: 0.10.0
11
- # the below comes from engine_cart, a gem used to test this Rails engine gem in the context of a Rails app.
12
- file = File.expand_path('Gemfile', ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path('.internal_test_app', File.dirname(__FILE__)))
13
- if File.exist?(file)
14
- begin
15
- eval_gemfile file
16
- rescue Bundler::GemfileError => e
17
- Bundler.ui.warn '[EngineCart] Skipping Rails application dependencies:'
18
- Bundler.ui.warn e.message
19
- end
20
- else
21
- Bundler.ui.warn "[EngineCart] Unable to find test application dependencies in #{file}, using placeholder dependencies"
22
-
23
- if ENV['RAILS_VERSION']
24
- if ENV['RAILS_VERSION'] == 'edge'
25
- gem 'rails', github: 'rails/rails'
26
- ENV['ENGINE_CART_RAILS_OPTIONS'] = '--edge --skip-turbolinks'
27
- else
28
- gem 'rails', ENV['RAILS_VERSION']
29
- end
30
- end
31
-
32
- case ENV['RAILS_VERSION']
33
- when /^4.2/
34
- gem 'responders', '~> 2.0'
35
- gem 'sass-rails', '>= 5.0'
36
- gem 'coffee-rails', '~> 4.1.0'
37
- when /^4.[01]/
38
- gem 'sass-rails', '< 5.0'
39
- end
40
- end
41
- # END ENGINE_CART BLOCK
@@ -3,6 +3,7 @@ module Riiif
3
3
  attr_reader :path
4
4
 
5
5
  class_attribute :info_extractor_class
6
+ # TODO: add alternative that uses kdu_jp2info
6
7
  self.info_extractor_class = ImageMagickInfoExtractor
7
8
 
8
9
  # @param input_path [String] The location of an image file
@@ -20,6 +21,8 @@ module Riiif
20
21
  end
21
22
  deprecation_deprecate read: 'Riiif::File.read is deprecated and will be removed in version 2.0'
22
23
 
24
+ # Yields a tempfile to the provided block
25
+ # @return [Riiif::File] a file backed by the Tempfile
23
26
  def self.create(ext = nil, _validate = true, &block)
24
27
  tempfile = Tempfile.new(['mini_magick', ext.to_s.downcase])
25
28
  tempfile.binmode
@@ -32,22 +35,26 @@ module Riiif
32
35
  deprecation_deprecate create: 'Riiif::File.create is deprecated and will be removed in version 2.0'
33
36
 
34
37
  # @param [Transformation] transformation
35
- def extract(transformation)
36
- command = command_factory.build(path, transformation)
37
- execute(command)
38
+ # @param [ImageInformation] image_info
39
+ # @return [String] the processed image data
40
+ def extract(transformation, image_info = info)
41
+ transformer.transform(path, image_info, transformation)
38
42
  end
39
43
 
40
- def info
41
- @info ||= info_extractor_class.new(path).extract
44
+ def transformer
45
+ if Riiif.kakadu_enabled? && path.ends_with?('.jp2')
46
+ KakaduTransformer
47
+ else
48
+ ImagemagickTransformer
49
+ end
42
50
  end
43
51
 
44
- delegate :execute, to: Riiif::CommandRunner
45
- private :execute
46
-
47
- private
52
+ def info
53
+ @info ||= info_extractor.extract
54
+ end
48
55
 
49
- def command_factory
50
- ImagemagickCommandFactory
51
- end
56
+ def info_extractor
57
+ @info_extractor ||= info_extractor_class.new(path)
58
+ end
52
59
  end
53
60
  end
@@ -4,24 +4,24 @@ require 'digest/md5'
4
4
  # These explict requires are needed because in some contexts the Rails
5
5
  # autoloader can either: unload already loaded classes, or cause a lock while
6
6
  # trying to load a needed class.
7
- require_dependency 'riiif/region/imagemagick/absolute_decoder'
8
- require_dependency 'riiif/region/imagemagick/full_decoder'
9
- require_dependency 'riiif/region/imagemagick/percentage_decoder'
10
- require_dependency 'riiif/region/imagemagick/square_decoder'
7
+ require_dependency 'riiif/region/absolute'
8
+ require_dependency 'riiif/region/full'
9
+ require_dependency 'riiif/region/percentage'
10
+ require_dependency 'riiif/region/square'
11
11
 
12
- require_dependency 'riiif/size/imagemagick/absolute_decoder'
13
- require_dependency 'riiif/size/imagemagick/best_fit_decoder'
14
- require_dependency 'riiif/size/imagemagick/full_decoder'
15
- require_dependency 'riiif/size/imagemagick/height_decoder'
16
- require_dependency 'riiif/size/imagemagick/percent_decoder'
17
- require_dependency 'riiif/size/imagemagick/width_decoder'
12
+ require_dependency 'riiif/size/absolute'
13
+ require_dependency 'riiif/size/best_fit'
14
+ require_dependency 'riiif/size/full'
15
+ require_dependency 'riiif/size/height'
16
+ require_dependency 'riiif/size/percent'
17
+ require_dependency 'riiif/size/width'
18
18
 
19
19
  module Riiif
20
20
  class Image
21
21
  extend Deprecation
22
22
 
23
23
  class_attribute :file_resolver, :info_service, :authorization_service, :cache
24
- self.file_resolver = FileSystemFileResolver.new(base_path: ::File.join(Rails.root, 'tmp'))
24
+ self.file_resolver = FileSystemFileResolver.new(base_path: File.join(Rails.root, 'tmp'))
25
25
  self.authorization_service = NilAuthorizationService
26
26
  self.cache = Rails.cache
27
27
 
@@ -54,12 +54,13 @@ module Riiif
54
54
 
55
55
  ##
56
56
  # @param [ActiveSupport::HashWithIndifferentAccess] args
57
+ # @return [String] the image data
57
58
  def render(args)
58
59
  cache_opts = args.select { |a| %w(region size quality rotation format).include? a.to_s }
59
60
  key = Image.cache_key(id, cache_opts)
60
61
 
61
62
  cache.fetch(key, compress: true, expires_in: Image.expires_in) do
62
- file.extract(OptionDecoder.decode(args, info))
63
+ file.extract(OptionDecoder.decode(args, info), info)
63
64
  end
64
65
  end
65
66
 
@@ -14,6 +14,10 @@ module Riiif
14
14
  { width: width, height: height }
15
15
  end
16
16
 
17
+ def aspect_ratio
18
+ width.to_f / height
19
+ end
20
+
17
21
  def [](key)
18
22
  to_h[key]
19
23
  end
@@ -0,0 +1,35 @@
1
+ module Riiif
2
+ # Represents a IIIF request
3
+ class Transformation
4
+ attr_reader :crop, :size, :quality, :rotation, :format
5
+ def initialize(crop, size, quality, rotation, format)
6
+ @crop = crop
7
+ @size = size
8
+ @quality = quality
9
+ @rotation = rotation
10
+ @format = format
11
+ end
12
+
13
+ # Create a clone of this Transformation, scaled by the factor
14
+ # @param [Integer] factor the scale for the new transformation
15
+ # @return [Transformation] a new transformation, scaled by factor
16
+ def reduce(factor)
17
+ Transformation.new(crop.dup,
18
+ size.reduce(factor),
19
+ quality,
20
+ rotation,
21
+ format)
22
+ end
23
+
24
+ # Create a clone of this Transformation, without the crop
25
+ # @return [Transformation] a new transformation
26
+ # TODO: it would be nice if we didn't need image_info
27
+ def without_crop(image_info)
28
+ Transformation.new(Region::Full.new(image_info),
29
+ size.dup,
30
+ quality,
31
+ rotation,
32
+ format)
33
+ end
34
+ end
35
+ end
File without changes
@@ -6,6 +6,8 @@ module Riiif
6
6
  include ActiveSupport::Benchmarkable
7
7
  delegate :logger, to: :Rails
8
8
 
9
+ # TODO: this is being loaded into memory. We could make this a stream.
10
+ # @return [String] all the image data
9
11
  def execute(command)
10
12
  out = nil
11
13
  benchmark("Riiif executed #{command}") do
@@ -0,0 +1,54 @@
1
+ module Riiif
2
+ # Represents a cropping operation
3
+ class Crop
4
+ attr_reader :image_info
5
+
6
+ # @return [String] a region for imagemagick to decode
7
+ # (appropriate for passing to the -crop parameter)
8
+ def to_imagemagick
9
+ "#{width}x#{height}+#{offset_x}+#{offset_y}"
10
+ end
11
+
12
+ # @return [String] a region for kakadu to decode
13
+ # (appropriate for passing to the -region parameter)
14
+ def to_kakadu
15
+ "\{#{decimal_offset_y},#{decimal_offset_x}\},\{#{decimal_height},#{decimal_width}\}"
16
+ end
17
+
18
+ attr_reader :offset_x
19
+
20
+ attr_reader :offset_y
21
+
22
+ # @return [Integer] the height in pixels
23
+ def height
24
+ image_info.height
25
+ end
26
+
27
+ # @return [Integer] the width in pixels
28
+ def width
29
+ image_info.width
30
+ end
31
+
32
+ # @return [Float] the fractional height with respect to the original size
33
+ def decimal_height(n = height)
34
+ n.to_f / image_info.height
35
+ end
36
+
37
+ # @return [Float] the fractional width with respect to the original size
38
+ def decimal_width(n = width)
39
+ n.to_f / image_info.width
40
+ end
41
+
42
+ def decimal_offset_x
43
+ offset_x.to_f / image_info.width
44
+ end
45
+
46
+ def decimal_offset_y
47
+ offset_y.to_f / image_info.height
48
+ end
49
+
50
+ def maintain_aspect_ratio?
51
+ (height / width) == (image_info.height / image_info.width)
52
+ end
53
+ end
54
+ end
@@ -9,35 +9,29 @@ module Riiif
9
9
 
10
10
  # A helper method to instantiate and invoke build
11
11
  # @param [String] path the location of the file
12
+ # @param info [ImageInformation] information about the source
12
13
  # @param [Transformation] transformation
13
14
  # @param [Integer] compression (85) the compression level to use (set 0 for no compression)
14
15
  # @param [String] sampling_factor ("4:2:0") the chroma sample factor (set 0 for no compression)
15
16
  # @param [Boolean] strip_metadata (true) do we want to strip EXIF tags?
16
- # @return [String] a command for running imagemagick to produce the requested output
17
- def self.build(path, transformation, compression: 85, sampling_factor: '4:2:0', strip_metadata: true)
18
- new(path, transformation,
19
- compression: compression,
20
- sampling_factor: sampling_factor,
21
- strip_metadata: strip_metadata).build
22
- end
23
-
24
- # A helper method to instantiate and invoke build
25
- # @param [String] path the location of the file
26
- # @param [Transformation] transformation
27
- # @param [Integer] compression the compression level to use (set 0 for no compression)
28
- def initialize(path, transformation, compression:, sampling_factor:, strip_metadata:)
17
+ def initialize(path, info, transformation, compression: 85, sampling_factor: '4:2:0', strip_metadata: true)
29
18
  @path = path
19
+ @info = info
30
20
  @transformation = transformation
31
21
  @compression = compression
32
22
  @sampling_factor = sampling_factor
33
23
  @strip_metadata = strip_metadata
34
24
  end
35
25
 
36
- attr_reader :path, :transformation, :compression, :sampling_factor, :strip_metadata
26
+ attr_reader :path, :info, :transformation, :compression, :sampling_factor, :strip_metadata
37
27
 
38
28
  # @return [String] a command for running imagemagick to produce the requested output
39
- def build
40
- [external_command, crop, size, rotation, colorspace, quality, sampling, metadata, output].join
29
+ def command
30
+ [external_command, crop, size, rotation, colorspace, quality, sampling, metadata, input, output].join
31
+ end
32
+
33
+ def reduction_factor
34
+ nil
41
35
  end
42
36
 
43
37
  private
@@ -50,16 +44,23 @@ module Riiif
50
44
  transformation.format == 'jpg'.freeze
51
45
  end
52
46
 
47
+ def input
48
+ " #{path}"
49
+ end
50
+
51
+ # pipe the output to STDOUT
53
52
  def output
54
- " #{path} #{transformation.format}:-"
53
+ " #{transformation.format}:-"
55
54
  end
56
55
 
57
56
  def crop
58
- " -crop #{transformation.crop}" if transformation.crop
57
+ directive = transformation.crop.to_imagemagick
58
+ " -crop #{directive}" if directive
59
59
  end
60
60
 
61
61
  def size
62
- " -resize #{transformation.size}" if transformation.size
62
+ directive = transformation.size.to_imagemagick
63
+ " -resize #{directive}" if directive
63
64
  end
64
65
 
65
66
  def rotation