riiif 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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -0
  3. data/app/controllers/riiif/images_controller.rb +26 -0
  4. data/app/models/riiif/file.rb +87 -0
  5. data/app/models/riiif/image.rb +16 -36
  6. data/app/views/riiif/images/view.html.erb +21 -0
  7. data/config/routes.rb +5 -1
  8. data/lib/riiif.rb +1 -0
  9. data/lib/riiif/file_system_file_resolver.rb +1 -1
  10. data/lib/riiif/http_file_resolver.rb +24 -0
  11. data/lib/riiif/version.rb +1 -1
  12. data/riiif.gemspec +1 -2
  13. data/spec/controllers/images_controller_spec.rb +17 -0
  14. data/spec/models/image_spec.rb +45 -33
  15. data/spec/routing/resize_routes_spec.rb +26 -6
  16. data/vendor/assets/images/openseadragon/fullpage_grouphover.png +0 -0
  17. data/vendor/assets/images/openseadragon/fullpage_hover.png +0 -0
  18. data/vendor/assets/images/openseadragon/fullpage_pressed.png +0 -0
  19. data/vendor/assets/images/openseadragon/fullpage_rest.png +0 -0
  20. data/vendor/assets/images/openseadragon/home_grouphover.png +0 -0
  21. data/vendor/assets/images/openseadragon/home_hover.png +0 -0
  22. data/vendor/assets/images/openseadragon/home_pressed.png +0 -0
  23. data/vendor/assets/images/openseadragon/home_rest.png +0 -0
  24. data/vendor/assets/images/openseadragon/next_grouphover.png +0 -0
  25. data/vendor/assets/images/openseadragon/next_hover.png +0 -0
  26. data/vendor/assets/images/openseadragon/next_pressed.png +0 -0
  27. data/vendor/assets/images/openseadragon/next_rest.png +0 -0
  28. data/vendor/assets/images/openseadragon/previous_grouphover.png +0 -0
  29. data/vendor/assets/images/openseadragon/previous_hover.png +0 -0
  30. data/vendor/assets/images/openseadragon/previous_pressed.png +0 -0
  31. data/vendor/assets/images/openseadragon/previous_rest.png +0 -0
  32. data/vendor/assets/images/openseadragon/zoomin_grouphover.png +0 -0
  33. data/vendor/assets/images/openseadragon/zoomin_hover.png +0 -0
  34. data/vendor/assets/images/openseadragon/zoomin_pressed.png +0 -0
  35. data/vendor/assets/images/openseadragon/zoomin_rest.png +0 -0
  36. data/vendor/assets/images/openseadragon/zoomout_grouphover.png +0 -0
  37. data/vendor/assets/images/openseadragon/zoomout_hover.png +0 -0
  38. data/vendor/assets/images/openseadragon/zoomout_pressed.png +0 -0
  39. data/vendor/assets/images/openseadragon/zoomout_rest.png +0 -0
  40. data/vendor/assets/javascripts/openseadragon.js +12279 -0
  41. metadata +30 -18
  42. data/spec/samples/world.jp2 +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f9f72b481aa0760baf9a47f06e01a62f1e76ec2e
4
- data.tar.gz: 4f903b470600ac688a2f0636f59c40898f7e22e2
3
+ metadata.gz: 2267ef01c3a2abbf3991710ef5c4c9f6ac55500c
4
+ data.tar.gz: 13fc80e6e72c789bac048f66fc020d8a0cb2e314
5
5
  SHA512:
6
- metadata.gz: 870c2da826793ec753971ae9c677a57d57577d1eb65c7aa69a5f98acea2a3601f8f1e2290c8f7e4553fd99fcc1043a2d4e449d4c884c3def264695de313c7849
7
- data.tar.gz: d998c2468c0779170a188a6bbd47ef843c86c7df45203fbd115fbe28346a64dc765064dcb682b22eb114d3ff732b373cfd795e26dda4fde66638820fdffab474
6
+ metadata.gz: 0d45589ca6d5e13de6d7a40a61b09c48e9d062118c1845d9fd786e7d8f5066980d9e1adb8d1a4b1df7b419a6729248fec8bc8ea6338d0e9216324a94d9cec7eb
7
+ data.tar.gz: 64600eb8e05f1f613b7a039ed6c25b36f5f87d75f1993b9dad667ae3eea9e47e5fe9b66200ef4a03f3fc96862e307cdc2adf936e69609206e02cd4014562553b
data/README.md CHANGED
@@ -15,7 +15,32 @@ And then execute:
15
15
  Or install it yourself as:
16
16
 
17
17
  $ gem install riiif
18
+
19
+ ## Configure
18
20
 
21
+ ### Images on the servers file system.
22
+
23
+ By default Riiif is set to load images from the filesystem using the Riiif::FileSystemFileResolver.
24
+ You can configure how this resolver finds the files by setting this property:
25
+ ```
26
+ Riiif::FileSystemFileResolver.base_path = '/opt/repository/images/'
27
+ ```
28
+ When the Id passed in is "foo_image", then it will look for an image file using this glob:
29
+ ```
30
+ /opt/repository/images/foo_image.{png,jpg,tiff,jp,jp2}
31
+ ```
32
+
33
+ ### Images retrieved over HTTP
34
+ To source the images from the network instead of the file system, we first configure Riiif to use an alternative resolver:
35
+ ```
36
+ Riiif::Image.file_resolver = Riiif::HTTPFileResolver
37
+ ```
38
+ Then we configure the resolver with a mechanism for mapping the provided id to a url:
39
+ ```
40
+ Riiif::HTTPFileResolver.id_to_uri = lambda do |id|
41
+ "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/#{id}.jpg/600px-#{id}.jpg"
42
+ end
43
+ ```
19
44
  ## Usage
20
45
 
21
46
  Mount the gem as an engine:
@@ -1,9 +1,35 @@
1
1
  module Riiif
2
2
  class ImagesController < ::ApplicationController
3
+ before_filter :link_header, only: [:show, :info]
3
4
  def show
4
5
  image = Image.new(params[:id])
5
6
  data = image.render(params.permit(:region, :size, :rotation, :quality, :format))
6
7
  send_data data, type: Mime::Type.lookup_by_extension(params[:format]), :disposition => 'inline'
7
8
  end
9
+
10
+ def info
11
+ image = Image.new(params[:id])
12
+ render json: image.info.merge(server_info)
13
+ end
14
+
15
+ def view
16
+ @image = Image.new(params[:id])
17
+ end
18
+
19
+ protected
20
+
21
+ def link_header
22
+ response.headers["Link"] = '<http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2>;rel="profile"'
23
+ end
24
+
25
+ def server_info
26
+ {
27
+ "@context" => "http://library.stanford.edu/iiif/image-api/1.1/context.json",
28
+ "@id" => request.original_url.sub('/info.json', ''),
29
+ "formats" => Image::OUTPUT_FORMATS,
30
+ "profile" => "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0"
31
+
32
+ }
33
+ end
8
34
  end
9
35
  end
@@ -0,0 +1,87 @@
1
+ require 'open3'
2
+ module Riiif
3
+ class File
4
+ include Open3
5
+ attr_reader :path
6
+ # @param input_path [String] The location of an image file
7
+ def initialize(input_path, tempfile = nil)
8
+ raise "HUH" if input_path.is_a? Riiif::File
9
+ @path = input_path
10
+ @tempfile = tempfile # ensures that the tempfile will stick around until this file is garbage collected.
11
+ end
12
+
13
+ def self.open(file_or_url, ext = nil)
14
+ file_or_url = file_or_url.to_s # Force it to be a String... hell or highwater
15
+ if file_or_url.include?("://")
16
+ require 'open-uri'
17
+ ext ||= ::File.extname(URI.parse(file_or_url).path)
18
+ Kernel::open(file_or_url) do |f|
19
+ self.read(f, ext)
20
+ end
21
+ else
22
+ self.new(file_or_url)
23
+ end
24
+ end
25
+
26
+ def self.read(stream, ext)
27
+ create(ext) do |f|
28
+ while chunk = stream.read(8192)
29
+ f.write(chunk)
30
+ end
31
+ end
32
+ end
33
+
34
+ def self.create(ext = nil, validate = true, &block)
35
+ begin
36
+ tempfile = Tempfile.new(['mini_magick', ext.to_s.downcase])
37
+ tempfile.binmode
38
+ block.call(tempfile)
39
+ tempfile.close
40
+ image = self.new(tempfile.path, tempfile)
41
+ ensure
42
+ tempfile.close if tempfile
43
+ end
44
+ end
45
+
46
+ def extract(options)
47
+
48
+ command = 'convert'
49
+ command << " -crop #{options[:crop]}" if options[:crop]
50
+ command << " -resize #{options[:size]}" if options[:size]
51
+ if options[:rotation]
52
+ command << " -virtual-pixel white +distort srt #{options[:rotation]}"
53
+ end
54
+
55
+ case options[:quality]
56
+ when 'grey'
57
+ command << ' -colorspace Gray'
58
+ when 'bitonal'
59
+ command << ' -colorspace Gray'
60
+ command << ' -type Bilevel'
61
+ end
62
+ command << " #{path} #{options[:format]}:-"
63
+ Rails.logger.debug "RIIIF executed: #{command}"
64
+ execute(command)
65
+ end
66
+
67
+ def info
68
+ return @info if @info
69
+ height, width = execute("identify -format %hx%w #{path}").split('x')
70
+ @info = {height: Integer(height), width: Integer(width)}
71
+ end
72
+
73
+ private
74
+ def execute(command)
75
+ stdin, stdout, stderr, wait_thr = popen3(command)
76
+ stdin.close
77
+ stdout.binmode
78
+ out = stdout.read
79
+ stdout.close
80
+ err = stderr.read
81
+ stderr.close
82
+ raise "Unable to execute command \"#{command}\"\n#{err}" unless wait_thr.value.success?
83
+ out
84
+ end
85
+
86
+ end
87
+ end
@@ -1,37 +1,30 @@
1
- require 'mini_magick'
2
1
  module Riiif
3
2
  class Image
3
+
4
4
  class_attribute :file_resolver
5
5
  self.file_resolver = FileSystemFileResolver
6
6
 
7
- attr_reader :path_name
7
+ OUTPUT_FORMATS = %W{jpg png}
8
+
9
+ attr_reader :path_name, :id
8
10
 
9
11
  # @param [String] id The identifier of the file
10
12
  def initialize(id)
13
+ @id = id
11
14
  @path_name = file_resolver.find(id)
12
15
  end
13
16
 
14
17
  def render(args)
15
18
  options = decode_options!(args)
19
+ Rails.cache.fetch(options.merge(id: id), compress: true, expires_in: 3.days) do
20
+ image.extract(options)
21
+ end
22
+ end
16
23
 
17
- image.combine_options do |c|
18
- c.crop options[:crop] if options[:crop]
19
- c.resize options[:size] if options[:size]
20
- if options[:rotation]
21
- c.virtual_pixel 'white'
22
- c.distort.+ 'srt', options[:rotation]
23
- end
24
+ delegate :info, to: :image
24
25
 
25
- case options[:quality]
26
- when 'grey'
27
- c.colorspace "Gray"
28
- when 'bitonal'
29
- c.colorspace "Gray"
30
- c.type 'Bilevel'
31
- end
32
- end
33
- image.format(options[:format])
34
- image.to_blob
26
+ def image
27
+ @image ||= Riiif::File.open(path_name)
35
28
  end
36
29
 
37
30
  private
@@ -63,7 +56,7 @@ module Riiif
63
56
  end
64
57
 
65
58
  def validate_format!(format)
66
- raise InvalidAttributeError, "Unsupported format: #{format}" unless ['jpg', 'png'].include?(format)
59
+ raise InvalidAttributeError, "Unsupported format: #{format}" unless OUTPUT_FORMATS.include?(format)
67
60
 
68
61
  end
69
62
 
@@ -72,8 +65,8 @@ module Riiif
72
65
  nil
73
66
  elsif md = /^pct:(\d+),(\d+),(\d+),(\d+)$/.match(region)
74
67
  # Image magic can't do percentage offsets, so we have to calculate it
75
- offset_x = (image[:width] * Integer(md[1]).to_f / 100).round
76
- offset_y = (image[:height] * Integer(md[2]).to_f / 100).round
68
+ offset_x = (info[:width] * Integer(md[1]).to_f / 100).round
69
+ offset_y = (info[:height] * Integer(md[2]).to_f / 100).round
77
70
  "#{md[3]}%x#{md[4]}+#{offset_x}+#{offset_y}"
78
71
  elsif md = /^(\d+),(\d+),(\d+),(\d+)$/.match(region)
79
72
  "#{md[3]}x#{md[4]}+#{md[1]}+#{md[2]}"
@@ -89,7 +82,7 @@ module Riiif
89
82
  "x#{md[1]}"
90
83
  elsif md = /^(\d+),$/.match(size)
91
84
  "#{md[1]}"
92
- elsif md = /^pct:(\d+)$/.match(size)
85
+ elsif md = /^pct:(\d+(.\d+)?)$/.match(size)
93
86
  "#{md[1]}%"
94
87
  elsif md = /^(\d+),(\d+)$/.match(size)
95
88
  "#{md[1]}x#{md[2]}!"
@@ -100,18 +93,5 @@ module Riiif
100
93
  end
101
94
  end
102
95
 
103
- def image
104
- begin
105
- @image ||= MiniMagick::Image.open(path_name)
106
- rescue Errno::ENOENT => e
107
- Rails.logger.error "Unable to find #{path_name}"
108
- Rails.logger.error e.backtrace
109
- raise Riiif::Error, "Unable to find #{path_name}"
110
- rescue MiniMagick::Error => e
111
- Rails.logger.error "Error trying to open #{path_name}"
112
- Rails.logger.error e.backtrace
113
- raise Riiif::Error, "Unable to open the image #{path_name}"
114
- end
115
- end
116
96
  end
117
97
  end
@@ -0,0 +1,21 @@
1
+ <div id="openseadragon1" style="width: 800px; height: 600px;"></div>
2
+ <%=javascript_include_tag "openseadragon.js" %>
3
+ <script type="text/javascript">
4
+ var viewer = OpenSeadragon({
5
+ id: "openseadragon1",
6
+ prefixUrl: "/assets/openseadragon/",
7
+ tileSources: [{
8
+ "image_host": "http://localhost:8080/image-service",
9
+ "identifier": "irises",
10
+ "width": 4264,
11
+ "height": 3282,
12
+ "scale_factors": [1, 2, 3, 4, 5],
13
+ "tile_width": 1024,
14
+ "tile_height": 1024,
15
+ "formats": [ "jpg", "png" ],
16
+ "qualities": ["native", "bitonal", "grey", "color"],
17
+ "profile": "http://library.stanford.edu/iiif/image-api/compliance.html#level1"
18
+ }]
19
+ });
20
+ </script>
21
+ DOOD
data/config/routes.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  Riiif::Engine.routes.draw do
2
2
  ALLOW_DOTS ||= /[\w.]+/
3
- get "/:id/:region/:size/:rotation/:quality(.:format)" => "images#show", :constraints => { :rotation => ALLOW_DOTS}
3
+ PERCENTAGE ||= /(pct:)?[\w.]+/
4
+ get "/:id/:region/:size/:rotation/:quality(.:format)" => "images#show",
5
+ constraints: { rotation: ALLOW_DOTS, size: PERCENTAGE}
6
+ get "/:id/info(.:format)" => "images#info", :constraints => { :format => /json/}
7
+ get "/:id/view(.:format)" => "images#view"
4
8
  end
data/lib/riiif.rb CHANGED
@@ -5,6 +5,7 @@ module Riiif
5
5
  extend ActiveSupport::Autoload
6
6
  autoload :Image
7
7
  autoload :FileSystemFileResolver
8
+ autoload :HTTPFileResolver
8
9
 
9
10
  class Error < RuntimeError; end
10
11
  class InvalidAttributeError < Error; end
@@ -13,7 +13,7 @@ module Riiif
13
13
 
14
14
  def self.pattern(id)
15
15
  raise ArgumentException, "Invalid characters in id `#{id}`" unless /^\w+$/.match(id)
16
- File.join(base_path, "#{id}.{#{input_types.join(',')}}")
16
+ ::File.join(base_path, "#{id}.{#{input_types.join(',')}}")
17
17
  end
18
18
 
19
19
  end
@@ -0,0 +1,24 @@
1
+ module Riiif
2
+ module HTTPFileResolver
3
+
4
+ # Set a lambda that maps the first parameter (id) to a URL
5
+ # Example:
6
+ #
7
+ # Riiif::HTTPFileResolver.id_to_uri = lambda do |id|
8
+ # "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/#{id}.jpg/600px-#{id}.jpg"
9
+ # end
10
+ #
11
+ mattr_accessor :id_to_uri
12
+
13
+ def self.find(id)
14
+ uri(id)
15
+ end
16
+
17
+ protected
18
+
19
+ def self.uri(id)
20
+ raise "Must set the id_to_uri lambda" if id_to_uri.nil?
21
+ id_to_uri.call(id)
22
+ end
23
+ end
24
+ end
data/lib/riiif/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Riiif
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/riiif.gemspec CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = ""
14
14
  spec.license = "APACHE2"
15
15
 
16
- spec.files = `git ls-files`.split($/)
16
+ spec.files = `git ls-files|grep -v spec/samples`.split($/)
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
@@ -22,6 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "rake"
23
23
  spec.add_development_dependency "engine_cart"
24
24
  spec.add_development_dependency "rspec-rails"
25
- spec.add_dependency 'mini_magick'
26
25
  spec.add_dependency 'rails', '> 3.2.0'
27
26
  end
@@ -12,5 +12,22 @@ describe Riiif::ImagesController do
12
12
  rotation: '0', quality: 'native', format: 'jpg'
13
13
  expect(response).to be_successful
14
14
  expect(response.body).to eq 'IMAGEDATA'
15
+ expect(response.headers['Link']).to eq '<http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2>;rel="profile"'
16
+ end
17
+
18
+ it "should return info" do
19
+ image = double
20
+ expect(Riiif::Image).to receive(:new).with('abcd1234').and_return(image)
21
+ expect(image).to receive(:info).and_return({width: 6000, height: 4000 })
22
+ get :info, id: 'abcd1234', format: 'json'
23
+ expect(response).to be_successful
24
+ json = JSON.parse(response.body)
25
+ expect(json).to eq "@context"=>"http://library.stanford.edu/iiif/image-api/1.1/context.json",
26
+ "@id" =>"http://test.host/image-service/abcd1234",
27
+ "width" =>6000,
28
+ "height" =>4000,
29
+ "formats" => [ "jpg", "png" ],
30
+ "profile" => "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0"
31
+ expect(response.headers['Link']).to eq '<http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2>;rel="profile"'
15
32
  end
16
33
  end
@@ -1,15 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Riiif::Image do
4
+ before { Rails.cache.clear }
5
+ let(:filename) { File.expand_path('spec/samples/world.jp2') }
4
6
  subject { Riiif::Image.new('world') }
5
7
  describe "happy path" do
6
- let(:combinator) { double }
7
- let(:inner) { double }
8
8
  before do
9
- expect(inner).to receive(:format).with('jpg')
10
- expect(inner).to receive(:to_blob).and_return('imagedata')
11
- inner.stub(:combine_options).and_yield(combinator)
12
- subject.stub(:image).and_return(inner)
9
+ expect(subject.image).to receive(:execute).with("convert #{filename} jpg:-").and_return('imagedata')
13
10
  end
14
11
  it "should render" do
15
12
  expect(subject.render('size' => 'full', format: 'jpg')).to eq 'imagedata'
@@ -22,27 +19,42 @@ describe Riiif::Image do
22
19
  end
23
20
  end
24
21
 
22
+ describe "info" do
23
+ it "should return the data" do
24
+ expect(subject.info).to eq height: 400, width:800
25
+ end
26
+ end
25
27
 
26
- describe "mogrify" do
27
- let(:combinator) { double }
28
- let(:inner) { double(format: true, to_blob: 'imagedata') }
28
+ describe "get images from web" do
29
29
  before do
30
- inner.stub(:combine_options).and_yield(combinator)
31
- subject.stub(:image).and_return(inner)
30
+ Riiif::Image.file_resolver = Riiif::HTTPFileResolver
31
+ Riiif::HTTPFileResolver.id_to_uri = lambda do |id|
32
+ "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/#{id}.jpg/600px-#{id}.jpg"
33
+ end
34
+ end
35
+ after do
36
+ Riiif::Image.file_resolver = Riiif::FileSystemFileResolver
37
+ end
38
+ subject { Riiif::Image.new('Cave_26,_Ajanta') }
39
+ it "should be easy" do
40
+ expect(subject.info).to eq height: 390, width:600
32
41
  end
42
+ end
43
+
44
+
45
+ describe "mogrify" do
33
46
  describe "region" do
34
47
  it "should return the original when specifing full size" do
35
- expect(combinator).to_not receive(:crop)
48
+ expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
36
49
  subject.render(region: 'full', format: 'png')
37
50
  end
38
51
  it "should handle absolute geometry" do
39
- expect(combinator).to receive(:crop).with('60x75+80+15')
52
+ expect(subject.image).to receive(:execute).with("convert -crop 60x75+80+15 #{filename} png:-")
40
53
  subject.render(region: '80,15,60,75', format: 'png')
41
54
  end
42
55
  it "should handle percent geometry" do
43
- expect(inner).to receive(:[]).with(:height).and_return(131)
44
- expect(inner).to receive(:[]).with(:width).and_return(175)
45
- expect(combinator).to receive(:crop).with('80%x70+18+13')
56
+ expect(subject.image).to receive(:execute).with("identify -format %hx%w #{filename}").and_return('131x175')
57
+ expect(subject.image).to receive(:execute).with("convert -crop 80%x70+18+13 #{filename} png:-")
46
58
  subject.render(region: 'pct:10,10,80,70', format: 'png')
47
59
  end
48
60
  it "should raise an error for invalid geometry" do
@@ -52,27 +64,31 @@ describe Riiif::Image do
52
64
 
53
65
  describe "resize" do
54
66
  it "should return the original when specifing full size" do
55
- expect(combinator).to_not receive(:resize)
67
+ expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
56
68
  subject.render(size: 'full', format: 'png')
57
69
  end
58
- it "should handle percent sizes" do
59
- expect(combinator).to receive(:resize).with('50%')
70
+ it "should handle integer percent sizes" do
71
+ expect(subject.image).to receive(:execute).with("convert -resize 50% #{filename} png:-")
60
72
  subject.render(size: 'pct:50', format: 'png')
61
73
  end
74
+ it "should handle float percent sizes" do
75
+ expect(subject.image).to receive(:execute).with("convert -resize 12.5% #{filename} png:-")
76
+ subject.render(size: 'pct:12.5', format: 'png')
77
+ end
62
78
  it "should handle w," do
63
- expect(combinator).to receive(:resize).with('50')
79
+ expect(subject.image).to receive(:execute).with("convert -resize 50 #{filename} png:-")
64
80
  subject.render(size: '50,', format: 'png')
65
81
  end
66
82
  it "should handle ,h" do
67
- expect(combinator).to receive(:resize).with('x50')
83
+ expect(subject.image).to receive(:execute).with("convert -resize x50 #{filename} png:-")
68
84
  subject.render(size: ',50', format: 'png')
69
85
  end
70
86
  it "should handle w,h" do
71
- expect(combinator).to receive(:resize).with('150x75!')
87
+ expect(subject.image).to receive(:execute).with("convert -resize 150x75! #{filename} png:-")
72
88
  subject.render(size: '150,75', format: 'png')
73
89
  end
74
90
  it "should handle bestfit (!w,h)" do
75
- expect(combinator).to receive(:resize).with('150x75')
91
+ expect(subject.image).to receive(:execute).with("convert -resize 150x75 #{filename} png:-")
76
92
  subject.render(size: '!150,75', format: 'png')
77
93
  end
78
94
  it "should raise an error for invalid size" do
@@ -81,15 +97,12 @@ describe Riiif::Image do
81
97
  end
82
98
 
83
99
  describe "rotate" do
84
- let(:distorter) { double }
85
100
  it "should return the original when specifing full size" do
86
- expect(combinator).to_not receive(:distort)
101
+ expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
87
102
  subject.render(rotation: '0', format: 'png')
88
103
  end
89
104
  it "should handle floats" do
90
- expect(combinator).to receive(:distort).and_return(distorter)
91
- expect(combinator).to receive(:virtual_pixel).with('white')
92
- expect(distorter).to receive(:+).with("srt", 22.5)
105
+ expect(subject.image).to receive(:execute).with("convert -virtual-pixel white +distort srt 22.5 #{filename} png:-")
93
106
  subject.render(rotation: '22.5', format: 'png')
94
107
  end
95
108
  it "should raise an error for invalid angle" do
@@ -99,20 +112,19 @@ describe Riiif::Image do
99
112
 
100
113
  describe "quality" do
101
114
  it "should return the original when specifing native" do
102
- expect(combinator).to_not receive(:colorspace)
115
+ expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
103
116
  subject.render(quality: 'native', format: 'png')
104
117
  end
105
118
  it "should return the original when specifing color" do
106
- expect(combinator).to_not receive(:colorspace)
119
+ expect(subject.image).to receive(:execute).with("convert #{filename} png:-")
107
120
  subject.render(quality: 'color', format: 'png')
108
121
  end
109
122
  it "should convert to grayscale" do
110
- expect(combinator).to receive(:colorspace).with('Gray')
123
+ expect(subject.image).to receive(:execute).with("convert -colorspace Gray #{filename} png:-")
111
124
  subject.render(quality: 'grey', format: 'png')
112
125
  end
113
126
  it "should convert to bitonal" do
114
- expect(combinator).to receive(:colorspace).with('Gray')
115
- expect(combinator).to receive(:type).with('Bilevel')
127
+ expect(subject.image).to receive(:execute).with("convert -colorspace Gray -type Bilevel #{filename} png:-")
116
128
  subject.render(quality: 'bitonal', format: 'png')
117
129
  end
118
130
  it "should raise an error for invalid angle" do