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
@@ -0,0 +1,44 @@
1
+ module Riiif
2
+ module Size
3
+ # The width and height of the returned image is scaled to n% of the width and height
4
+ # of the extracted region. The aspect ratio of the returned image is the same as that
5
+ # of the extracted region.
6
+ class Percent < Resize
7
+ def initialize(info, percentage)
8
+ @image_info = info
9
+ @percentage = percentage
10
+ end
11
+
12
+ attr_reader :percentage
13
+
14
+ # @return [String] a resize directive for imagemagick to use
15
+ def to_imagemagick
16
+ "#{percentage}%"
17
+ end
18
+
19
+ # @return [Integer] the height in pixels
20
+ def height
21
+ percent_of(image_info.height)
22
+ end
23
+
24
+ # @return [Integer] the width in pixels
25
+ def width
26
+ percent_of(image_info.width)
27
+ end
28
+
29
+ # @param [Integer] factor number of times to reduce by 1/2
30
+ def reduce(factor)
31
+ pct = percentage.to_f * 2**factor
32
+ Percent.new(image_info, pct)
33
+ end
34
+
35
+ private
36
+
37
+ # @param [Integer] value a value to convert to the percentage
38
+ # @return [Float]
39
+ def percent_of(value)
40
+ value * Integer(percentage).to_f / 100
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
1
+ module Riiif
2
+ module Size
3
+ # The image or region should be scaled so that its width is exactly equal
4
+ # to the provided parameter, and the height will be a calculated value that
5
+ # maintains the aspect ratio of the extracted region
6
+ class Width < Resize
7
+ def initialize(info, width)
8
+ @image_info = info
9
+ @width = width.to_i
10
+ end
11
+
12
+ # @return [String] a resize directive for imagemagick to use
13
+ def to_imagemagick
14
+ @width.to_s
15
+ end
16
+
17
+ attr_reader :width
18
+
19
+ def height
20
+ width * image_info.height / image_info.width
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ module Riiif
2
+ # Transforms an image using a backend
3
+ class AbstractTransformer
4
+ # @param path [String] The path of the source image file
5
+ # @param image_info [ImageInformation] information about the source
6
+ # @param [Transformation] transformation
7
+ def self.transform(path, image_info, transformation)
8
+ new(path, image_info, transformation).transform
9
+ end
10
+
11
+ def initialize(path, image_info, transformation)
12
+ @path = path
13
+ @image_info = image_info
14
+ @transformation = transformation
15
+ end
16
+
17
+ attr_reader :path, :image_info, :transformation
18
+
19
+ def transform
20
+ execute(command_builder.command)
21
+ end
22
+
23
+ def command_builder
24
+ @command_builder ||= command_factory.new(path, image_info, transformation)
25
+ end
26
+
27
+ delegate :execute, to: Riiif::CommandRunner
28
+ private :execute
29
+ end
30
+ end
@@ -0,0 +1,8 @@
1
+ module Riiif
2
+ # Transforms an image using Imagemagick
3
+ class ImagemagickTransformer < AbstractTransformer
4
+ def command_factory
5
+ ImagemagickCommandFactory
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,39 @@
1
+ module Riiif
2
+ # Transforms an image using Kakadu
3
+ class KakaduTransformer < AbstractTransformer
4
+ def command_factory
5
+ KakaduCommandFactory
6
+ end
7
+
8
+ def transform
9
+ with_tempfile do |file_name|
10
+ execute(command_builder.command(file_name))
11
+ post_process(file_name, command_builder.reduction_factor)
12
+ end
13
+ end
14
+
15
+ def with_tempfile
16
+ Tempfile.open(['riiif-intermediate', '.bmp']) do |f|
17
+ yield f.path
18
+ end
19
+ end
20
+
21
+ # The data we get back from kdu_expand is a bmp and we need to change it
22
+ # to the requested format by calling Imagemagick.
23
+ def post_process(intermediate_file, reduction_factor)
24
+ # Calculate a new set of transforms with respect to reduction_factor
25
+ transformation = if reduction_factor
26
+ self.transformation.without_crop(image_info).reduce(reduction_factor)
27
+ else
28
+ self.transformation.without_crop(image_info)
29
+ end
30
+ Riiif::File.new(intermediate_file).extract(transformation, image_info)
31
+ end
32
+
33
+ private
34
+
35
+ def tmp_path
36
+ @link_path ||= LinkNameService.create
37
+ end
38
+ end
39
+ end
data/lib/riiif.rb CHANGED
@@ -3,13 +3,7 @@ require 'deprecation'
3
3
  require 'riiif/engine'
4
4
  module Riiif
5
5
  extend ActiveSupport::Autoload
6
- autoload :Image
7
- autoload :AbstractFileSystemResolver
8
- autoload :FileSystemFileResolver
9
- autoload :HTTPFileResolver
10
6
  autoload :Routes
11
- autoload :AkubraSystemFileResolver
12
- autoload :NilAuthorizationService
13
7
 
14
8
  class Error < RuntimeError; end
15
9
  class InvalidAttributeError < Error; end
@@ -18,7 +12,10 @@ module Riiif
18
12
  # This error is raised when Riiif can't convert an image
19
13
  class ConversionError < Error; end
20
14
 
21
- Transformation = Struct.new(:crop, :size, :quality, :rotation, :format)
22
15
  mattr_accessor :not_found_image # the image to use when a lookup fails
23
16
  mattr_accessor :unauthorized_image # the image to use when a user doesn't have access
17
+
18
+ def self.kakadu_enabled?
19
+ Engine.config.kakadu_enabled
20
+ end
24
21
  end
data/lib/riiif/engine.rb CHANGED
@@ -5,8 +5,9 @@ module Riiif
5
5
  # How long to cache the tiles for.
6
6
  config.cache_duration_in_days = 3
7
7
 
8
- config.action_dispatch.rescue_responses.merge!(
9
- 'Riiif::ImageNotFoundError' => :not_found
10
- )
8
+ config.action_dispatch.rescue_responses['Riiif::ImageNotFoundError'] = :not_found
9
+
10
+ # Set to true to use kdu for jp2000 source images
11
+ config.kakadu_enabled = false
11
12
  end
12
13
  end
data/lib/riiif/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Riiif
2
- VERSION = '1.7.1'.freeze
2
+ VERSION = '2.0.0.beta1'.freeze
3
3
  end
data/riiif.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency 'deprecation', '>= 1.0.0'
23
23
  spec.add_development_dependency 'bundler', '~> 1.3'
24
24
  spec.add_development_dependency 'rake'
25
- spec.add_development_dependency 'engine_cart', '~> 2.0'
25
+ spec.add_development_dependency 'engine_cart', '~> 0.8'
26
26
  spec.add_development_dependency 'rspec-rails'
27
27
  spec.add_development_dependency 'sqlite3'
28
28
  spec.add_development_dependency 'rubocop', '~> 0.47.1'
@@ -15,11 +15,14 @@ RSpec.describe Riiif::Image do
15
15
 
16
16
  describe 'happy path' do
17
17
  before do
18
- expect(subject.file).to receive(:execute)
19
- .with("convert -quality 85 -sampling-factor 4:2:0 -strip #{filename} jpg:-")
20
- .and_return('imagedata')
18
+ allow(image.info_service).to receive(:call).and_return({})
21
19
  end
20
+
22
21
  it 'renders' do
22
+ expect(Riiif::CommandRunner).to receive(:execute)
23
+ .with("convert -quality 85 -sampling-factor 4:2:0 -strip #{filename} jpg:-")
24
+ .and_return('imagedata')
25
+
23
26
  expect(subject.render('size' => 'full', format: 'jpg')).to eq 'imagedata'
24
27
  end
25
28
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Riiif::Transformation do
6
+ subject(:transformation) do
7
+ Riiif::Transformation.new(region,
8
+ size,
9
+ quality,
10
+ rotation,
11
+ fmt)
12
+ end
13
+
14
+ let(:region) { Riiif::Region::Full.new(image_info) }
15
+ let(:size) { Riiif::Size::Percent.new(image_info, 20) }
16
+ let(:quality) { nil }
17
+ let(:rotation) { nil }
18
+ let(:fmt) { nil }
19
+ let(:image_info) { double('Image info', height: 4381, width: 6501) }
20
+
21
+ describe 'reduce' do
22
+ subject { transformation.reduce(factor) }
23
+ context 'when reduced by 2' do
24
+ let(:factor) { 2 }
25
+ let(:size) { Riiif::Size::Percent.new(image_info, 20) }
26
+
27
+ it 'downsamples the size' do
28
+ expect(subject.size).to be_kind_of Riiif::Size::Percent
29
+ expect(subject.size.percentage).to eq 80.0
30
+ end
31
+ end
32
+ end
33
+
34
+ describe 'without_crop' do
35
+ let(:region) { Riiif::Region::Absolute.new(image_info, 5, 6, 7, 8) }
36
+
37
+ subject { transformation.without_crop(image_info) }
38
+ it 'nullifies the crop' do
39
+ expect(subject.crop).to be_kind_of Riiif::Region::Full
40
+ end
41
+ end
42
+ end
@@ -2,13 +2,15 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe Riiif::ImagemagickCommandFactory do
4
4
  let(:path) { 'foo.tiff' }
5
+ let(:info) { double('foo') }
5
6
 
6
- describe '.build' do
7
- subject { described_class.build(path, transformation) }
7
+ describe '.command' do
8
+ subject { instance.command }
9
+ let(:instance) { described_class.new(path, info, transformation) }
8
10
 
9
11
  let(:transformation) do
10
- Riiif::Transformation.new('region',
11
- 'size',
12
+ Riiif::Transformation.new(Riiif::Region::Full.new(info),
13
+ Riiif::Size::Full.new,
12
14
  'quality',
13
15
  'rotation',
14
16
  format)
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Riiif::KakaduCommandFactory do
6
+ subject(:instance) { described_class.new(path, info, transformation) }
7
+
8
+ let(:info) { double(:info) }
9
+ let(:path) { 'foo.jp2' }
10
+ let(:region) { Riiif::Region::Full.new(info) }
11
+ let(:size) { Riiif::Size::Full.new }
12
+ let(:quality) { nil }
13
+ let(:rotation) { nil }
14
+ let(:fmt) { nil }
15
+
16
+ let(:transformation) do
17
+ Riiif::Transformation.new(region,
18
+ size,
19
+ quality,
20
+ rotation,
21
+ fmt)
22
+ end
23
+
24
+ describe '#command' do
25
+ subject { instance.command '/tmp/bar.bmp' }
26
+
27
+ context 'with a full size image' do
28
+ it { is_expected.to eq 'kdu_expand -quiet -i foo.jp2 -num_threads 4 -o /tmp/bar.bmp' }
29
+ end
30
+ end
31
+
32
+ describe '#region' do
33
+ subject { instance.send(:region) }
34
+ let(:info) { double(height: 300, width: 300) }
35
+
36
+ context 'with a full' do
37
+ it { is_expected.to be nil }
38
+ end
39
+
40
+ context 'with absolute' do
41
+ let(:region) { Riiif::Region::Absolute.new(info, 25, 75, 150, 100) }
42
+ it { is_expected.to eq ' -region "{0.25,0.08333333333333333},{0.3333333333333333,0.5}"' }
43
+ end
44
+
45
+ context 'with a square' do
46
+ let(:region) { Riiif::Region::Square.new(info) }
47
+ it { is_expected.to eq ' -region "{0.0,0},{1.0,1.0}"' }
48
+ end
49
+
50
+ context 'with a percentage' do
51
+ let(:region) { Riiif::Region::Percentage.new(info, 20, 30, 40, 50) }
52
+ it { is_expected.to eq ' -region "{0.3,0.2},{0.5,0.4}"' }
53
+ end
54
+ end
55
+
56
+ describe '#reduction_factor' do
57
+ subject { instance.send(:reduction_factor) }
58
+
59
+ let(:info) { Riiif::ImageInformation.new(300, 300) }
60
+
61
+ context 'for a full size image' do
62
+ it { is_expected.to eq nil }
63
+ end
64
+
65
+ context 'when the aspect ratio is maintined for absolute' do
66
+ let(:size) { Riiif::Size::Absolute.new(info, 145, 145) }
67
+ it { is_expected.to eq 1 }
68
+ end
69
+
70
+ context 'when the aspect ratio is not-maintined' do
71
+ let(:size) { Riiif::Size::Absolute.new(info, 100, 145) }
72
+ it { is_expected.to eq nil }
73
+ end
74
+
75
+ context 'when aspect ratio is maintained for 45 pct' do
76
+ let(:size) { Riiif::Size::Percent.new(info, 45) }
77
+ it { is_expected.to eq 1 }
78
+ end
79
+
80
+ context 'when aspect ratio is maintained for 20 pct' do
81
+ let(:size) { Riiif::Size::Percent.new(info, 20) }
82
+ it { is_expected.to eq 2 }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Riiif::Region::Absolute do
4
+ let(:image_info) { double }
5
+
6
+ context 'when initialized with strings' do
7
+ let(:instance) { described_class.new(image_info, '5', '15', '50', '100') }
8
+
9
+ it 'casts height to an integer' do
10
+ expect(instance.height).to eq 100
11
+ end
12
+
13
+ it 'casts width to an integer' do
14
+ expect(instance.width).to eq 50
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Riiif::Size::Absolute do
4
+ let(:image_info) { double }
5
+
6
+ context 'when initialized with strings' do
7
+ let(:instance) { described_class.new(image_info, '50', '100') }
8
+
9
+ it 'casts height to an integer' do
10
+ expect(instance.height).to eq 100
11
+ end
12
+
13
+ it 'casts width to an integer' do
14
+ expect(instance.width).to eq 50
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Riiif::Size::Height do
4
+ let(:image_info) { double }
5
+
6
+ context 'when initialized with strings' do
7
+ let(:instance) { described_class.new(image_info, '50') }
8
+
9
+ it 'casts height to an integer' do
10
+ expect(instance.height).to eq 50
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Riiif::Size::Width do
4
+ let(:image_info) { double }
5
+
6
+ context 'when initialized with strings' do
7
+ let(:instance) { described_class.new(image_info, '50') }
8
+
9
+ it 'casts height to an integer' do
10
+ expect(instance.width).to eq 50
11
+ end
12
+ end
13
+ end