jptmoore / maniiifest

Typesafe IIIF presentation v3 parsing without external dependencies
MIT License
11 stars 0 forks source link
iiif iiif-presentation-3 manifest parser

Maniiifest

Description

Maniiifest provides methods to parse and manipulate IIIF Presentation API 3.0 specification and W3C web annotations. It ensures type safety and offers utility functions for working with IIIF data. Maniiifest takes a parser generator approach to generating TypeScript type definitions using a domain-specific language (DSL). The current specification is available here.

A typechecker/validator built using maniiifest is available online here.

Installation

Install the package using npm:

npm install maniiifest --save-dev

Usage

Import and use the functions in your TypeScript project:

import { Maniiifest } from 'maniiifest';

const manifest = {
    "id": "https://iiif.io/api/cookbook/recipe/0032-collection/manifest-02.json",
    "type": "Manifest",
    "label": { "en": ["Northeaster"] }
}

const parser = new Maniiifest(manifest);
const label = parser.getManifestLabelByLanguage('en');
console.log(label?.['en']);

To parse web annotations you need to provide the type of annotation to the constructor. For example:

const annotationParser = new Maniiifest(annotation, "Annotation");
const annotationPageParser = new Maniiifest(annotation_page, "AnnotationPage");
const annotationCollectionParser = new Maniiifest(annotation_collection, "AnnotationCollection");

The aim is to support the most relevant subset of the W3C standard as used within IIIF manifests.

Documentation

Documentation for the current supported get methods and generators available here. If you would like to see other methods added please raise an issue.

Tutorial

In this example we will use generators to work with a complex collection that nests manifests within it.

import { Maniiifest } from 'maniiifest';

async function main() {
    const response = await fetch('https://iiif.wellcomecollection.org/presentation/b19974760');
    const jsonData = await response.json();
    const parser = new Maniiifest(jsonData);
    const manifests = parser.iterateCollectionManifest();
    let count = 0;
    for (const item of manifests) {
        if (count >= 25) break;
        const manifestRef = new Maniiifest(item);
        const metadata = manifestRef.iterateManifestMetadata();
        for (const item of metadata) {
            console.log(item);
        }
        count++;
    }
}

main()

The output will be the metadata from the first 25 manifests:

❯ ts-node tutorial.ts
{ label: { en: [ 'Volume' ] }, value: { none: [ '1' ] } }
{ label: { en: [ 'Year' ] }, value: { none: [ '1859' ] } }
{ label: { en: [ 'Month' ] }, value: { en: [ 'September' ] } }
{
  label: { en: [ 'DisplayDate' ] },
  value: { en: [ '15. September 1859' ] }
}
{ label: { en: [ 'Volume' ] }, value: { none: [ '1' ] } }
{ label: { en: [ 'Year' ] }, value: { none: [ '1859' ] } }
{ label: { en: [ 'Month' ] }, value: { en: [ 'October' ] } }
.....

In this example we will work with externally referenced W3C annotations.

import { Maniiifest } from 'maniiifest';

async function main() {
    const response = await fetch('https://iiif.io/api/cookbook/recipe/0269-embedded-or-referenced-annotations/manifest.json');
    const jsonData = await response.json();
    const parser = new Maniiifest(jsonData);
    const annotationPages = parser.iterateManifestCanvasW3cAnnotationPage();
    for (const annotationPage of annotationPages) {
        const response = await fetch(annotationPage.id);
        const jsonData = await response.json();
        const parser = new Maniiifest(jsonData, "AnnotationPage");
        const annotations = parser.iterateAnnotationPageAnnotation();
        for (const annotation of annotations) {
            console.log(annotation.body?.value);
        }
    }
}

main()

The output will the commenting value from the single annotation:

Göttinger Marktplatz mit Gänseliesel Brunnen

In this example we will work with an annotation that uses the georeference extension.

import { Maniiifest } from 'maniiifest';

async function main() {
    const response = await fetch('https://annotations.allmaps.org/maps/cde9210870a2652a');
    const jsonData = await response.json();
    const annotation = new Maniiifest(jsonData, "Annotation");
    const points = Array.from(annotation.iterateAnnotationGeometryPointCoordinates());
    for (let i = 0; i < points.length; i += 2) {
        console.log(`x: ${points[i]}, y: ${points[i + 1]}`);
    } 
}

main()

The output will be all the point coordinates:

x: -70.9375518, y: 42.4811769
x: -70.9398138, y: 42.4825027
x: -70.9403993, y: 42.4821228
x: -70.9434097, y: 42.480079
x: -70.9373183, y: 42.4793787
x: -70.9454651, y: 42.4765122
x: -70.9364491, y: 42.4804618
x: -70.9377961, y: 42.4788144
x: -70.935966, y: 42.4809988
x: -70.9390062, y: 42.4772977
x: -70.9398389, y: 42.4815905
x: -70.9369067, y: 42.4798999

More examples of parsing complex manifests and collections can be found here.

Scripts

License

This project is licensed under the MIT License.