riiif 0.0.1 → 0.0.2

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