wax_iiif 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +29 -0
- data/.rspec +2 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/Guardfile +10 -0
- data/LICENSE.md +30 -0
- data/README.md +8 -0
- data/Rakefile +24 -0
- data/lib/iiif_s3/base_properties.rb +95 -0
- data/lib/iiif_s3/builder.rb +254 -0
- data/lib/iiif_s3/collection.rb +61 -0
- data/lib/iiif_s3/config.rb +142 -0
- data/lib/iiif_s3/errors.rb +37 -0
- data/lib/iiif_s3/full_image.rb +20 -0
- data/lib/iiif_s3/image_info.rb +96 -0
- data/lib/iiif_s3/image_record.rb +141 -0
- data/lib/iiif_s3/image_tile.rb +46 -0
- data/lib/iiif_s3/image_variant.rb +126 -0
- data/lib/iiif_s3/manifest.rb +151 -0
- data/lib/iiif_s3/thumbnail.rb +35 -0
- data/lib/iiif_s3/utilities.rb +12 -0
- data/lib/iiif_s3/utilities/helpers.rb +96 -0
- data/lib/iiif_s3/utilities/pdf_splitter.rb +50 -0
- data/lib/iiif_s3/version.rb +5 -0
- data/lib/wax_iiif.rb +83 -0
- data/spec/base_properties_spec.rb +22 -0
- data/spec/data/blank.csv +0 -0
- data/spec/data/invalid.csv +1 -0
- data/spec/data/no_header.csv +1 -0
- data/spec/data/test.csv +2 -0
- data/spec/data/test.jpg +0 -0
- data/spec/data/test.pdf +0 -0
- data/spec/iiif_s3/builder_spec.rb +152 -0
- data/spec/iiif_s3/collection_spec.rb +68 -0
- data/spec/iiif_s3/config_spec.rb +15 -0
- data/spec/iiif_s3/image_info_spec.rb +57 -0
- data/spec/iiif_s3/image_record_spec.rb +96 -0
- data/spec/iiif_s3/image_variant_spec.rb +71 -0
- data/spec/iiif_s3/manifest_spec.rb +97 -0
- data/spec/iiif_s3/utilities/pdf_splitter_spec.rb +17 -0
- data/spec/shared_contexts.rb +115 -0
- data/spec/spec_helper.rb +12 -0
- data/test.rb +77 -0
- data/wax_iiif.gemspec +29 -0
- metadata +218 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module IiifS3
|
2
|
+
|
3
|
+
#
|
4
|
+
# Class Collection is an abstraction over the IIIF Collection, which is an aggregation
|
5
|
+
# of IIIF manifests.
|
6
|
+
#
|
7
|
+
# @author David Newbury <david.newbury@gmail.com>
|
8
|
+
#
|
9
|
+
class Collection
|
10
|
+
|
11
|
+
# @return [String] The IIIF Type for collections
|
12
|
+
TYPE = "sc:Collection"
|
13
|
+
|
14
|
+
include BaseProperties
|
15
|
+
attr_reader :collections, :manifests
|
16
|
+
|
17
|
+
def initialize(label, config, name="top")
|
18
|
+
raise IiifS3::Error::MissingCollectionName if label.nil? || label.empty?
|
19
|
+
@config = config
|
20
|
+
@manifests = []
|
21
|
+
@collections = []
|
22
|
+
self.label = label
|
23
|
+
self.id = "collection/#{name}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_collection(collection)
|
27
|
+
raise IiifS3::Error::NotACollection unless collection.respond_to?(:type) && collection.type == Collection::TYPE
|
28
|
+
@collections.push(collection)
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_manifest(manifest)
|
32
|
+
raise IiifS3::Error::NotAManifest unless manifest.respond_to?(:type) && manifest.type == Manifest::TYPE
|
33
|
+
@manifests.push(manifest)
|
34
|
+
end
|
35
|
+
|
36
|
+
# The JSON representation of this collection in the IIIF-expected format
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# @return [String] The JSON representation as a string
|
40
|
+
#
|
41
|
+
def to_json
|
42
|
+
obj = base_properties
|
43
|
+
obj["collections"] = collect_object(collections) unless collections.empty?
|
44
|
+
obj["manifests"] = collect_object(manifests) unless manifests.empty?
|
45
|
+
JSON.pretty_generate obj
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def collect_object(things)
|
51
|
+
things.collect do |thing|
|
52
|
+
{
|
53
|
+
"@id" => thing.id,
|
54
|
+
"@type" => thing.type,
|
55
|
+
"label" => thing.label
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module IiifS3
|
2
|
+
|
3
|
+
# Config provides a data structure for holding the configuration settings
|
4
|
+
# for the IiifS3 class.
|
5
|
+
#
|
6
|
+
# @author David Newbury <david.newbury@gmail.com>
|
7
|
+
#
|
8
|
+
class Config
|
9
|
+
|
10
|
+
# @return [String] The default URL to append to all IDs.
|
11
|
+
DEFAULT_URL = "http://0.0.0.0"
|
12
|
+
# @return [String] The name of the subdirectory where generated images live
|
13
|
+
DEFAULT_IMAGE_DIRECTORY_NAME = "images"
|
14
|
+
# @return [String] The default path for writing generated image files
|
15
|
+
DEFAULT_OUTPUT_DIRECTORY = "./build"
|
16
|
+
# @return [Number] The default tile width/height in pixels
|
17
|
+
DEFAULT_TILE_WIDTH = 512
|
18
|
+
# @return [Array<Number>] The default tile scaling factors
|
19
|
+
DEFAULT_TILE_SCALE_FACTORS = [1,2,4,8]
|
20
|
+
# @return [Number] The default thumbnail size in pixels
|
21
|
+
DEFAULT_THUMBNAIL_SIZE = 250
|
22
|
+
|
23
|
+
#
|
24
|
+
# @!attribute [r] base_url
|
25
|
+
# @return [String] The protocol, domain, and port used for generating URIs.
|
26
|
+
# Defaults to {IiifS3::Config::DEFAULT_URL}
|
27
|
+
attr_reader :base_url
|
28
|
+
#
|
29
|
+
# @!attribute [r] use_extensions
|
30
|
+
# @return [Boolean] Should generated IDs and files have a .json extension?
|
31
|
+
# Defaults to true
|
32
|
+
attr_reader :use_extensions
|
33
|
+
#
|
34
|
+
# @!attribute [r] output_dir
|
35
|
+
# @return [String] The directory on the local file system where the output
|
36
|
+
# files should be saved
|
37
|
+
# Defaults to {IiifS3::Config::DEFAULT_OUTPUT_DIRECTORY}
|
38
|
+
attr_reader :output_dir
|
39
|
+
#
|
40
|
+
# @!attribute [r] prefix
|
41
|
+
# @return [String] A prefix to be appended between the base URI and the id.
|
42
|
+
# Can be blank,and it will automatically prepend a slash if one is not
|
43
|
+
# provided.
|
44
|
+
# Defaults to ""
|
45
|
+
attr_reader :prefix
|
46
|
+
#
|
47
|
+
# @!attribute [r] image_directory_name
|
48
|
+
# @return [String] The name of the directory/prefix where image files will be
|
49
|
+
# located.
|
50
|
+
# Defaults to IiifS3::Config::DEFAULT_IMAGE_DIRECTORY_NAME
|
51
|
+
attr_reader :image_directory_name
|
52
|
+
#
|
53
|
+
# @!attribute [r] tile_width
|
54
|
+
# @return [Number] The width (and height) of each individual tile.
|
55
|
+
# Defaults to IiifS3::Config::DEFAULT_TILE_WIDTH
|
56
|
+
attr_reader :tile_width
|
57
|
+
#
|
58
|
+
# @!attribute [r] tile
|
59
|
+
# @return [Array<Number>] An array of tile ratios to be uploaded.
|
60
|
+
# Defaults to IiifS3::Config::DEFAULT_TILE_SCALE_FACTORS
|
61
|
+
attr_reader :tile_scale_factors
|
62
|
+
#
|
63
|
+
# @!attribute [r] variants
|
64
|
+
# @return [Hash] A Hash of key/value pairs. Each key should be the name of a variant,
|
65
|
+
# each value the maximum pixel dimension of the longest side.
|
66
|
+
# Defaults to {}
|
67
|
+
attr_reader :variants
|
68
|
+
#
|
69
|
+
# @!attribute [r] upload_to_s3
|
70
|
+
# @return [Boolean] Should the files that are created by automatically uploaded to Amazon S3?
|
71
|
+
# Defaults to false
|
72
|
+
attr_reader :upload_to_s3
|
73
|
+
|
74
|
+
# @!attribute [r] thumbnail_size
|
75
|
+
# @return [Number] The max width in pixels for a thumbnail image
|
76
|
+
attr_reader :thumbnail_size
|
77
|
+
|
78
|
+
# @!attribute [r] verbose
|
79
|
+
# @return [Bool] Should the program log information to the console?
|
80
|
+
attr_reader :verbose
|
81
|
+
alias :verbose? :verbose
|
82
|
+
|
83
|
+
# @!attribute [r] s3
|
84
|
+
# @return [IiifS3::AmazonS3] the S3 object for this system
|
85
|
+
attr_reader :s3
|
86
|
+
|
87
|
+
|
88
|
+
# Initialize a new configuration option.
|
89
|
+
#
|
90
|
+
# @param [Hash] opts
|
91
|
+
# @option opts [Boolean] :upload_to_s3 if true, images and metadata will be
|
92
|
+
# uploaded to Amazon S3. Defaults to False.
|
93
|
+
# @option opts [Number] :tile_width The width in pixels for generated tiles.
|
94
|
+
# Defaults to {DEFAULT_TILE_WIDTH}
|
95
|
+
# @option opts [Array<Number>] :tile_scale_factors An array of ratios for generated tiles.
|
96
|
+
# Defaults to {DEFAULT_TILE_SCALE_FACTORS}
|
97
|
+
# @option opts [String] :image_directory_name The name of the subdirectory for actual
|
98
|
+
# image data. Defaults to {DEFAULT_IMAGE_DIRECTORY_NAME}
|
99
|
+
# @option opts [String] :output_dir The name of the directory for generated files.
|
100
|
+
# image data. Defaults to {DEFAULT_OUTPUT_DIRECTORY}
|
101
|
+
# @option opts [String] :base_url The base URL for the generated URIs. Defaults to
|
102
|
+
# {DEFAULT_URL} if not auto-uploading to S3 and to the s3 bucket if upload_to_s3 is enabled.
|
103
|
+
# @option opts [Number] :thumbnail_size the size in pixels
|
104
|
+
# for the largest side of the thumbnail images. Defaults to {DEFAULT_THUMBNAIL_SIZE}.
|
105
|
+
# @option opts [Bool] :use_extensions (true) should files have exensions appended?
|
106
|
+
# @option opts [Bool] :verbose (false) Should debug information be printed to the console?
|
107
|
+
# @option opts [String] :prefix ("") a prefix (read: subdirectory) for the generated URIs.
|
108
|
+
# @option opts [Hash{String: String}] :variants
|
109
|
+
def initialize(opts = {})
|
110
|
+
@upload_to_s3 = opts[:upload_to_s3] || false
|
111
|
+
@s3 = IiifS3::AmazonS3.new if @upload_to_s3
|
112
|
+
@tile_width = opts[:tile_width] || DEFAULT_TILE_WIDTH
|
113
|
+
@tile_scale_factors = opts[:tile_scale_factors] || DEFAULT_TILE_SCALE_FACTORS
|
114
|
+
@image_directory_name = opts[:image_directory_name] || DEFAULT_IMAGE_DIRECTORY_NAME
|
115
|
+
@base_url = opts[:base_url] || ( @upload_to_s3 ? @s3.bucket.url : DEFAULT_URL)
|
116
|
+
@use_extensions = opts.fetch(:use_extensions, true) ## true
|
117
|
+
@output_dir = opts[:output_dir] || DEFAULT_OUTPUT_DIRECTORY
|
118
|
+
@variants = opts[:variants] || {}
|
119
|
+
@thumbnail_size = opts[:thumbnail_size] || DEFAULT_THUMBNAIL_SIZE
|
120
|
+
@verbose = opts.fetch(:verbose, false) ## false
|
121
|
+
@prefix = opts[:prefix] || ""
|
122
|
+
if @prefix.length > 0 && @prefix[0] != "/"
|
123
|
+
@prefix = "/#{@prefix}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# Compare two configuration files
|
129
|
+
#
|
130
|
+
# @param [IiifS3::Config] other_config The configuration file to compare
|
131
|
+
#
|
132
|
+
# @return [Bool] True if they are the same, false otherwise
|
133
|
+
#
|
134
|
+
def ==(other_config)
|
135
|
+
valid = true
|
136
|
+
self.instance_variables.each do |v|
|
137
|
+
valid &&= instance_variable_get(v) == other_config.instance_variable_get(v)
|
138
|
+
end
|
139
|
+
valid
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module IiifS3
|
2
|
+
|
3
|
+
#
|
4
|
+
# Module Error collects standard errors for th IiifS3 library.
|
5
|
+
module Error
|
6
|
+
|
7
|
+
# Class BlankCSV indicates that a provided CSV has no data.
|
8
|
+
class BlankCSV < StandardError; end
|
9
|
+
|
10
|
+
# Class InvalidCSV indicates that there is something wrong with the provided CSV.
|
11
|
+
class InvalidCSV < StandardError; end
|
12
|
+
|
13
|
+
# Class BadAmazonCredentials indicates that something was wrong with the Amazon login information.
|
14
|
+
class BadAmazonCredentials < StandardError; end
|
15
|
+
|
16
|
+
# Class MissingCollectionName indicates that the collection provided did not have a label.
|
17
|
+
class MissingCollectionName < StandardError; end
|
18
|
+
|
19
|
+
# Class NotACollection indicates that the object provided was not a sc:Collection.
|
20
|
+
class NotACollection < StandardError; end
|
21
|
+
|
22
|
+
# Class NotAManifest indicates that the object provided was not a sc:Manifest.
|
23
|
+
class NotAManifest < StandardError; end
|
24
|
+
|
25
|
+
# Class InvalidCSV indicates that there is something wrong with the provided Image Data.
|
26
|
+
class InvalidImageData < StandardError; end
|
27
|
+
|
28
|
+
# Class InvalidViewingDirection indicates that the direction provided was not a valid viewing direction.
|
29
|
+
class InvalidViewingDirection < InvalidImageData; end
|
30
|
+
|
31
|
+
# Class MultiplePrimaryImages indicates that multiple images were tagged as primary for a given manifest.
|
32
|
+
class MultiplePrimaryImages < InvalidImageData; end
|
33
|
+
|
34
|
+
# Class NoMasterError indicates that all of the images in a collection are secondary images.
|
35
|
+
class NoMasterError < InvalidImageData; end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require "mini_magick"
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module IiifS3
|
6
|
+
|
7
|
+
#
|
8
|
+
# Class FullImage is a standard image variant that does not resize the image at all.
|
9
|
+
class FullImage < ImageVariant
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def filestring
|
14
|
+
"/full/full/0"
|
15
|
+
end
|
16
|
+
|
17
|
+
def resize(width, height); end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module IiifS3
|
2
|
+
|
3
|
+
#
|
4
|
+
# Class ImageInfo is a data object for the JSON representation of the image.
|
5
|
+
#
|
6
|
+
# It is designed to support the http://iiif.io/api/image/2.0/#image-information spec.
|
7
|
+
class ImageInfo
|
8
|
+
|
9
|
+
attr_accessor :id
|
10
|
+
attr_accessor :width
|
11
|
+
attr_accessor :height
|
12
|
+
attr_accessor :tile_width
|
13
|
+
attr_accessor :tile_scale_factors
|
14
|
+
|
15
|
+
def initialize(uri, variants, tile_width= nil, tile_scale_factors = nil)
|
16
|
+
|
17
|
+
raise IiifS3::Error::InvalidImageData, "No full variant provided: variants: #{variants}" unless variants["full"]
|
18
|
+
raise IiifS3::Error::InvalidImageData, "No thumbnail variant provided: variants: #{variants}" unless variants["thumbnail"]
|
19
|
+
raise IiifS3::Error::InvalidImageData, "No URI was provided for this image!" if uri.nil?
|
20
|
+
|
21
|
+
@id = uri
|
22
|
+
full = variants["full"]
|
23
|
+
@variants = variants
|
24
|
+
@width = full.width
|
25
|
+
@height = full.height
|
26
|
+
@tile_width = tile_width
|
27
|
+
@tile_scale_factors = tile_scale_factors
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Hash] a collection of valid sizes based on the available image variants
|
31
|
+
#
|
32
|
+
def sizes
|
33
|
+
@variants.collect do |name,obj|
|
34
|
+
{"width" => obj.width, "height" => obj.height}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# The hash of tile information, or nil if the information does not exist.
|
39
|
+
#
|
40
|
+
#
|
41
|
+
# @return [Hash, nil] A hash of the tile metadata properly formatted for IIIF JSON.
|
42
|
+
#
|
43
|
+
def tiles
|
44
|
+
return nil if @tile_scale_factors.nil? || @tile_scale_factors.empty?
|
45
|
+
|
46
|
+
return [{
|
47
|
+
"width" => @tile_width,
|
48
|
+
"scaleFactors" => @tile_scale_factors
|
49
|
+
}]
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# Generate the JSON data for this image in the IIIF-expected format.
|
54
|
+
#
|
55
|
+
#
|
56
|
+
# @return [String] the JSON representation of this image
|
57
|
+
#
|
58
|
+
def to_json
|
59
|
+
obj = {
|
60
|
+
"@context" => context,
|
61
|
+
"@id" => URI.escape(id),
|
62
|
+
"protocol" => protocol,
|
63
|
+
"width" => width,
|
64
|
+
"height" => height,
|
65
|
+
"sizes" => sizes,
|
66
|
+
"profile" => profile,
|
67
|
+
}
|
68
|
+
obj["tiles"] = tiles unless tiles.nil?
|
69
|
+
obj["profile"] = profile
|
70
|
+
obj["service"] = service unless service.nil?
|
71
|
+
JSON.pretty_generate obj
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [String] The IIIF context for this image
|
75
|
+
def context
|
76
|
+
IiifS3::IMAGE_CONTEXT
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [String] The IIIF protocol for this image
|
80
|
+
def protocol
|
81
|
+
IiifS3::IMAGE_PROTOCOL
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [String] The IIIF profile this image supports
|
85
|
+
def profile
|
86
|
+
[IiifS3::LEVEL_0,{
|
87
|
+
supports: ["cors","sizeByWhListed", "baseUriRedirect"]
|
88
|
+
}]
|
89
|
+
end
|
90
|
+
|
91
|
+
# TODO: Implement this. See <http://iiif.io/api/annex/services/#physical-dimensions>
|
92
|
+
def service
|
93
|
+
return nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module IiifS3
|
2
|
+
# Class ImageRecord provides a data structure for a single image file.
|
3
|
+
# It contains information for content from the manifest level down to the
|
4
|
+
# specific variants of the images.
|
5
|
+
#
|
6
|
+
# It has the concept of primary images, which are the first (or only) image
|
7
|
+
# in the sequence. This is the image where much of the top-level metadata is
|
8
|
+
# taken from. Each sequence can only have a single primary image, but that
|
9
|
+
# constraint in enforced
|
10
|
+
#
|
11
|
+
# @author David Newbury <david.newbury@gmail.com>
|
12
|
+
#
|
13
|
+
class ImageRecord
|
14
|
+
attr_accessor :id
|
15
|
+
attr_accessor :label
|
16
|
+
attr_accessor :description
|
17
|
+
attr_accessor :attribution
|
18
|
+
attr_accessor :license
|
19
|
+
attr_accessor :metadata
|
20
|
+
|
21
|
+
attr_accessor :logo
|
22
|
+
attr_accessor :variants
|
23
|
+
|
24
|
+
attr_writer :page_number
|
25
|
+
attr_writer :section
|
26
|
+
attr_writer :section_label
|
27
|
+
attr_writer :is_document
|
28
|
+
|
29
|
+
# @param [Hash] opts
|
30
|
+
# @option opts [String] :id The primary ID for the object.
|
31
|
+
# @option opts [String] :label The human-readable label for all grouped records
|
32
|
+
# @option opts [String] :description A longer, human-readable description of the gropued records
|
33
|
+
# @option opts [String] :logo A URL pointing to a logo of the institution
|
34
|
+
# @option opts [Hash] :variants A hash of derivative names and sizes
|
35
|
+
# @example {thumb: 150}
|
36
|
+
def initialize(opts={})
|
37
|
+
opts.each do |key, val|
|
38
|
+
self.send("#{key}=",val) if self.methods.include? "#{key}=".to_sym
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# The page number of this image. Defaults to 1.
|
43
|
+
#
|
44
|
+
# @return [Number]
|
45
|
+
def page_number
|
46
|
+
@page_number || 1
|
47
|
+
end
|
48
|
+
|
49
|
+
# The path to this image.
|
50
|
+
#
|
51
|
+
# @return [String]
|
52
|
+
def image_path
|
53
|
+
@path
|
54
|
+
end
|
55
|
+
|
56
|
+
def path=(_path)
|
57
|
+
raise IiifS3::Error::InvalidImageData, "Path is invalid: '#{_path}'" unless _path && File.exist?(_path)
|
58
|
+
@path = _path
|
59
|
+
end
|
60
|
+
|
61
|
+
# Is this image part of a document, or is it a standalone image (or image sequence)?
|
62
|
+
#
|
63
|
+
# Currently, the only effects the page viewing hint for the image sequence.
|
64
|
+
# This will only have an effect on the primary image for this sequence.
|
65
|
+
#
|
66
|
+
# @return [Bool]
|
67
|
+
#
|
68
|
+
def is_document
|
69
|
+
return !!@is_document
|
70
|
+
end
|
71
|
+
alias :is_document? :is_document
|
72
|
+
|
73
|
+
# The name of the section this image is contained in.
|
74
|
+
# Currently used to id the canvas for this image.
|
75
|
+
#
|
76
|
+
# defaults to IiifS3::DEFAULT_CANVAS_LABEL
|
77
|
+
#
|
78
|
+
# @return [String]
|
79
|
+
#
|
80
|
+
def section
|
81
|
+
@section || DEFAULT_CANVAS_LABEL
|
82
|
+
end
|
83
|
+
|
84
|
+
# The label for the section this image is contained in.
|
85
|
+
# Currently used to label the canvas for this image.
|
86
|
+
#
|
87
|
+
# defaults to IiifS3::DEFAULT_CANVAS_LABEL
|
88
|
+
#
|
89
|
+
# @return [String]
|
90
|
+
#
|
91
|
+
def section_label
|
92
|
+
@section_label || DEFAULT_CANVAS_LABEL
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [String] The prefered viewing direction for this image.
|
96
|
+
# Will default to IiifS3::DEFAULT_VIEWING_DIRECTION
|
97
|
+
#
|
98
|
+
def viewing_direction
|
99
|
+
@viewing_direction || DEFAULT_VIEWING_DIRECTION
|
100
|
+
end
|
101
|
+
|
102
|
+
def viewing_direction=(dir)
|
103
|
+
raise Error::InvalidViewingDirection unless IiifS3.is_valid_viewing_direction(dir)
|
104
|
+
@viewing_direction = dir
|
105
|
+
end
|
106
|
+
|
107
|
+
# Is this image the master image for its sequence?
|
108
|
+
#
|
109
|
+
# Each image sequence has a single image chosen as the primary image for
|
110
|
+
# the sequence. By default, page one is the master image, but another image
|
111
|
+
# could be chosen as the master if desired.
|
112
|
+
#
|
113
|
+
# This is, for instance, the image whose thumbnail is the representation for
|
114
|
+
# the entire sequence, and it defined viewing direction and other top-level
|
115
|
+
# metadata.
|
116
|
+
#
|
117
|
+
# @return [Bool]
|
118
|
+
#
|
119
|
+
def is_primary
|
120
|
+
if @is_primary.nil?
|
121
|
+
self.page_number == 1
|
122
|
+
else
|
123
|
+
@is_primary
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
alias :is_primary? :is_primary
|
128
|
+
alias :is_master :is_primary # Depriciated, but around for backwards compatibility
|
129
|
+
|
130
|
+
|
131
|
+
# Set this image record as the master record for the sequence
|
132
|
+
#
|
133
|
+
# @param [Bool] val Is this image the master
|
134
|
+
#
|
135
|
+
# @return [Bool]
|
136
|
+
#
|
137
|
+
def is_primary=(val)
|
138
|
+
@is_primary = !!val
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|