iiif_manifest 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -0
  3. data/.rspec +0 -0
  4. data/.rubocop.yml +3 -0
  5. data/.rubocop_todo.yml +36 -0
  6. data/.travis.yml +0 -0
  7. data/CODE_OF_CONDUCT.md +0 -0
  8. data/Gemfile +0 -0
  9. data/LICENSE +0 -0
  10. data/README.md +27 -10
  11. data/Rakefile +0 -0
  12. data/iiif_manifest.gemspec +2 -1
  13. data/lib/iiif_manifest.rb +1 -0
  14. data/lib/iiif_manifest/display_image.rb +0 -0
  15. data/lib/iiif_manifest/iiif_collection.rb +6 -4
  16. data/lib/iiif_manifest/iiif_endpoint.rb +0 -0
  17. data/lib/iiif_manifest/manifest_builder.rb +6 -6
  18. data/lib/iiif_manifest/manifest_builder/canvas_builder.rb +12 -12
  19. data/lib/iiif_manifest/manifest_builder/canvas_builder_factory.rb +3 -3
  20. data/lib/iiif_manifest/manifest_builder/child_manifest_builder_factory.rb +0 -0
  21. data/lib/iiif_manifest/manifest_builder/composite_builder.rb +0 -0
  22. data/lib/iiif_manifest/manifest_builder/composite_builder_factory.rb +0 -0
  23. data/lib/iiif_manifest/manifest_builder/deep_canvas_builder_factory.rb +6 -6
  24. data/lib/iiif_manifest/manifest_builder/iiif_service.rb +0 -0
  25. data/lib/iiif_manifest/manifest_builder/image_builder.rb +9 -9
  26. data/lib/iiif_manifest/manifest_builder/image_service_builder.rb +3 -3
  27. data/lib/iiif_manifest/manifest_builder/record_property_builder.rb +50 -51
  28. data/lib/iiif_manifest/manifest_builder/resource_builder.rb +9 -9
  29. data/lib/iiif_manifest/manifest_builder/sequence_builder.rb +19 -19
  30. data/lib/iiif_manifest/manifest_builder/structure_builder.rb +0 -0
  31. data/lib/iiif_manifest/manifest_factory.rb +3 -3
  32. data/lib/iiif_manifest/manifest_service_locator.rb +0 -0
  33. data/lib/iiif_manifest/v3.rb +13 -0
  34. data/lib/iiif_manifest/v3/display_content.rb +17 -0
  35. data/lib/iiif_manifest/v3/manifest_builder.rb +61 -0
  36. data/lib/iiif_manifest/v3/manifest_builder/body_builder.rb +48 -0
  37. data/lib/iiif_manifest/v3/manifest_builder/canvas_builder.rb +77 -0
  38. data/lib/iiif_manifest/v3/manifest_builder/choice_builder.rb +47 -0
  39. data/lib/iiif_manifest/v3/manifest_builder/content_builder.rb +38 -0
  40. data/lib/iiif_manifest/v3/manifest_builder/iiif_service.rb +235 -0
  41. data/lib/iiif_manifest/v3/manifest_builder/image_service_builder.rb +35 -0
  42. data/lib/iiif_manifest/v3/manifest_builder/record_property_builder.rb +97 -0
  43. data/lib/iiif_manifest/v3/manifest_builder/structure_builder.rb +87 -0
  44. data/lib/iiif_manifest/v3/manifest_factory.rb +38 -0
  45. data/lib/iiif_manifest/v3/manifest_service_locator.rb +148 -0
  46. data/lib/iiif_manifest/version.rb +1 -1
  47. metadata +29 -2
@@ -20,17 +20,17 @@ module IIIFManifest
20
20
 
21
21
  private
22
22
 
23
- def resource
24
- @resource ||= iiif_resource_factory.new
25
- end
23
+ def resource
24
+ @resource ||= iiif_resource_factory.new
25
+ end
26
26
 
27
- def iiif_endpoint
28
- display_image.try(:iiif_endpoint)
29
- end
27
+ def iiif_endpoint
28
+ display_image.try(:iiif_endpoint)
29
+ end
30
30
 
31
- def image_service_builder
32
- image_service_builder_factory.new(iiif_endpoint)
33
- end
31
+ def image_service_builder
32
+ image_service_builder_factory.new(iiif_endpoint)
33
+ end
34
34
  end
35
35
  end
36
36
  end
@@ -20,28 +20,28 @@ module IIIFManifest
20
20
 
21
21
  private
22
22
 
23
- def canvas_builder
24
- canvas_builder_factory.from(work)
25
- end
23
+ def canvas_builder
24
+ canvas_builder_factory.from(work)
25
+ end
26
26
 
27
- def sequence
28
- @sequence ||=
29
- begin
30
- sequence = sequence_factory.new
31
- sequence['@id'] ||= work.manifest_url + '/sequence/normal'
32
- sequence['rendering'] ||= populate_sequence_rendering
33
- canvas_builder.apply(sequence)
34
- sequence
35
- end
36
- end
27
+ def sequence
28
+ @sequence ||=
29
+ begin
30
+ sequence = sequence_factory.new
31
+ sequence['@id'] ||= work.manifest_url + '/sequence/normal'
32
+ sequence['rendering'] ||= populate_sequence_rendering
33
+ canvas_builder.apply(sequence)
34
+ sequence
35
+ end
36
+ end
37
37
 
38
- def populate_sequence_rendering
39
- if work.respond_to?(:sequence_rendering)
40
- work.sequence_rendering.each(&:to_h)
41
- else
42
- []
38
+ def populate_sequence_rendering
39
+ if work.respond_to?(:sequence_rendering)
40
+ work.sequence_rendering.each(&:to_h)
41
+ else
42
+ []
43
+ end
43
44
  end
44
- end
45
45
  end
46
46
  end
47
47
  end
@@ -29,8 +29,8 @@ module IIIFManifest
29
29
 
30
30
  private
31
31
 
32
- def sammelband?(work)
33
- work.respond_to?(:sammelband?) && work.sammelband?
34
- end
32
+ def sammelband?(work)
33
+ work.respond_to?(:sammelband?) && work.sammelband?
34
+ end
35
35
  end
36
36
  end
@@ -0,0 +1,13 @@
1
+ require 'active_support'
2
+ require 'active_support/core_ext/module'
3
+ require 'active_support/core_ext/object'
4
+
5
+ module IIIFManifest
6
+ module V3
7
+ extend ActiveSupport::Autoload
8
+ autoload :ManifestBuilder
9
+ autoload :ManifestFactory
10
+ autoload :ManifestServiceLocator
11
+ autoload :DisplayContent
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class DisplayContent
4
+ attr_reader :url, :width, :height, :duration, :iiif_endpoint, :format, :type, :label
5
+ def initialize(url, type:, width: nil, height: nil, duration: nil, label: nil, format: nil, iiif_endpoint: nil)
6
+ @url = url
7
+ @type = type
8
+ @width = width
9
+ @height = height
10
+ @duration = duration
11
+ @label = label
12
+ @format = format
13
+ @iiif_endpoint = iiif_endpoint
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,61 @@
1
+ require_relative 'manifest_builder/iiif_service'
2
+ require_relative 'manifest_builder/canvas_builder'
3
+ require_relative 'manifest_builder/record_property_builder'
4
+ require_relative 'manifest_builder/choice_builder'
5
+ require_relative 'manifest_builder/content_builder'
6
+ require_relative 'manifest_builder/body_builder'
7
+ require_relative 'manifest_builder/structure_builder'
8
+ require_relative 'manifest_builder/image_service_builder'
9
+
10
+ module IIIFManifest
11
+ module V3
12
+ class ManifestBuilder
13
+ class << self
14
+ # Utility method to wrap the obj into a IIIF V3 compliant language map as needed.
15
+ def language_map(obj)
16
+ return nil if obj.blank?
17
+ return obj if valid_language_map?(obj)
18
+ obj_to_language_map(obj)
19
+ end
20
+
21
+ def valid_language_map?(obj)
22
+ obj.is_a?(Hash) && obj.all? do |k, v|
23
+ k.is_a?(String) && v.is_a?(Array) && v.all? { |o| o.is_a?(String) }
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def obj_to_language_map(obj)
30
+ return nil unless obj.is_a?(String) || (obj.is_a?(Array) && obj.all? { |o| o.is_a?(String) })
31
+ { '@none' => Array(obj) }
32
+ end
33
+ end
34
+
35
+ attr_reader :work,
36
+ :builders,
37
+ :top_record_factory
38
+ def initialize(work, builders:, top_record_factory:)
39
+ @work = work
40
+ @builders = builders
41
+ @top_record_factory = top_record_factory
42
+ end
43
+
44
+ def apply(collection)
45
+ collection['manifests'] ||= []
46
+ collection['manifests'] << to_h
47
+ collection
48
+ end
49
+
50
+ def to_h
51
+ @to_h ||= builders.new(work).apply(top_record)
52
+ end
53
+
54
+ private
55
+
56
+ def top_record
57
+ top_record_factory.new
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,48 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class BodyBuilder
5
+ attr_reader :display_content, :iiif_body_factory, :image_service_builder_factory
6
+ def initialize(display_content, iiif_body_factory:, image_service_builder_factory:)
7
+ @display_content = display_content
8
+ @iiif_body_factory = iiif_body_factory
9
+ @image_service_builder_factory = image_service_builder_factory
10
+ end
11
+
12
+ def apply(annotation)
13
+ build_body
14
+ image_service_builder.apply(body) if iiif_endpoint
15
+ annotation.body = body
16
+ end
17
+
18
+ private
19
+
20
+ def build_body
21
+ body['id'] = display_content.url
22
+ body['type'] = body_type
23
+ body['height'] = display_content.height if display_content.try(:height).present?
24
+ body['width'] = display_content.width if display_content.try(:width).present?
25
+ body['duration'] = display_content.duration if display_content.try(:duration).present?
26
+ body['format'] = display_content.format if display_content.try(:format).present?
27
+ body['label'] = ManifestBuilder.language_map(display_content.label) if display_content.try(:label).present?
28
+ end
29
+
30
+ def body
31
+ @body ||= iiif_body_factory.new
32
+ end
33
+
34
+ def body_type
35
+ display_content.try(:type) || 'Image'
36
+ end
37
+
38
+ def iiif_endpoint
39
+ display_content.try(:iiif_endpoint)
40
+ end
41
+
42
+ def image_service_builder
43
+ image_service_builder_factory.new(iiif_endpoint)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,77 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class CanvasBuilder
5
+ attr_reader :record, :parent, :iiif_canvas_factory, :content_builder,
6
+ :choice_builder, :iiif_annotation_page_factory
7
+
8
+ def initialize(record,
9
+ parent,
10
+ iiif_canvas_factory:,
11
+ content_builder:,
12
+ choice_builder:,
13
+ iiif_annotation_page_factory:)
14
+ @record = record
15
+ @parent = parent
16
+ @iiif_canvas_factory = iiif_canvas_factory
17
+ @content_builder = content_builder
18
+ @choice_builder = choice_builder
19
+ @iiif_annotation_page_factory = iiif_annotation_page_factory
20
+ apply_record_properties
21
+ # Presentation 2.x approach
22
+ attach_image if display_image
23
+ # Presentation 3.0 approach
24
+ attach_content if display_content
25
+ end
26
+
27
+ def canvas
28
+ @canvas ||= iiif_canvas_factory.new
29
+ end
30
+
31
+ def path
32
+ path = "#{parent.manifest_url}/canvas/#{record.id}"
33
+ path << "##{record.media_fragment}" if record.respond_to?(:media_fragment)
34
+ path
35
+ end
36
+
37
+ def apply(items)
38
+ return items if canvas.items.blank?
39
+ items << canvas
40
+ end
41
+
42
+ private
43
+
44
+ def display_image
45
+ record.display_image if record.respond_to?(:display_image)
46
+ end
47
+
48
+ def display_content
49
+ Array.wrap(record.display_content) if record.respond_to?(:display_content)
50
+ end
51
+
52
+ def apply_record_properties
53
+ canvas['id'] = path
54
+ canvas.label = ManifestBuilder.language_map(record.to_s) if record.to_s.present?
55
+ annotation_page['id'] = "#{path}/annotation_page/#{annotation_page.index}"
56
+ canvas.items = [annotation_page]
57
+ end
58
+
59
+ def annotation_page
60
+ @annotation_page ||= iiif_annotation_page_factory.new
61
+ end
62
+
63
+ def attach_image
64
+ content_builder.new(display_image).apply(canvas)
65
+ end
66
+
67
+ def attach_content
68
+ if display_content.size == 1
69
+ content_builder.new(display_content.first).apply(canvas)
70
+ else
71
+ choice_builder.new(display_content).apply(canvas)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,47 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class ChoiceBuilder
5
+ attr_reader :display_content, :iiif_annotation_factory, :body_builder_factory, :iiif_choice_factory
6
+ def initialize(display_content, iiif_annotation_factory:, body_builder_factory:, iiif_choice_factory:)
7
+ @display_content = display_content
8
+ @iiif_annotation_factory = iiif_annotation_factory
9
+ @body_builder_factory = body_builder_factory
10
+ @iiif_choice_factory = iiif_choice_factory
11
+ build_choice
12
+ end
13
+
14
+ def apply(canvas)
15
+ annotation['target'] = canvas['id']
16
+ canvas['width'] = choice.items.first['width']
17
+ canvas['height'] = choice.items.first['height']
18
+ canvas['duration'] = choice.items.first['duration']
19
+ annotation.body = choice
20
+ # Assume first item in canvas is an annotation page
21
+ canvas.items.first.items += [annotation]
22
+ end
23
+
24
+ private
25
+
26
+ def build_choice
27
+ display_content.each do |content|
28
+ content_body = body_builder(content).apply(iiif_annotation_factory.new)
29
+ choice.items += [content_body]
30
+ end
31
+ end
32
+
33
+ def body_builder(content)
34
+ body_builder_factory.new(content)
35
+ end
36
+
37
+ def annotation
38
+ @annotation ||= iiif_annotation_factory.new
39
+ end
40
+
41
+ def choice
42
+ @choice ||= iiif_choice_factory.new
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,38 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class ContentBuilder
5
+ attr_reader :display_content, :iiif_annotation_factory, :body_builder_factory
6
+ def initialize(display_content, iiif_annotation_factory:, body_builder_factory:)
7
+ @display_content = display_content
8
+ @iiif_annotation_factory = iiif_annotation_factory
9
+ @body_builder_factory = body_builder_factory
10
+ build_resource
11
+ end
12
+
13
+ def apply(canvas)
14
+ annotation['target'] = canvas['id']
15
+ canvas['width'] = annotation.body['width']
16
+ canvas['height'] = annotation.body['height']
17
+ canvas['duration'] = annotation.body['duration']
18
+ # Assume first item in canvas is an annotation page
19
+ canvas.items.first.items += [annotation]
20
+ end
21
+
22
+ private
23
+
24
+ def build_resource
25
+ body_builder.apply(annotation)
26
+ end
27
+
28
+ def body_builder
29
+ body_builder_factory.new(display_content)
30
+ end
31
+
32
+ def annotation
33
+ @annotation ||= iiif_annotation_factory.new
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,235 @@
1
+ module IIIFManifest
2
+ module V3
3
+ class ManifestBuilder
4
+ class IIIFService < IIIFManifest::ManifestBuilder::IIIFService
5
+ end
6
+
7
+ class IIIFManifest < IIIFService
8
+ def label
9
+ inner_hash['label']
10
+ end
11
+
12
+ def label=(label)
13
+ inner_hash['label'] = label
14
+ end
15
+
16
+ def summary
17
+ inner_hash['summary']
18
+ end
19
+
20
+ def summary=(summary)
21
+ return unless summary.present?
22
+ inner_hash['summary'] = summary
23
+ end
24
+
25
+ def behavior=(behavior)
26
+ return unless behavior.present?
27
+ inner_hash['behavior'] = behavior
28
+ end
29
+
30
+ def viewing_direction=(viewing_direction)
31
+ return unless viewing_direction.present?
32
+ inner_hash['viewingDirection'] = viewing_direction
33
+ end
34
+
35
+ def viewingDirection
36
+ inner_hash['viewingDirection']
37
+ end
38
+
39
+ def items
40
+ inner_hash['items'] ||= []
41
+ end
42
+
43
+ def items=(items)
44
+ inner_hash['items'] = items
45
+ end
46
+
47
+ def metadata=(metadata)
48
+ inner_hash['metadata'] = metadata
49
+ end
50
+
51
+ def service
52
+ inner_hash['service'] || []
53
+ end
54
+
55
+ def service=(service)
56
+ inner_hash['service'] = service
57
+ end
58
+
59
+ def see_also=(see_also)
60
+ inner_hash['seeAlso'] = see_also
61
+ end
62
+
63
+ def rendering=(rendering)
64
+ inner_hash['rendering'] = rendering
65
+ end
66
+
67
+ def rights=(rights)
68
+ inner_hash['rights'] = rights
69
+ end
70
+
71
+ def initial_attributes
72
+ {
73
+ '@context' => [
74
+ 'http://www.w3.org/ns/anno.jsonld',
75
+ 'http://iiif.io/api/presentation/3/context.json'
76
+ ],
77
+ 'type' => 'Manifest'
78
+ }
79
+ end
80
+
81
+ class Collection < IIIFManifest
82
+ def initial_attributes
83
+ {
84
+ '@context' => [
85
+ 'http://www.w3.org/ns/anno.jsonld',
86
+ 'http://iiif.io/api/presentation/3/context.json'
87
+ ],
88
+ 'type' => 'Collection'
89
+ }
90
+ end
91
+
92
+ def viewing_direction=(_viewing_direction)
93
+ raise NotImplementedError
94
+ end
95
+
96
+ def viewingDirection
97
+ raise NotImplementedError
98
+ end
99
+ end
100
+
101
+ class Canvas < IIIFService
102
+ def label
103
+ inner_hash['label']
104
+ end
105
+
106
+ def label=(label)
107
+ inner_hash['label'] = label
108
+ end
109
+
110
+ def items
111
+ inner_hash['items'] ||= []
112
+ end
113
+
114
+ def items=(items)
115
+ inner_hash['items'] = items
116
+ end
117
+
118
+ def initial_attributes
119
+ {
120
+ 'type' => 'Canvas'
121
+ }
122
+ end
123
+ end
124
+
125
+ class Range < IIIFService
126
+ def initial_attributes
127
+ {
128
+ 'type' => 'Range'
129
+ }
130
+ end
131
+ end
132
+
133
+ class Body < IIIFService
134
+ def service=(service)
135
+ inner_hash['service'] = service
136
+ end
137
+
138
+ def initial_attributes
139
+ {
140
+ }
141
+ end
142
+ end
143
+
144
+ class Choice < IIIFService
145
+ def items
146
+ inner_hash['items'] ||= []
147
+ end
148
+
149
+ def items=(items)
150
+ inner_hash['items'] = items
151
+ end
152
+
153
+ def initial_attributes
154
+ {
155
+ 'type' => 'Choice',
156
+ 'choiceHint' => 'user'
157
+ }
158
+ end
159
+ end
160
+
161
+ class AnnotationPage < IIIFService
162
+ def items
163
+ inner_hash['items'] ||= []
164
+ end
165
+
166
+ def items=(items)
167
+ inner_hash['items'] = items
168
+ end
169
+
170
+ def index
171
+ @index ||= SecureRandom.uuid
172
+ end
173
+
174
+ def initial_attributes
175
+ {
176
+ 'type' => 'AnnotationPage'
177
+ }
178
+ end
179
+ end
180
+
181
+ class Annotation < IIIFService
182
+ def body=(body)
183
+ inner_hash['body'] = body
184
+ end
185
+
186
+ def body
187
+ inner_hash['body']
188
+ end
189
+
190
+ def initial_attributes
191
+ {
192
+ 'type' => 'Annotation',
193
+ 'motivation' => 'painting'
194
+ }
195
+ end
196
+ end
197
+
198
+ class SearchService < IIIFService
199
+ def service=(service)
200
+ inner_hash['service'] = service
201
+ end
202
+
203
+ def search_service=(search_service)
204
+ inner_hash['id'] = search_service
205
+ end
206
+
207
+ def initial_attributes
208
+ {
209
+ '@context' => 'http://iiif.io/api/search/1/context.json',
210
+ 'profile' => 'http://iiif.io/api/search/1/search',
211
+ 'label' => 'Search within this manifest'
212
+ }
213
+ end
214
+ end
215
+
216
+ class AutocompleteService < IIIFService
217
+ def autocomplete_service
218
+ inner_hash['id']
219
+ end
220
+
221
+ def autocomplete_service=(autocomplete_service)
222
+ inner_hash['id'] = autocomplete_service
223
+ end
224
+
225
+ def initial_attributes
226
+ {
227
+ 'profile' => 'http://iiif.io/api/search/1/autocomplete',
228
+ 'label' => 'Get suggested words in this manifest'
229
+ }
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end