Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/samvera/iiif_manifest


https://github.com/samvera/iiif_manifest

core-components samvera-community

Last synced: 3 days ago
JSON representation

Awesome Lists containing this project

README

        

# IIIFManifest

Code:
[![CircleCI](https://circleci.com/gh/samvera/iiif_manifest.svg?style=svg)](https://circleci.com/gh/samvera/iiif_manifest) [![Coverage Status](https://coveralls.io/repos/github/samvera/iiif_manifest/badge.svg)](https://coveralls.io/github/samvera/iiif_manifest)

Docs:
[![Contribution Guidelines](http://img.shields.io/badge/CONTRIBUTING-Guidelines-blue.svg)](./CONTRIBUTING.md) [![Apache 2.0 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE)

Community Support: [![Samvera Community Slack](https://img.shields.io/badge/samvera-slack-blueviolet)](http://slack.samvera.org/)

# What is IIIFManifest

IIIF defines an API for presenting related images in a viewer. This transforms Hydra::Works objects into that format usable by players such as

## Product Owner & Maintenance

`iiif_manifest` is a Core Component of the Samvera Community. The documentation for what this means can be found [here](http://samvera.github.io/core_components.html#requirements-for-a-core-component).

### Product Owner

[kdid](https://github.com/kdid)

# Usage

Your application **_must_** have an object that implements `#file_set_presenters` and `#work_presenters`. The former method should return as set of leaf nodes and the later any interstitial nodes. If none are found an empty array should be returned.

Additionally, it **_must_** have a `#description` method that returns a string.

Additionally it **_should_** implement `#manifest_url` that shows where the manifest can be found.

Additionally it **_should_** implement `#manifest_metadata` to provide an array containing hashes of metadata Label/Value pairs.

Additionally it **_may_** implement `#search_service` to contain the url for a IIIF search api compliant search endpoint and `#autocomplete_service` to contain the url for a IIIF search api compliant autocomplete endpoint. Please note, the autocomplete service is embedded within the search service description so if an autocomplete_service is supplied without a search_service it will be ignored. The IIIF `profile` added to the service descriptions is version 0 as this is the version supported by the current version of Universal Viewer. Only include a search_service within the manifest if your application has implemented a IIIF search service at the endpoint specified in the manifest.

Additionally it **_may_** implement `#service` to contain an array of hashes for services other than `search_service` or `autocomplete_service`. Each must contain "@id" (V2) or "id" (V3) and "@context" (V2) or "type" (V3) and may contain any other arbitrary properties.

Additionally it **_may_** implement `#sequence_rendering` to contain an array of hashes for file downloads to be offered at sequences level. Each hash must contain "@id", "format" (mime type) and "label" (eg. `{ "@id" => "download url", "format" => "application/pdf", "label" => "user friendly label" }`).

Finally, it **_may_** implement `ranges`, which returns an array of objects which represent a table of contents or similar structure, each of which responds to `label`, `ranges`, and `file_set_presenters`.

For example:

```ruby
class Book
def initialize(id, pages = [])
@id = id
@pages = pages
end

def file_set_presenters
@pages
end

def work_presenters
[]
end

def manifest_url
"http://test.host/books/#{@id}/manifest"
end

def description
'a brief description'
end

def manifest_metadata
[
{ "label" => "Title", "value" => "Title of the Item" },
{ "label" => "Creator", "value" => "Morrissey, Stephen Patrick" }
]
end

def search_service
"http://test.host/books/#{@id}/search"
end

def autocomplete_service
"http://test.host/books/#{@id}/autocomplete"
end

def service
[
{
"@context" => "http://iiif.io/api/annext/services/example/context.json",
"@id" => "https://example.org/service",
"profile" => "https://example.org/docs/service"
}
]
end

def sequence_rendering
[{"@id" => "http://test.host/file_set/id/download", "format" => "application/pdf", "label" => "Download"}]
end

def ranges
[
ManifestRange.new(
label: "Table of Contents",
ranges: [
ManifestRange.new(
label: "Chapter 1",
file_set_presenters: @pages
)
]
)
]
end
end

class ManifestRange
attr_reader :label, :ranges, :file_set_presenters
def initialize(label:, ranges: [], file_set_presenters: [])
@label = label
@ranges = ranges
@file_set_presenters = file_set_presenters
end
end
```

The class that represents the leaf nodes, must implement `#id`. It must also implement `#display_image` which returns an instance of `IIIFManifest::DisplayImage`

In Presentation 3.0, additionally it **_may_** implement;
- `#item_metadata` to contain an array of hashes for metadata to be displayed at each leaf node. Items must contain "label" and "value" properties.
- `#sequence_rendering` to contain an array of hashes for file downloads to be offered at each leaf node. This follows a similar format as `#sequence_rendering` at sequences level
- `#see_also` to contain an array of hashes for related resources to be offered at each leaf node. Items must contain "id" and "type" properties. Items should contain "label", "format", and "profile" properties.
- `#part_of` to contain an array of hashes for parent resources to be offered at each leaf node. Items must contain "id" and "type" properties. Items should contain "label".
- `#homepage` to contain an array of hashes for homepage resources to be offered at each leaf node. Items must contain "id", "type", and "label" properties. Items should contain a "format" property and may contain a "language" property.
- `#placeholder_content` to contain an instance of `IIIFManifest::V3::DisplayContent` for [`placeholderCanvas`](https://iiif.io/api/presentation/3.0/#placeholdercanvas) at each leaf node
- `#service` to contain an array of hashes for services. Each must contain "id" and "type" and may contain any other arbitrary properties.

```ruby
class Page
def initialize(id)
@id = id
end

def id
@id
end

def display_image
IIIFManifest::DisplayImage.new(id,
width: 100,
height: 100,
format: "image/jpeg",
iiif_endpoint: endpoint
)
end

# --------------------------------------- Presentation 3.0 ---------------------------------------
def sequence_rendering
[{"@id" => "http://test.host/display_image/id/download", "format" => "application/pdf", "label" => "Download"}]
end

def see_also
[{"id" => "http://test.host/display_image/id/image.json", "type" => "dataset", "format" => "application/json", "label" => "Related Resource"}]
end

def part_of
[{"id" => "http://test.host/display_image/id/parent.json", "type" => "manifest"}]
end

def homepage
[{"id" => "http://test.host/display_image/id/homepage", "type" => "Text", "label" => "Item Homepage"}]
end

def placeholder_content
IIIFManifest::V3::DisplayContent.new(id,
width: 100,
height: 100,
type: "Image",
format: "image/jpeg")
end

def service
[
{
"@context" => "http://iiif.io/api/annext/services/example/context.json",
"@id" => "https://example.org/service",
"profile" => "https://example.org/docs/service"
}
]
end
# --------------------------------------- Presentation 3.0 ---------------------------------------

private

def endpoint
IIIFManifest::IIIFEndpoint.new("http://test.host/images/#{id}",
profile: "http://iiif.io/api/image/2/level2.json")
end
end
```

Then you can produce the manifest on the book object like this:

```ruby
book = Book.new('book-77',[Page.new('page-99')])
IIIFManifest::ManifestFactory.new(book).to_h.to_json
```

## Presentation 3.0

Provisional support for the [3.0 version of the IIIF presentation api spec](https://iiif.io/api/presentation/3.0/) has been added with a focus on audiovisual content. The [change log](https://iiif.io/api/presentation/3.0/change-log/) lists the changes to the specification.

The presentation 3.0 support has been contained to the `V3` namespace. Version 2.0 manifests are still being built using `IIIFManifest::ManifestFactory` while version 3.0 manifests can now be built using `IIIFManifest::V3::ManifestFactory`.

```ruby
book = Book.new('book-77',[Page.new('page-99')])
IIIFManifest::V3::ManifestFactory.new(book).to_h.to_json
```

### Notable changes for Presentation 3.0

- Presenters must still define `#description` but it is now serialized as `summary`. ()
- All textual strings, including metadata labels and values, are now serialized as language maps and may be provided as a hash with language code keys with string values. Values not provided in this format are automatically converted so no change to `#description`, `#manifest_metadata`, range labels, or other fields are required. ()
- Presenters **_may_** implement `#homepage` to contain a hash for linking back to a repository webpage for this manifest. The hash must contain "id", "format" (mime type), "type", and "label" (eg. `{ "id" => "repository url", "format" => "text/html", "type" => "Text", "label" => { "en": ["View in repository"] }`).
- File set presenters may target a fragment of its content by providing `#media_fragment` which will be appended to its `id`.
- Range objects may now implement `#items` instead of `#ranges` and `#file_set_presenters` to allow for interleaving these objects. `#items` is not required and existing range objects should continue to work.
- File set presenters may provide,
- `#display_content` which should return an instance of `IIIFManifest::V3::DisplayContent` (or an array of instances in the case of a user `Choice`)
- `#annotation_content` which should return an instance of `IIIFManifest::V3::AnnotationContent` (or an array of instances in the case of a canvas having multiple annotations)
- `#display_image` is no longer required but will still work if provided
- `#sequence_rendering` is supported at leaf node level, to present an array of file downloads available at each leaf node
- `#part_of` is supported at leaf node level, to present an array of parent resources available at each leaf node.
- `#homepage` is supported at leaf node level, to present an array of homepage resources available at each leaf node.
- `#placeholder_content` which returns an instance of `IIIFManifest::V3::DisplayContent` presents a [`placeholderCanvas`](https://iiif.io/api/presentation/3.0/#placeholdercanvas) at leaf node level
- DisplayContent may provide `#auth_service` which should return a hash containing a IIIF Authentication service definition () that will be included on the content resource.

## Configuration

The `label`, `rights`, `homepage`, `description` (V2 only), and `summary` (V3 only) properties can be configured to pull its information from different attributes.

**NOTE:** In the V2 manifest, `label` and `description` is expected to be a string so if the model's attribute is multivalued, only the first value would be used.

To enable this, add the following code to a config file at `config/initializers/iiif_manifest_config.rb` in your application.
```ruby
# Example: use the default configuration but amend the summary property
IIIFManifest.config do |config|
config.manifest_property_to_record_method_name_map.merge!(summary: :abstract, rights: :license)
end
```
In the above example of a V3 manifest (since it is a `summary` instead of `description`), the `summary` property will be using the model's `#abstract` attribute value instead of the default `#description`. The `rights` property will use the model's `#license` attribute instead of the default `#rights_statement`. All other configurable properties will use their defaults.

```ruby
# Example: use this configuration to set the max edge length of thumbnails, default is 200
IIIFManifest.confg do |config|
config.max_edge_for_thumbnail = 100
end
```
Thumbnails have been added for version 3 manifests because [Universal Viewer](https://github.com/UniversalViewer/universalviewer/issues/102) currently require them to be explicitly set otherwise they would not show up. The above example is used to configure what the default size for the thumbnails would be.

```ruby
# Example: use this configuration to disable thumbnails to show up by default on the manifest level (version 3 only)
IIIFManifest.confg do |config|
config.manifest_thumbnail = false
end
```
According to the Presentation API 3.0 [specifications](https://iiif.io/api/presentation/3.0/#thumbnail):
> A Manifest *SHOULD* have the `thumbnail` property with at least one item.

The above configuration allows you to disable that if desired since it is not a *MUST*.

# Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at . This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.

If you're working on PR for this project, create a feature branch off of `main`.

This repository follows the [Samvera Community Code of Conduct](https://samvera.atlassian.net/wiki/spaces/samvera/pages/405212316/Code+of+Conduct) and [language recommendations](https://github.com/samvera/maintenance/blob/master/templates/CONTRIBUTING.md#language). Please ***do not*** create a branch called `master` for this repository or as part of your pull request; the branch will either need to be removed or renamed before it can be considered for inclusion in the code base and history of this repository.

## Help

The Samvera community is here to help. Please see our [support guide](./SUPPORT.md).

# Acknowledgments

This software has been developed by and is brought to you by the Samvera community. Learn more at the [Samvera website](http://samvera.org/).

![Samvera Logo](https://raw.githubusercontent.com/samvera/maintenance/main/assets/samvera_tree.png)