@allmaps/iiif-parser
Version:
Allmaps IIIF parser
122 lines (121 loc) • 4.58 kB
JavaScript
import { Manifest2Schema, Manifest3Schema, ManifestSchema } from '../schemas/iiif.js';
import { Image } from './image.js';
import { Canvas } from './canvas.js';
import { parseVersion2String, parseVersion3String, parseVersion2Metadata, filterInvalidMetadata } from '../lib/strings.js';
const ManifestTypeString = 'manifest';
/**
* Parsed IIIF Manifest, embedded in a Collection
* @class EmbeddedManifest
* @property {boolean} embedded - Whether the Manifest is embedded in a Collection
* @property {string} [uri] - URI of Manifest
* @property {LanguageString} [label] - Label of Manifest
* @property {MajorVersion} [majorVersion] - IIIF API version of Manifest
* @property {string} [type] - Resource type, equals 'manifest'
*/
export class EmbeddedManifest {
embedded = true;
uri;
type = ManifestTypeString;
label;
majorVersion;
constructor(parsedManifest) {
if ('@type' in parsedManifest) {
// IIIF Presentation API 2.0
this.uri = parsedManifest['@id'];
this.majorVersion = 2;
if (parsedManifest.label) {
this.label = parseVersion2String(parsedManifest.label);
}
}
else if ('type' in parsedManifest) {
// IIIF Presentation API 3.0
this.uri = parsedManifest.id;
this.majorVersion = 3;
this.label = parseVersion3String(parsedManifest.label);
}
else {
throw new Error('Unsupported Manifest');
}
}
}
/**
* Parsed IIIF Manifest
* @class Manifest
* @extends EmbeddedManifest
* @property {Canvas[]} canvases - Array of parsed canvases
* @property {LanguageString} [description] - Description of Manifest
* @property {Metadata} [metadata] - Metadata of Manifest
*/
export class Manifest extends EmbeddedManifest {
canvases = [];
description;
metadata;
embedded = false;
constructor(parsedManifest) {
super(parsedManifest);
if ('@type' in parsedManifest) {
// IIIF Presentation API 2.0
if (parsedManifest.description) {
this.description = parseVersion2String(parsedManifest.description);
}
this.metadata = filterInvalidMetadata(parseVersion2Metadata(parsedManifest.metadata));
const sequence = parsedManifest.sequences[0];
this.canvases = sequence.canvases.map((canvas) => new Canvas(canvas));
}
else if ('type' in parsedManifest) {
// IIIF Presentation API 3.0
this.metadata = filterInvalidMetadata(parsedManifest.metadata);
this.canvases = parsedManifest.items.map((canvas) => new Canvas(canvas));
}
else {
throw new Error('Unsupported Manifest');
}
}
/**
* Parses a IIIF resource and returns a [Manifest](#manifest) containing the parsed version
* @param {any} iiifManifest - Source data of IIIF Manifest
* @param {MajorVersion} [majorVersion=null] - IIIF API version of Manifest. If not provided, it will be determined automatically
* @returns {Manifest} Parsed IIIF Manifest
* @static
*/
static parse(iiifManifest, majorVersion = null) {
let parsedManifest;
if (majorVersion === 2) {
parsedManifest = Manifest2Schema.parse(iiifManifest);
}
else if (majorVersion === 3) {
parsedManifest = Manifest3Schema.parse(iiifManifest);
}
else {
parsedManifest = ManifestSchema.parse(iiifManifest);
}
return new Manifest(parsedManifest);
}
async fetchAll(fetchFn = globalThis.fetch) {
const results = [];
for await (const next of this.fetchNext(fetchFn)) {
results.push(next);
}
return results;
}
async *fetchNext(fetchFn = globalThis.fetch, depth = 0) {
for (const canvasIndex in this.canvases) {
const canvas = this.canvases[canvasIndex];
const image = canvas.image;
if (image.embedded) {
const url = `${image.uri}/info.json`;
const iiifManifest = await fetchFn(url).then((response) => response.json());
const newImage = Image.parse(iiifManifest);
canvas.image = newImage;
yield {
item: newImage,
depth,
parent: {
uri: this.uri,
type: this.type
}
};
}
}
}
}