diff --git a/.env.example b/.env.example index cf1cea6..fa97aed 100644 --- a/.env.example +++ b/.env.example @@ -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' diff --git a/controllers/canvas.mjs b/controllers/canvas.mjs index 1d6f609..d15286e 100644 --- a/controllers/canvas.mjs +++ b/controllers/canvas.mjs @@ -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(); diff --git a/controllers/manifest.mjs b/controllers/manifest.mjs index 0a42a74..43b30c3 100644 --- a/controllers/manifest.mjs +++ b/controllers/manifest.mjs @@ -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; -} \ No newline at end of file diff --git a/routes/index.mjs b/routes/index.mjs index 864012a..6daf8ec 100644 --- a/routes/index.mjs +++ b/routes/index.mjs @@ -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); }); diff --git a/src/Canvas.js b/src/Canvas.js index 3d4d561..e371232 100644 --- a/src/Canvas.js +++ b/src/Canvas.js @@ -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 diff --git a/src/IIIFResource.js b/src/IIIFResource.js index 28114d2..6a66551 100644 --- a/src/IIIFResource.js +++ b/src/IIIFResource.js @@ -5,6 +5,7 @@ class IIIFResource { id; type; + generateId(serviceURL, filename) {} toObject() {} } diff --git a/src/Image.js b/src/Image.js index 964f49d..9571d34 100644 --- a/src/Image.js +++ b/src/Image.js @@ -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 diff --git a/src/Manifest.js b/src/Manifest.js index 787e938..49e242f 100644 --- a/src/Manifest.js +++ b/src/Manifest.js @@ -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 diff --git a/src/Sequence.js b/src/Sequence.js index ea51b39..6184105 100644 --- a/src/Sequence.js +++ b/src/Sequence.js @@ -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 diff --git a/src/common.js b/src/common.js new file mode 100644 index 0000000..e55526d --- /dev/null +++ b/src/common.js @@ -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; \ No newline at end of file