UNPKG

iiif-processor

Version:

IIIF 2.1 & 3.0 Image API modules for NodeJS

1 lines 31 kB
{"version":3,"sources":["../src/processor.ts","../src/transform.ts","../src/v2/index.ts","../src/v2/info.ts","../src/v3/index.ts","../src/v3/info.ts","../src/versions.ts"],"sourcesContent":["import Debug from 'debug';\nimport mime from 'mime-types';\nimport path from 'path';\nimport sharp from 'sharp';\nimport { Operations } from './transform';\nimport { IIIFError } from './error';\nimport Versions from './versions';\nimport type {\n Dimensions,\n MaxDimensions,\n ProcessorResult,\n ResolvedDimensions,\n ContentResult,\n ErrorResult,\n RedirectResult\n} from './types';\nimport type { VersionModule } from './contracts';\n\nconst debug = Debug('iiif-processor:main');\nconst debugv = Debug('verbose:iiif-processor');\n\nconst defaultpathPrefix = '/iiif/{{version}}/';\n\nfunction getIiifVersion(url: string, template: string) {\n const { origin, pathname } = new URL(url);\n const templateMatcher = template.replace(\n /\\{\\{version\\}\\}/,\n '(?<iiifVersion>\\\\d+)'\n );\n const pathMatcher = `^(?<prefix>${templateMatcher})(?<request>.+)$`;\n const re = new RegExp(pathMatcher);\n const parsed = re.exec(pathname);\n if (parsed) {\n parsed.groups.prefix = origin + parsed.groups.prefix;\n return { ...parsed.groups } as {\n prefix: string;\n iiifVersion: string;\n request: string;\n };\n } else {\n throw new IIIFError('Invalid IIIF path');\n }\n}\n\nexport type DimensionFunction = (input: {\n id: string;\n baseUrl: string;\n}) => Promise<Dimensions | Dimensions[]>;\nexport type StreamResolver = (input: {\n id: string;\n baseUrl: string;\n}) => Promise<NodeJS.ReadableStream>;\nexport type StreamResolverWithCallback = (\n input: { id: string; baseUrl: string },\n callback: (stream: NodeJS.ReadableStream) => Promise<unknown>\n) => Promise<unknown>;\nexport type ProcessorOptions = {\n dimensionFunction?: DimensionFunction;\n max?: { width: number; height?: number; area?: number };\n includeMetadata?: boolean;\n density?: number;\n debugBorder?: boolean;\n iiifVersion?: number;\n pageThreshold?: number;\n pathPrefix?: string;\n sharpOptions?: Record<string, unknown>;\n request?: string;\n};\n\nexport class Processor {\n private errorClass = IIIFError;\n private Implementation!: VersionModule;\n private sizeInfo?: Dimensions[];\n private sharpOptions?: Record<string, unknown>;\n\n id!: string;\n baseUrl!: string;\n version!: number;\n request!: string;\n streamResolver!: StreamResolver | StreamResolverWithCallback;\n filename?: string;\n\n // parsed params from Calculator.parsePath\n info?: string;\n region!: string;\n size!: string;\n rotation!: string;\n quality!: string;\n format!: string;\n\n // options\n dimensionFunction!: DimensionFunction;\n max?: MaxDimensions;\n includeMetadata = false;\n density?: number | null;\n debugBorder = false;\n pageThreshold?: number;\n\n constructor(\n url: string,\n streamResolver: StreamResolver | StreamResolverWithCallback,\n opts: ProcessorOptions = {}\n ) {\n const { prefix, iiifVersion, request } = getIiifVersion(\n url,\n opts.pathPrefix || defaultpathPrefix\n );\n\n if (typeof streamResolver !== 'function') {\n throw new IIIFError('streamResolver option must be specified');\n }\n\n if (opts.max?.height && !opts.max?.width) {\n throw new IIIFError('maxHeight cannot be specified without maxWidth');\n }\n\n const defaults = {\n dimensionFunction: this.defaultDimensionFunction.bind(this),\n density: null\n };\n\n this.setOpts({\n ...defaults,\n iiifVersion,\n ...opts,\n prefix,\n request\n }).initialize(streamResolver);\n }\n\n setOpts(opts) {\n this.dimensionFunction = opts.dimensionFunction;\n this.max = { ...opts.max };\n this.includeMetadata = !!opts.includeMetadata;\n this.density = opts.density;\n this.baseUrl = opts.prefix;\n this.debugBorder = !!opts.debugBorder;\n this.pageThreshold = opts.pageThreshold;\n this.sharpOptions = { ...opts.sharpOptions };\n this.version = Number(opts.iiifVersion);\n this.request = opts.request;\n return this;\n }\n\n initialize(streamResolver: StreamResolver | StreamResolverWithCallback) {\n this.Implementation = Versions[this.version] as VersionModule;\n if (!this.Implementation) {\n throw new IIIFError(\n `No implementation found for IIIF Image API v${this.version}`\n );\n }\n\n const params = this.Implementation.Calculator.parsePath(this.request);\n debug('Parsed URL: %j', params);\n Object.assign(this, params);\n this.streamResolver = streamResolver;\n\n if (this.quality && this.format) {\n this.filename = [this.quality, this.format].join('.');\n } else if (this.info) {\n this.filename = 'info.json';\n }\n return this;\n }\n\n async withStream(\n { id, baseUrl }: { id: string; baseUrl: string },\n callback: (s: NodeJS.ReadableStream) => Promise<unknown>\n ) {\n debug('Requesting stream for %s', id);\n if (this.streamResolver.length === 2) {\n return await (this.streamResolver as StreamResolverWithCallback)(\n { id, baseUrl },\n callback\n );\n } else {\n const stream = await (this.streamResolver as StreamResolver)({\n id,\n baseUrl\n });\n return await callback(stream);\n }\n }\n\n async defaultDimensionFunction({\n id,\n baseUrl\n }: {\n id: string;\n baseUrl: string;\n }): Promise<Dimensions[]> {\n const result: Dimensions[] = [];\n let page = 0;\n const target = sharp({ limitInputPixels: false, page });\n\n return (await this.withStream({ id, baseUrl }, async (stream) => {\n stream.pipe(target);\n const { autoOrient, ...metadata } = await target.metadata();\n const { width, height, pages } = { ...metadata, ...autoOrient };\n if (!width || !height) return result;\n result.push({ width, height });\n if (!isNaN(pages)) {\n for (page += 1; page < pages; page++) {\n const scale = 1 / 2 ** page;\n result.push({\n width: Math.floor(width * scale),\n height: Math.floor(height * scale)\n });\n }\n }\n return result;\n })) as Dimensions[];\n }\n\n async dimensions(): Promise<Dimensions[]> {\n const fallback =\n this.dimensionFunction !== this.defaultDimensionFunction.bind(this);\n\n if (!this.sizeInfo) {\n debug(\n 'Attempting to use dimensionFunction to retrieve dimensions for %j',\n this.id\n );\n const params = { id: this.id, baseUrl: this.baseUrl };\n let dims: ResolvedDimensions = await this.dimensionFunction(params);\n if (fallback && !dims) {\n const warning =\n 'Unable to get dimensions for %s using custom function. Falling back to sharp.metadata().';\n debug(warning, this.id);\n console.warn(warning, this.id);\n dims = await this.defaultDimensionFunction(params);\n }\n if (!Array.isArray(dims)) dims = [dims];\n this.sizeInfo = dims as Dimensions[];\n }\n return this.sizeInfo;\n }\n\n async infoJson() {\n const [dim] = await this.dimensions();\n const sizes: Array<{ width: number; height: number }> = [];\n for (\n let size = [dim.width, dim.height];\n size.every((x) => x >= 64);\n size = size.map((x) => Math.floor(x / 2))\n ) {\n sizes.push({ width: size[0], height: size[1] });\n }\n\n const uri = new URL(this.baseUrl);\n // Node's URL has readonly pathname in types; construct via join on new URL\n uri.pathname = path.join(uri.pathname, this.id);\n const id = uri.toString();\n const doc = this.Implementation.infoDoc({\n id,\n ...dim,\n sizes,\n max: this.max\n });\n for (const prop in doc) {\n if (doc[prop] === null || doc[prop] === undefined) delete doc[prop];\n }\n\n const body = JSON.stringify(doc, (_key, value) =>\n value?.constructor === Set ? [...value] : value\n );\n return {\n type: 'content',\n contentType: 'application/ld+json',\n body\n } as ContentResult;\n }\n\n operations(dim: Dimensions[]) {\n const sharpOpt = this.sharpOptions;\n const { max, pageThreshold } = this;\n debug('pageThreshold: %d', pageThreshold);\n return new Operations(this.version, dim, {\n sharp: sharpOpt,\n max,\n pageThreshold\n })\n .region(this.region)\n .size(this.size)\n .rotation(this.rotation)\n .quality(this.quality)\n .format(this.format, this.density ?? undefined)\n .withMetadata(this.includeMetadata);\n }\n\n async applyBorder(transformed: sharp.Sharp) {\n const buf = await transformed.toBuffer();\n const borderPipe = sharp(buf, { limitInputPixels: false });\n const { width, height } = await borderPipe.metadata();\n const background = { r: 255, g: 0, b: 0, alpha: 1 };\n\n const topBorder = {\n create: { width, height: 1, channels: 4, background } as sharp.Create\n };\n const bottomBorder = {\n create: { width, height: 1, channels: 4, background } as sharp.Create\n };\n const leftBorder = {\n create: { width: 1, height, channels: 4, background } as sharp.Create\n };\n const rightBorder = {\n create: { width: 1, height, channels: 4, background } as sharp.Create\n };\n\n return borderPipe.composite([\n { input: topBorder, left: 0, top: 0 },\n { input: bottomBorder, left: 0, top: (height as number) - 1 },\n { input: leftBorder, left: 0, top: 0 },\n { input: rightBorder, left: (width as number) - 1, top: 0 }\n ]);\n }\n\n async iiifImage() {\n debugv('Request %s', this.request);\n const dim = await this.dimensions();\n const operations = this.operations(dim);\n debugv('Operations: %j', operations);\n const pipeline = await operations.pipeline();\n\n const result = await this.withStream(\n { id: this.id, baseUrl: this.baseUrl },\n async (stream) => {\n debug('piping stream to pipeline');\n let transformed = await stream.pipe(pipeline);\n if (this.debugBorder) {\n transformed = await this.applyBorder(transformed);\n }\n debug('converting to buffer');\n return await transformed.toBuffer();\n }\n );\n debug('returning %d bytes', (result as Buffer).length);\n debug('baseUrl', this.baseUrl);\n\n const canonicalUrl = new URL(\n path.join(this.id, operations.canonicalPath()),\n this.baseUrl\n );\n return {\n type: 'content',\n canonicalLink: canonicalUrl.toString(),\n profileLink: this.Implementation.profileLink,\n contentType: mime.lookup(this.format) as string,\n body: result as Buffer\n } as ContentResult;\n }\n\n async execute(): Promise<ProcessorResult> {\n try {\n if (this.format === undefined && this.info === undefined) {\n debug('No format or info.json requested; redirecting to info.json');\n return {\n location: new URL(\n path.join(this.id, 'info.json'),\n this.baseUrl\n ).toString(),\n type: 'redirect'\n } as RedirectResult;\n }\n\n if (this.filename === 'info.json') {\n return await this.infoJson();\n }\n\n return await this.iiifImage();\n } catch (err) {\n if (err instanceof IIIFError) {\n debug('IIIFError caught: %j', err);\n return {\n type: 'error',\n message: err.message,\n statusCode: err.statusCode || 500\n } as ErrorResult;\n } else {\n throw err;\n }\n }\n }\n}\n\nexport default Processor;\n","import Sharp, { Sharp as SharpType } from 'sharp';\nimport Debug from 'debug';\nimport { Versions } from './versions';\nimport type { VersionModule, CalculatorLike, CalculatorOptions } from './contracts';\nimport type { Dimensions, BoundingBox, Format } from './types';\n\nconst debug = Debug('iiif-processor:transform');\n\nconst DEFAULT_PAGE_THRESHOLD = 1;\nconst SCALE_PRECISION = 10000000;\n\ntype PageDim = { width: number; height: number; page: number };\n\nexport class Operations {\n private keepMetadata?: boolean;\n private pages: PageDim[];\n private sharpOptions?: Record<string, unknown>;\n private calculator: CalculatorLike;\n private pageThreshold: number;\n\n constructor (version: number, dims: Dimensions[], opts: CalculatorOptions & { sharp?: Record<string, unknown>; pageThreshold?: number }) {\n const { sharp, pageThreshold, ...rest } = { ...opts };\n const Implementation: VersionModule = Versions[version];\n this.calculator = new Implementation.Calculator(dims[0], rest);\n this.pageThreshold = typeof pageThreshold === 'number' ? pageThreshold : DEFAULT_PAGE_THRESHOLD;\n\n this.pages = dims\n .map((dim, page) => ({ ...dim, page }))\n .sort((a, b) => b.width * b.height - a.width * a.height);\n this.sharpOptions = sharp;\n }\n\n region (v: string) {\n this.calculator.region(v);\n return this;\n }\n\n size (v: string) {\n this.calculator.size(v);\n return this;\n }\n\n rotation (v: string) {\n this.calculator.rotation(v);\n return this;\n }\n\n quality (v: string) {\n this.calculator.quality(v);\n return this;\n }\n\n format (v: string, density?: number) {\n this.calculator.format(v, density);\n return this;\n }\n\n info () {\n return this.calculator.info();\n }\n\n canonicalPath () {\n return this.calculator.canonicalPath();\n }\n\n withMetadata (v: boolean) {\n this.keepMetadata = v;\n return this;\n }\n\n private computePage () {\n const { fullSize } = this.info();\n const { page } = this.pages.find((_candidate, index) => {\n const next = this.pages[index + 1];\n debug('comparing candidate %j to target %j with a %d-pixel buffer', next, fullSize, this.pageThreshold);\n return !next || (next.width + this.pageThreshold < fullSize.width && next.height + this.pageThreshold < fullSize.height);\n }) as PageDim;\n\n const resolution = this.pages[page];\n const scale = page === 0 ? 1 : Math.round((resolution.width / this.pages[0].width) * SCALE_PRECISION) / SCALE_PRECISION;\n debug('Using page %d (%j) as source and scaling by %f', page, resolution, scale);\n return { page, scale };\n }\n\n pipeline (): SharpType {\n const pipeline = Sharp({\n limitInputPixels: false,\n ...{ ...this.sharpOptions }\n });\n const { page, scale } = this.computePage();\n (pipeline as any).options.input.page = page; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n const { format, quality, region, rotation: { flop, degree }, size } = this.info();\n scaleRegion(region, scale, this.pages[page]);\n\n pipeline.autoOrient().extract(region).resize(size);\n if (flop) pipeline.flop();\n pipeline.rotate(degree);\n if (quality === 'gray') pipeline.grayscale();\n if (quality === 'bitonal') pipeline.threshold();\n setFormat(pipeline, format);\n if (this.keepMetadata) pipeline.keepMetadata();\n\n debug('Pipeline: %j', { page, region, size, rotation: { flop, degree }, quality, format });\n return pipeline;\n }\n}\n\nfunction setFormat (pipeline: SharpType, format: { type: Format; density?: number }) {\n let pipelineFormat;\n const pipelineOptions: any = {}; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n switch (format.type) {\n case 'jpeg':\n pipelineFormat = 'jpg';\n break;\n case 'tif':\n pipelineFormat = 'tiff';\n if (format.density) {\n pipelineOptions.xres = format.density / 25.4;\n pipelineOptions.yres = format.density / 25.4;\n }\n break;\n default:\n pipelineFormat = format.type;\n }\n pipeline.toFormat(pipelineFormat, pipelineOptions);\n if (format.density) {\n pipeline.withMetadata({ density: format.density });\n }\n}\n\nfunction scaleRegion (region: BoundingBox, scale: number, page: { width: number; height: number }) {\n region.left = Math.floor(region.left * scale);\n region.top = Math.floor(region.top * scale);\n region.width = Math.floor(region.width * scale);\n region.height = Math.floor(region.height * scale);\n region.left = Math.max(region.left, 0);\n region.top = Math.max(region.top, 0);\n region.width = Math.min(region.width, page.width);\n region.height = Math.min(region.height, page.height);\n return region;\n}\n\nexport default { Operations };\n","export * from './info';\nexport * from '../calculator/v2';\n","import { Dimensions } from '../types';\nimport { Formats, Qualities } from '../calculator/v2';\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport Debug from 'debug';\nimport type { InfoDocInput, InfoDoc } from '../contracts';\nconst profileLink = 'http://iiif.io/api/image/2/level2.json';\n\nconst IIIFProfile = {\n formats: new Set(Formats),\n qualities: new Set(Qualities),\n supports: new Set([\n 'baseUriRedirect',\n 'canonicalLinkHeader',\n 'cors',\n 'jsonldMediaType',\n 'mirroring',\n 'profileLinkHeader',\n 'regionByPct',\n 'regionByPx',\n 'regionSquare',\n 'rotationArbitrary',\n 'rotationBy90s',\n 'sizeAboveFull',\n 'sizeByConfinedWh',\n 'sizeByDistortedWh',\n 'sizeByForcedWh',\n 'sizeByH',\n 'sizeByPct',\n 'sizeByW',\n 'sizeByWh',\n 'sizeByWhListed'\n ])\n};\n\nexport function infoDoc ({ id, width, height, sizes, max }: InfoDocInput): InfoDoc {\n const maxAttrs = {\n maxWidth: max?.width,\n maxHeight: max?.height,\n maxArea: max?.area\n };\n\n return {\n '@context': 'http://iiif.io/api/image/2/context.json',\n '@id': id,\n protocol: 'http://iiif.io/api/image',\n width,\n height,\n sizes,\n tiles: [\n { width: 512, height: 512, scaleFactors: sizes.map((_v: Dimensions, i: number) => 2 ** i) }\n ],\n profile: [profileLink, { ...IIIFProfile, ...maxAttrs }]\n };\n}\n\nexport { profileLink };\n","export * from './info';\nexport * from '../calculator/v3';\n","import { Dimensions } from '../types';\nimport { Formats, Qualities } from '../calculator/v3';\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport Debug from 'debug';\nimport type { InfoDocInput, InfoDoc } from '../contracts';\n\nexport const profileLink = 'https://iiif.io/api/image/3/level2.json';\n\nconst defaultFormats: Set<string> = new Set(['jpg', 'png']);\nconst defaultQualities: Set<string> = new Set(['default']);\nconst IIIFExtras = {\n extraFeatures: [\n 'canonicalLinkHeader',\n 'mirroring',\n 'profileLinkHeader',\n 'rotationArbitrary',\n 'sizeByDistortedWh',\n 'sizeByForcedWh',\n 'sizeByWhListed',\n 'sizeUpscaling'\n ],\n extraFormats: new Set(Formats.filter((f) => !defaultFormats.has(f))),\n extraQualities: new Set(Qualities.filter((q) => !defaultQualities.has(q)))\n};\n\nexport function infoDoc({\n id,\n width,\n height,\n sizes,\n max\n}: InfoDocInput): InfoDoc {\n const maxAttrs = {\n maxWidth: max?.width,\n maxHeight: max?.height,\n maxArea: max?.area\n };\n\n return {\n '@context': 'http://iiif.io/api/image/3/context.json',\n id,\n type: 'ImageService3',\n protocol: 'http://iiif.io/api/image',\n profile: 'level2',\n width,\n height,\n sizes,\n tiles: [\n {\n width: 512,\n height: 512,\n scaleFactors: sizes.map((_v: Dimensions, i: number) => 2 ** i)\n }\n ],\n ...IIIFExtras,\n ...maxAttrs\n };\n}\n","import * as v2 from './v2';\nimport * as v3 from './v3';\nimport type { VersionModule } from './contracts';\n\nexport const Versions: Record<2 | 3, VersionModule> = {\n 2: v2 as unknown as VersionModule,\n 3: v3 as unknown as VersionModule\n};\n\nexport default Versions;\n"],"mappings":"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","names":["Debug","Calculator","infoDoc","profileLink","profileLink","infoDoc","sharp","debug","Debug"]}