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
@@ -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