Complete manifest JSON + working canvas JSON

This commit is contained in:
Nicolò P 2023-10-09 12:33:30 +02:00
parent 550fe0f4ef
commit 127b2b302f
10 changed files with 131 additions and 96 deletions

View File

@ -2,6 +2,6 @@ PORT = 8080
BASE_URL = 'https://something.com'
# The most recent API version number that should be supported
IIIF_API_VERSION = 2
# The Image API service's base URL
# The Image API service's base URL. No trailing slash!
IMAGE_SERVER_URL = 'https://images.something.com'
IMAGES_DIR = '/path/to/iiif/images'

View File

@ -1,19 +1,30 @@
import Canvas from '../src/Canvas.js';
import Image from '../src/Image.js';
import Common from '../src/common.js';
/**
* Generate a canvas object to serve
* @param {string} manifestId The corresponding manifest's id
* @param {int|string} name The canvas name
* @param {number|string} name The canvas name
*/
export default function generateCanvas(manifestId, name) {
export default async function generateCanvas(manifestId, name) {
const IIIF_API_VERSION = process.env.IIIF_API_VERSION;
const BASE_URL = process.env.BASE_URL;
const canvas = new Canvas(IIIF_API_VERSION, BASE_URL);
canvas.generateID(manifestId, name);
canvas.setLabel(`${manifestId}-${name.toLowerCase()}`);
const image = new Image(canvas.id);
image.generateID(process.env.IMAGE_SERVER_URL, await Common.getImageName(canvas));
const imgSize = await Common.getImageSize(image.id);
image.setSize(imgSize.height, imgSize.width);
canvas.setThumbnail(
imgSize.thumb.height,
imgSize.thumb.width,
image.id
);
const image = new Image(4000, 3000);
canvas.setThumbnail();
canvas.addImage(image);
return canvas.toObject();

View File

@ -1,15 +1,8 @@
'use strict';
import Manifest from '../src/Manifest.js';
import Sequence from '../src/Sequence.js';
import Canvas from '../src/Canvas.js';
import Image from '../src/Image.js';
import Common from '../src/common.js';
import * as fs from 'fs';
/**
* @typedef {Obj}
*/
/**
* Generate a manifest object to serve
* @param {string} manifestId
@ -21,86 +14,11 @@ export default async function generateManifest(manifestId) {
let manifest = new Manifest(IIIF_API_VERSION, BASE_URL);
manifest.generateID(manifestId);
manifest = await populateCanvases(
manifest = await Common.populateCanvases(
manifest,
await getImageList(manifestId),
await Common.getImageList(manifestId),
manifestId
);
return manifest.toObject();
}
/**
* @param {string} manifestId
*/
async function getImageList(manifestId) {
let folderName = manifestId.replace(/pherc-(\d+)-(\w+)$/, function (_match, g1, g2) {
return `PHerc_${g1}_${g2.toUpperCase()}`;
});
folderName += '_iiif';
return await fs.promises.readdir(`${process.env.IMAGES_DIR}/${folderName}`);
}
/**
* @todo Read height & width from info.json
* @param {Manifest} manifest
* @param {string[]} images List of image filenames from folder
* @returns {Manifest}
*/
async function populateCanvases(manifest, images, manifestId) {
const IIIF_API_VERSION = process.env.IIIF_API_VERSION;
const BASE_URL = process.env.BASE_URL;
const sequence = new Sequence(BASE_URL);
// There's only one sequence
sequence.generateID(manifestId, 0);
for (let img of images) {
let canvas = new Canvas(IIIF_API_VERSION, BASE_URL);
const canvasName = img.split('_')[3].replace(/\.[\w\d]{2,3}$/,'');
canvas.generateID(manifestId, canvasName);
canvas.setLabel(`${manifestId}-${canvasName.toLowerCase()}`);
let image = new Image(canvas.id);
image.generateID(process.env.IMAGE_SERVER_URL, img);
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);
sequence.addCanvas(canvas);
}
manifest.addSequence(sequence);
return manifest;
}
/**
* @todo Read height & width from info.json
* @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;
}

View File

@ -11,8 +11,8 @@ router.get('/iiif/:manifestid/manifest', async function(req, res) {
});
/* GET manifest JSON */
router.get('/iiif/:manifestid/canvas/:name', function(req, res) {
const canvas = generateCanvas(req.params.manifestid, req.params.name)
router.get('/iiif/:manifestid/canvas/:name', async function(req, res) {
const canvas = await generateCanvas(req.params.manifestid, req.params.name)
res.json(canvas);
});

View File

@ -7,6 +7,8 @@ class Canvas {
id = '';
type = 'sc:Canvas';
label = '';
resourceId = '';
name = '';
images = [];
thumbnail = {};
/**
@ -23,6 +25,8 @@ class Canvas {
*/
generateID(resourceId, name) {
this.id = `${this.BASE_URL}/iiif/${resourceId}/canvas/${name}`;
this.resourceId = resourceId;
this.name = name;
}
/**
* @param {string} label A label for this canvas

View File

@ -5,6 +5,7 @@ class IIIFResource {
id;
type;
generateId(serviceURL, filename) {}
toObject() {}
}

View File

@ -11,7 +11,11 @@ class Image {
__format = 'image/jpeg';
height = 0;
width = 0;
service = {};
service = {
"@context" : this.context,
"@id" : '',
profile : 'https://iiif.io/api/image/2/level2.json',
};
canvasId = '';
/**
*
@ -40,6 +44,7 @@ class Image {
const subfolder = splitFilename.slice(0,3).join('_') + '_iiif';
this.id = `${serviceURL}/2/${baseFolder}%2F${subfolder}%2F${filename}/full/full/0/default.jpg`;
this.service['@id'] = this.id.replace(/full.*$/,'');
}
/**
* Object representation of

View File

@ -6,6 +6,7 @@ import Sequence from "./Sequence.js";
class Manifest {
id = '';
type = 'sc:Manifest';
resourceId = '';
/**
* @var {Sequence[]}
*/
@ -22,10 +23,11 @@ class Manifest {
this.sequences.push(sequence.toObject());
}
/**
* @param {string} idParam From the request
* @param {string} resourceId From the request
*/
generateID(idParam) {
this.id = `${this.BASE_URL}/iiif/${idParam}/manifest` ;
generateID(resourceId) {
this.id = `${this.BASE_URL}/iiif/${resourceId}/manifest` ;
this.resourceId = resourceId;
}
/**
* Object representation of this

View File

@ -1,4 +1,5 @@
import IIIFResource from './IIIFResource.js';
import Canvas from './Canvas.js';
/**
* @todo Not needed in IIIF API v3,
* replaced by items
@ -8,6 +9,7 @@ class Sequence {
canvases = [];
id = '';
type = 'sc:Sequence';
resourceId = '';
constructor(baseUrl) {
this.BASE_URL = baseUrl;
@ -18,6 +20,7 @@ class Sequence {
*/
generateID(resourceId, name) {
this.id = `${this.BASE_URL}/iiif/${resourceId}/sequence/${name}`;
this.resourceId = resourceId;
}
/**
* @param {Canvas} canvas The Canvas object

91
src/common.js Normal file
View File

@ -0,0 +1,91 @@
import * as fs from 'fs';
import Manifest from './Manifest.js';
import Sequence from './Sequence.js';
import Canvas from './Canvas.js';
import Image from './Image.js';
const Common = {};
/**
* @param {string} manifestId
*/
Common.getImageList = async function (manifestId) {
let folderName = manifestId.replace(/pherc-(\d+)-(\w+)$/, function (_match, g1, g2) {
return `PHerc_${g1}_${g2.toUpperCase()}`;
});
folderName += '_iiif';
return await fs.promises.readdir(`${process.env.IMAGES_DIR}/${folderName}`);
}
/**
* @param {string} imageId The image's id as a URL to the image server
* @returns {{width: number, height: number, thumb: {width: number, height: number}}}
*/
Common.getImageSize = async function (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;
}
/**
* Get image name for given canvas
* @param {Canvas} canvas
*/
Common.getImageName = async function (canvas) {
const images = await this.getImageList(canvas.resourceId);
return images.filter(i => i.includes(canvas.name))[0];
}
/**
* @param {Manifest} manifest The manifest object
* @param {string[]} images List of image filenames from folder
* @returns {Manifest}
*/
Common.populateCanvases = async function (manifest, images) {
const IIIF_API_VERSION = process.env.IIIF_API_VERSION;
const BASE_URL = process.env.BASE_URL;
const sequence = new Sequence(BASE_URL);
// There's only one sequence
sequence.generateID(manifest.resourceId, 0);
for (let img of images) {
let canvas = new Canvas(IIIF_API_VERSION, BASE_URL);
const canvasName = img.split('_')[3].replace(/\.[\w\d]{2,3}$/,'');
canvas.generateID(manifest.resourceId, canvasName);
canvas.setLabel(`${manifest.resourceId}-${canvasName.toLowerCase()}`);
let image = new Image(canvas.id);
image.generateID(process.env.IMAGE_SERVER_URL, img);
const imgSize = await this.getImageSize(image.id);
image.setSize(imgSize.height, imgSize.width);
canvas.setThumbnail(
imgSize.thumb.height,
imgSize.thumb.width,
image.id
);
canvas.addImage(image);
sequence.addCanvas(canvas);
}
manifest.addSequence(sequence);
return manifest;
}
export default Common;