wax_iiif 0.0.1
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.
- 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
|