iiif_manifest 0.4.0 → 0.5.0

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 (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