riiif 1.7.1 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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