'use strict'; import Manifest from '../iiif/Manifest.js'; import Sequence from '../iiif/Sequence.js'; import Canvas from '../iiif/Canvas.js'; import Image from '../iiif/Image.js'; import ManifestMetadata from '../iiif/Metadata.js'; import { parse, getCanvasLabel, getCanvasName } from './FilenameParser.js'; import { getImageList } from './ImageRepository.js'; import { TECH_NAMES } from '../constants.js'; /** * Builds a manifest object based on canvases * and available metadata * @module ManifestBuilder */ const IIIF_API_VERSION = process.env.IIIF_API_VERSION; const BASE_URL = process.env.BASE_URL; const IMAGE_SERVER_URL = process.env.IMAGE_SERVER_URL; /** * Builds a Manifest object * @param {String} manifestId * @returns {Object} */ export async function buildManifest(manifestId) { let manifest = new Manifest(IIIF_API_VERSION, BASE_URL); manifest.generateID(manifestId); manifest.generateLabel(); const images = await getImageList(manifestId); manifest = await populateCanvases(manifest, images, manifestId); manifest.setMetadata( createMetadata( manifest, images[0], // A single image filename is sufficient to extract metadata ) ); return manifest.toObject(); } /** * Builds a Canvas object from route parameters * @param {String} manifestId * @param {String} name The canvas name */ export async function buildCanvas(manifestId, name) { const manifest = new Manifest(IIIF_API_VERSION, BASE_URL); manifest.generateID(manifestId); let filename = await getImageName(name, manifestId); return createCanvas(manifest, filename); } /** * Create a canvas from an image filename * @param {Manifest} manifest * @param {string} filename The image filename * @returns {Canvas} */ async function createCanvas (manifest, filename) { let canvas = new Canvas(IIIF_API_VERSION, BASE_URL); const canvasName = getCanvasName(filename, manifest.technique); canvas.generateID(manifest.resourceId, canvasName.toLowerCase()); canvas.label = getCanvasLabel(canvasName); let image = new Image(canvas.id); image.generateID(IMAGE_SERVER_URL, filename, manifest.technique); const imgSize = await getImageSize(image.id); image.setSize(imgSize.height, imgSize.width); canvas.setThumbnail( imgSize.thumb.height, imgSize.thumb.width, image.id ); canvas.addImage(image); return canvas; } /** * @param {string} imageId The image's id as a URL to the image server * @returns {{width: number, height: number, thumb: {width: number, height: number}}} */ async function getImageSize(imageId) { let infoURL = imageId.replace(/full.*$/,'info.json'); const res = await fetch(infoURL); let size = {}; if (res.ok) { const infoJson = await res.json(); const maxSize = infoJson.sizes[infoJson.sizes.length - 1]; size.height = maxSize.height; size.width = maxSize.width; size.thumb = { width: infoJson.sizes[1].width, height: infoJson.sizes[1].height, } } return size; } /** * @param {Manifest} manifest The manifest object * @param {string[]} images List of image filenames from folder * @returns {Manifest} */ async function populateCanvases (manifest, images) { const sequence = new Sequence(BASE_URL); // There's only one sequence sequence.generateID(manifest.resourceId, 0); for (let img of images) { // Skip failing images (TODO log error to file) try { let canvas = await createCanvas(manifest, img); sequence.addCanvas(canvas); } catch (error) { console.error(error); console.log(`\nAffected image: ${img}`); continue; } } // Sort them according to their ID number... (cornice, colonna, ecc...) sequence.canvases.sort((a, b) => { const firstId = a['@id'].slice(a['@id'].lastIndexOf('/') + 1).replace(/[a-z]+/ig,''); const secondId = b['@id'].slice(b['@id'].lastIndexOf('/') + 1).replace(/[a-z]+/ig,''); return Number(firstId) - Number(secondId); }); manifest.addSequence(sequence); return manifest; } /** * Get image name for given canvas * @todo Use regex in filter!! * @param {String} name The canvas name * @param {String} manifestId The manifest (resource) id * @returns {string} */ async function getImageName(name, manifestId) { const images = await getImageList(manifestId); // Adjust canvas name for HSI with PCA... if (/pc(1|3)/.test(name)) { name = name.replace( /pc((1|3))/, function (match, group1) { return `_HSI_PC${group1}`; } ); } return images.filter(i => i.includes(name))[0]; } /** * @param {Manifest} manifest The Manifest object * @param {string} imgFilename * @returns {ManifestMetadata} */ function createMetadata(manifest, imgFilename) { let metadata = parse(imgFilename, manifest.technique); metadata.technique = TECH_NAMES[manifest.technique]; return new ManifestMetadata(metadata); }