riiif 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 905d7f9639fc63f7764759b985ea235a4e369645
4
- data.tar.gz: e73244b575876cd67008082a497a5cc9d339777f
3
+ metadata.gz: 0814f758c2b092db4867b41ebff4cf4d7c05f810
4
+ data.tar.gz: f4c1c9b97aaf9d4997581306809f1f1598011f2b
5
5
  SHA512:
6
- metadata.gz: f4e8952000bb0374601d4b6d33e4d5428d721c69f30ef8bf5400e86021a4ce8214e764858401eb74779fe69380f51201ff968a3b678ae879caa7b066e2c7d77c
7
- data.tar.gz: 4b46ed4fd0b9d004123b7fd181702a89f25019a9c891b6573b891ca0c6b0c1432a5814963b65d6cc4a25f63df8c84d7be2027d05e71c12efd6cd9db961237652
6
+ metadata.gz: 81000645e733fc009fd703dbaed8963aa26e32e3e0df85f8476a69b5cda5819462d6ab43673fc6bbd96d45efeedb1c16f1e4e98678325be621e47221d18f855f
7
+ data.tar.gz: 2cf093cacb93384de5df8ca6986a5bdff3789aa5617aad79e2f68c054d5342e7427d231ae0e588e4e7aefd6efac7ccc0545544c47e8d86c86708a78ab50b4332
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Riiif
2
+ [![Gem Version](https://badge.fury.io/rb/riiif.png)](http://badge.fury.io/rb/riiif)
2
3
 
3
4
  A Ruby IIIF image server as a rails engine
4
5
 
@@ -31,7 +32,7 @@ When the Id passed in is "foo_image", then it will look for an image file using
31
32
  ```
32
33
 
33
34
  ### 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
+ It's preferable to use files on the filesystem, because this avoids the overhead of downloading the file. If this is unavoidable, Riiif can be configured to fetch files from the network. To enable this behavior, configure Riiif to use an alternative resolver:
35
36
  ```
36
37
  Riiif::Image.file_resolver = Riiif::HTTPFileResolver
37
38
  ```
@@ -41,6 +42,11 @@ Then we configure the resolver with a mechanism for mapping the provided id to a
41
42
  "http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/#{id}.jpg/600px-#{id}.jpg"
42
43
  end
43
44
  ```
45
+
46
+ This file resolver caches the network files, so you will want to clear out the old files or the cache will expand until you run out of disk space.
47
+ Using a script like this would be a good idea: https://github.com/pulibrary/loris/blob/607567b921404a15a2111fbd7123604f4fdec087/bin/loris-cache_clean.sh
48
+ By default the cache is located in `tmp/network_files`. You can set the cache path like this: `Riiif::HTTPFileResolver.cache_path = '/var/cache'`
49
+
44
50
  ## Usage
45
51
 
46
52
  Mount the gem as an engine:
@@ -57,6 +63,22 @@ Then you can make requests like this:
57
63
  * http://www.example.org/image-service/abcd1234/full/150,75/0/native.jpg
58
64
  * http://www.example.org/image-service/abcd1234/full/!150,75/0/native.jpg
59
65
 
60
- For more information see the IIIF spec:
66
+ ### OpenSeadragon
67
+
68
+ Riiif ships with OpenSeaDragon support. To use it add this in your controller:
69
+
70
+ ```ruby
71
+ helper Riiif::OpenseadragonHelper
72
+ ```
73
+
74
+ Then in your view you can do this:
75
+ ```erb
76
+ <%=javascript_include_tag "openseadragon.js" %>
77
+ <%= openseadragon_viewer(@image.id, html: {style: 'width: 800px; height: 600px;'}) %>
78
+ ```
79
+
80
+
81
+ ## For more information
82
+ see the IIIF spec:
61
83
 
62
84
  http://www-sul.stanford.edu/iiif/image-api/1.1/
@@ -0,0 +1,40 @@
1
+ module Riiif
2
+ module OpenseadragonHelper
3
+ def openseadragon_viewer(id_or_image, options={})
4
+ image = case id_or_image
5
+ when String
6
+ Image.new(id_or_image)
7
+ when Image
8
+ id_or_image
9
+ end
10
+ options[:tile_width] ||= '1024'
11
+ options[:tile_height] ||= '1024'
12
+ options[:html_id] ||= 'openseadragon1'
13
+ options[:html] ||= {}
14
+ options[:html][:id] = options[:html_id]
15
+ options[:image_host] ||= '/image-service'
16
+ options[:prefix_url] ||= '/assets/openseadragon/'
17
+ js =<<-EOF
18
+ var viewer = OpenSeadragon({
19
+ id: "#{options[:html_id]}",
20
+ prefixUrl: "#{options[:prefix_url]}",
21
+ tileSources: [{
22
+ "image_host": "#{options[:image_host]}",
23
+ "identifier": "#{image.id}",
24
+ "width": #{image.info[:width]},
25
+ "height": #{image.info[:height]},
26
+ "scale_factors": [1, 2, 3, 4, 5],
27
+ "tile_width": #{options[:tile_width]},
28
+ "tile_height": #{options[:tile_height]},
29
+ "formats": [ "jpg", "png" ],
30
+ "qualities": ["native", "bitonal", "grey", "color"],
31
+ "profile": "http://library.stanford.edu/iiif/image-api/compliance.html#level3"
32
+ }]
33
+ });
34
+ EOF
35
+
36
+ #<%=javascript_include_tag "openseadragon.js" %>
37
+ content_tag(:div, '', options[:html]) + javascript_tag(js)
38
+ end
39
+ end
40
+ end
@@ -2,27 +2,18 @@ require 'open3'
2
2
  module Riiif
3
3
  class File
4
4
  include Open3
5
+ include ActiveSupport::Benchmarkable
6
+
5
7
  attr_reader :path
8
+
9
+ delegate :logger, to: :Rails
10
+
6
11
  # @param input_path [String] The location of an image file
7
12
  def initialize(input_path, tempfile = nil)
8
- raise "HUH" if input_path.is_a? Riiif::File
9
13
  @path = input_path
10
14
  @tempfile = tempfile # ensures that the tempfile will stick around until this file is garbage collected.
11
15
  end
12
16
 
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
17
  def self.read(stream, ext)
27
18
  create(ext) do |f|
28
19
  while chunk = stream.read(8192)
@@ -60,7 +51,6 @@ module Riiif
60
51
  command << ' -type Bilevel'
61
52
  end
62
53
  command << " #{path} #{options[:format]}:-"
63
- Rails.logger.debug "RIIIF executed: #{command}"
64
54
  execute(command)
65
55
  end
66
56
 
@@ -71,15 +61,19 @@ module Riiif
71
61
  end
72
62
 
73
63
  private
64
+
74
65
  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?
66
+ out = nil
67
+ benchmark ("Riiif executed #{command}") do
68
+ stdin, stdout, stderr, wait_thr = popen3(command)
69
+ stdin.close
70
+ stdout.binmode
71
+ out = stdout.read
72
+ stdout.close
73
+ err = stderr.read
74
+ stderr.close
75
+ raise "Unable to execute command \"#{command}\"\n#{err}" unless wait_thr.value.success?
76
+ end
83
77
  out
84
78
  end
85
79
 
@@ -7,28 +7,27 @@ module Riiif
7
7
 
8
8
  OUTPUT_FORMATS = %W{jpg png}
9
9
 
10
- attr_reader :path_name, :id
10
+ attr_reader :id, :image
11
11
 
12
12
  # @param [String] id The identifier of the file
13
13
  def initialize(id)
14
14
  @id = id
15
- @path_name = file_resolver.find(id)
15
+ @image = file_resolver.find(id)
16
16
  end
17
17
 
18
18
  def render(args)
19
19
  options = decode_options!(args)
20
- # Use a MD5 digest to ensure the keys aren't too long.
21
- digest = Digest::MD5.hexdigest(options.merge(id: id).to_s)
22
- puts digest
23
- Rails.cache.fetch(digest, compress: true, expires_in: 3.days) do
20
+ Rails.cache.fetch(Image.cache_key(id, options), compress: true, expires_in: 3.days) do
24
21
  image.extract(options)
25
22
  end
26
23
  end
27
24
 
28
25
  delegate :info, to: :image
29
26
 
30
- def image
31
- @image ||= Riiif::File.open(path_name)
27
+ def self.cache_key(id, options)
28
+ str = options.merge(id: id).delete_if {|_, v| v.nil?}.to_s
29
+ # Use a MD5 digest to ensure the keys aren't too long.
30
+ Digest::MD5.hexdigest(str)
32
31
  end
33
32
 
34
33
  private
@@ -1,21 +1,2 @@
1
- <div id="openseadragon1" style="width: 800px; height: 600px;"></div>
2
1
  <%=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": "<%= @image.id %>",
10
- "width": <%= @image.info[:width] %>,
11
- "height": <%= @image.info[:height] %>,
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
2
+ <%= openseadragon_viewer(@image.id, html: {style: 'width: 800px; height: 600px;'}) %>
@@ -8,11 +8,17 @@ module Riiif
8
8
 
9
9
 
10
10
  def self.find(id)
11
- Dir.glob(pattern(id)).first
11
+ Riiif::File.new(path(id))
12
12
  end
13
13
 
14
+ def self.path(id)
15
+ search = pattern(id)
16
+ Dir.glob(search).first || raise(Errno::ENOENT, search)
17
+ end
18
+
19
+
14
20
  def self.pattern(id)
15
- raise ArgumentException, "Invalid characters in id `#{id}`" unless /^[\w-]+$/.match(id)
21
+ raise ArgumentError, "Invalid characters in id `#{id}`" unless /^[\w\-:]+$/.match(id)
16
22
  ::File.join(base_path, "#{id}.{#{input_types.join(',')}}")
17
23
  end
18
24
 
@@ -1,3 +1,6 @@
1
+ require 'open-uri'
2
+ require 'active_support/core_ext/file/atomic'
3
+
1
4
  module Riiif
2
5
  module HTTPFileResolver
3
6
 
@@ -10,15 +13,64 @@ module Riiif
10
13
  #
11
14
  mattr_accessor :id_to_uri
12
15
 
16
+ mattr_accessor :cache_path
17
+ self.cache_path = 'tmp/network_files'
18
+
19
+
13
20
  def self.find(id)
14
- uri(id)
21
+ remote = RemoteFile.new(uri(id))
22
+ Riiif::File.new(remote.fetch)
15
23
  end
16
24
 
17
- protected
25
+ class RemoteFile
26
+ include ActiveSupport::Benchmarkable
27
+ delegate :logger, to: :Rails
28
+ attr_reader :url
29
+ def initialize(url)
30
+ @url = url
31
+ end
32
+
33
+ def fetch
34
+ download_file unless ::File.exist?(file_name)
35
+ file_name
36
+ end
37
+
38
+ private
39
+
40
+ def ext
41
+ @ext ||= ::File.extname(URI.parse(url).path)
42
+ end
18
43
 
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)
44
+ def file_name
45
+ @cache_file_name ||= ::File.join(HTTPFileResolver.cache_path, Digest::MD5.hexdigest(url)+"#{ext}")
46
+ end
47
+
48
+ def download_file
49
+ ensure_cache_path(::File.dirname(file_name))
50
+ benchmark ("Riiif downloaded #{url}") do
51
+ ::File.atomic_write(file_name, HTTPFileResolver.cache_path) do |local|
52
+ Kernel::open(url) do |remote|
53
+ while chunk = remote.read(8192)
54
+ local.write(chunk)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ # Make sure a file path's directories exist.
62
+ def ensure_cache_path(path)
63
+ FileUtils.makedirs(path) unless ::File.exist?(path)
64
+ end
22
65
  end
66
+
67
+
68
+ protected
69
+
70
+ def self.uri(id)
71
+ raise "Must set the id_to_uri lambda" if id_to_uri.nil?
72
+ id_to_uri.call(id)
73
+ end
74
+
23
75
  end
24
76
  end
data/lib/riiif/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Riiif
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Riiif::OpenseadragonHelper do
4
+
5
+ it "should draw the viewer" do
6
+ out = openseadragon_viewer('world')
7
+ out.should == '<div id="openseadragon1"></div><script>
8
+ //<![CDATA[
9
+ var viewer = OpenSeadragon({
10
+ id: "openseadragon1",
11
+ prefixUrl: "/assets/openseadragon/",
12
+ tileSources: [{
13
+ "image_host": "/image-service",
14
+ "identifier": "world",
15
+ "width": 800,
16
+ "height": 400,
17
+ "scale_factors": [1, 2, 3, 4, 5],
18
+ "tile_width": 1024,
19
+ "tile_height": 1024,
20
+ "formats": [ "jpg", "png" ],
21
+ "qualities": ["native", "bitonal", "grey", "color"],
22
+ "profile": "http://library.stanford.edu/iiif/image-api/compliance.html#level3"
23
+ }]
24
+ });
25
+
26
+ //]]>
27
+ </script>'
28
+ end
29
+ end
@@ -2,14 +2,17 @@ require 'spec_helper'
2
2
 
3
3
  describe Riiif::FileSystemFileResolver do
4
4
  subject { Riiif::FileSystemFileResolver }
5
- it "should get nil when the file isn't found" do
6
- expect(subject.find('1234')).to be_nil
5
+ it "should raise an error when the file isn't found" do
6
+ expect{subject.find('1234')}.to raise_error Errno::ENOENT
7
7
  end
8
8
  it "should get the jpeg2000 file" do
9
- expect(subject.find('world')).to eq Riiif::FileSystemFileResolver.root + '/spec/samples/world.jp2'
9
+ expect(subject.find('world').path).to eq Riiif::FileSystemFileResolver.root + '/spec/samples/world.jp2'
10
10
  end
11
11
 
12
12
  it "should accept ids with dashes" do
13
13
  subject.pattern('foo-bar-baz')
14
14
  end
15
+ it "should accept ids with colins" do
16
+ subject.pattern('fo:baz')
17
+ end
15
18
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riiif
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Coyne
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-18 00:00:00.000000000 Z
11
+ date: 2013-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,6 +94,7 @@ files:
94
94
  - README.md
95
95
  - Rakefile
96
96
  - app/controllers/riiif/images_controller.rb
97
+ - app/helpers/riiif/openseadragon_helper.rb
97
98
  - app/models/riiif/file.rb
98
99
  - app/models/riiif/image.rb
99
100
  - app/views/riiif/images/view.html.erb
@@ -105,6 +106,7 @@ files:
105
106
  - lib/riiif/version.rb
106
107
  - riiif.gemspec
107
108
  - spec/controllers/images_controller_spec.rb
109
+ - spec/helpers/openseadragon_helper_spec.rb
108
110
  - spec/models/file_system_file_resolver_spec.rb
109
111
  - spec/models/image_spec.rb
110
112
  - spec/routing/resize_routes_spec.rb
@@ -162,6 +164,7 @@ specification_version: 4
162
164
  summary: A rails engine that support IIIF requests
163
165
  test_files:
164
166
  - spec/controllers/images_controller_spec.rb
167
+ - spec/helpers/openseadragon_helper_spec.rb
165
168
  - spec/models/file_system_file_resolver_spec.rb
166
169
  - spec/models/image_spec.rb
167
170
  - spec/routing/resize_routes_spec.rb