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 +4 -4
- data/README.md +24 -2
- data/app/helpers/riiif/openseadragon_helper.rb +40 -0
- data/app/models/riiif/file.rb +17 -23
- data/app/models/riiif/image.rb +7 -8
- data/app/views/riiif/images/view.html.erb +1 -20
- data/lib/riiif/file_system_file_resolver.rb +8 -2
- data/lib/riiif/http_file_resolver.rb +57 -5
- data/lib/riiif/version.rb +1 -1
- data/spec/helpers/openseadragon_helper_spec.rb +29 -0
- data/spec/models/file_system_file_resolver_spec.rb +6 -3
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0814f758c2b092db4867b41ebff4cf4d7c05f810
|
4
|
+
data.tar.gz: f4c1c9b97aaf9d4997581306809f1f1598011f2b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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
|
data/app/models/riiif/file.rb
CHANGED
@@ -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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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
|
|
data/app/models/riiif/image.rb
CHANGED
@@ -7,28 +7,27 @@ module Riiif
|
|
7
7
|
|
8
8
|
OUTPUT_FORMATS = %W{jpg png}
|
9
9
|
|
10
|
-
attr_reader :
|
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
|
-
@
|
15
|
+
@image = file_resolver.find(id)
|
16
16
|
end
|
17
17
|
|
18
18
|
def render(args)
|
19
19
|
options = decode_options!(args)
|
20
|
-
|
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
|
31
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
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
@@ -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
|
6
|
-
expect
|
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.
|
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-
|
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
|