cozy-iiif 0.2.7 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/core/canvas.d.ts +0 -1
- package/dist/core/image-service.d.ts +2 -2
- package/dist/index.js +131 -123
- package/dist/level-0/index.js +5 -4
- package/dist/types.d.ts +8 -3
- package/package.json +3 -2
- package/src/Cozy.ts +3 -4
- package/src/core/canvas.ts +41 -15
- package/src/core/image-service.ts +3 -3
- package/src/types.ts +9 -6
- package/test/core/canvas.test.ts +42 -0
- package/test/core/fixtures.ts +11 -1
- package/vite.config.ts +6 -4
package/README.md
CHANGED
@@ -134,6 +134,13 @@ console.log(image.getRegionURL(bounds));
|
|
134
134
|
|
135
135
|
// With custom minimum shorted dimension
|
136
136
|
console.log(image.getRegionURL(bounds, 800));
|
137
|
+
|
138
|
+
// Full image with custom minimum shorted dimension
|
139
|
+
console.log(image.getImageURL(800));
|
140
|
+
|
141
|
+
// Resolves the actual image pixel size from the info.json
|
142
|
+
// or the image file (which may **differ**) from the canvas size!
|
143
|
+
console.log(image.getPixelSize());
|
137
144
|
```
|
138
145
|
|
139
146
|
## Cozy Helpers
|
package/dist/core/canvas.d.ts
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import { Canvas } from '@iiif/presentation-3';
|
2
2
|
import { CozyImageResource } from '../types';
|
3
3
|
export declare const getThumbnailURL: (canvas: Canvas, images?: CozyImageResource[]) => (minSize?: number) => string | undefined;
|
4
|
-
export declare const getImageURL: (canvas: Canvas, images?: CozyImageResource[]) => (minSize?: number) => string | undefined;
|
5
4
|
export declare const normalizeServiceUrl: (url: string) => string;
|
6
5
|
export declare const getImages: (canvas: Canvas) => CozyImageResource[];
|
@@ -6,7 +6,7 @@ export declare const parseImageService: (service: Service) => {
|
|
6
6
|
majorVersion: number;
|
7
7
|
profileLevel: number;
|
8
8
|
} | undefined;
|
9
|
-
export declare const getImageURLFromService: (service:
|
10
|
-
export declare const getRegionURLFromService: (service:
|
9
|
+
export declare const getImageURLFromService: (service: Service, width: number, height: number) => string;
|
10
|
+
export declare const getRegionURLFromService: (service: Service, bounds: Bounds, minSize: number) => string | undefined;
|
11
11
|
export declare const getRegionURL: (image: CozyImageResource) => (bounds: Bounds, minSize?: number) => string | undefined;
|
12
12
|
export {};
|
package/dist/index.js
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
|
4
|
-
|
1
|
+
import { imageSize as ce } from "image-size";
|
2
|
+
import { g, a as j, b as S } from "./resource-DS2brz47.js";
|
3
|
+
import { c as zt } from "./resource-DS2brz47.js";
|
4
|
+
var le = "http://library.stanford.edu/iiif/image-api/compliance.html#level0", pe = "http://library.stanford.edu/iiif/image-api/compliance.html#level1", V = "http://library.stanford.edu/iiif/image-api/compliance.html#level2", ve = "http://library.stanford.edu/iiif/image-api/conformance.html#level0", he = "http://library.stanford.edu/iiif/image-api/conformance.html#level1", F = "http://library.stanford.edu/iiif/image-api/conformance.html#level2", ue = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0", fe = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1", W = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2", ge = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level0", me = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level1", H = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level2", de = "http://iiif.io/api/image/1/level0.json", ye = "http://iiif.io/api/image/1/profiles/level0.json", Ae = "http://iiif.io/api/image/1/level1.json", Ce = "http://iiif.io/api/image/1/profiles/level1.json", J = "http://iiif.io/api/image/1/level2.json", z = "http://iiif.io/api/image/1/profiles/level2.json", be = "http://iiif.io/api/image/2/level0.json", Re = "http://iiif.io/api/image/2/profiles/level0.json", Le = "http://iiif.io/api/image/2/level1.json", we = "http://iiif.io/api/image/2/profiles/level1.json", G = "http://iiif.io/api/image/2/level2.json", K = "http://iiif.io/api/image/2/profiles/level2.json", Ie = "level0", Se = "level1", Q = "level2", xe = "http://iiif.io/api/image/2/level0", Te = "http://iiif.io/api/image/2/level1", X = "http://iiif.io/api/image/2/level2", $e = [X, V, F, W, H, J, z, G, K, Q], Me = [xe, Te, X, le, pe, V, ve, he, F, ue, fe, W, ge, me, H, de, ye, Ae, Ce, J, z, be, Re, Le, we, G, K, Ie, Se, Q], je = Me;
|
5
|
+
function m(t) {
|
5
6
|
for (let e in t) (typeof t[e] > "u" || t[e] === null) && delete t[e];
|
6
7
|
return t;
|
7
8
|
}
|
8
9
|
function w(t) {
|
9
10
|
return Array.isArray(t) ? t : t ? [t] : [];
|
10
11
|
}
|
11
|
-
var
|
12
|
-
function
|
12
|
+
var ke = Object.defineProperty, Pe = (t, e, r) => e in t ? ke(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r, b = (t, e, r) => (Pe(t, typeof e != "symbol" ? e + "" : e, r), r), N = ["sc:Collection", "sc:Manifest", "sc:Canvas", "sc:AnnotationList", "oa:Annotation", "sc:Range", "sc:Layer", "sc:Sequence", "oa:Choice", "Service", "ContentResource"];
|
13
|
+
function Oe(t) {
|
13
14
|
if (typeof t > "u" || t === null) throw new Error("Null or undefined is not a valid entity.");
|
14
15
|
if (Array.isArray(t)) throw new Error("Array is not a valid entity");
|
15
16
|
if (typeof t != "object") throw new Error(`${typeof t} is not a valid entity`);
|
@@ -21,12 +22,12 @@ function Pe(t) {
|
|
21
22
|
if (t.format || t["@type"]) return "ContentResource";
|
22
23
|
throw new Error("Resource type is not known");
|
23
24
|
}
|
24
|
-
var
|
25
|
+
var Ue = class Y {
|
25
26
|
constructor(e, r = {}) {
|
26
27
|
b(this, "traversals"), b(this, "options"), this.traversals = { collection: [], manifest: [], canvas: [], annotationList: [], sequence: [], annotation: [], contentResource: [], choice: [], range: [], service: [], layer: [], ...e }, this.options = { convertPropsToArray: !0, mergeMemberProperties: !0, allowUndefinedReturn: !1, ...r };
|
27
28
|
}
|
28
29
|
static all(e) {
|
29
|
-
return new
|
30
|
+
return new Y({ collection: [e], manifest: [e], canvas: [e], annotationList: [e], sequence: [e], annotation: [e], contentResource: [e], choice: [e], range: [e], service: [e], layer: [e] });
|
30
31
|
}
|
31
32
|
traverseCollection(e) {
|
32
33
|
return this.traverseType(this.traverseDescriptive(this.traverseLinking(this.traverseCollectionItems(e))), this.traversals.collection);
|
@@ -99,7 +100,7 @@ var Oe = class Z {
|
|
99
100
|
}
|
100
101
|
traverseUnknown(e) {
|
101
102
|
if (!e["@type"] || typeof e == "string") return e;
|
102
|
-
switch (
|
103
|
+
switch (Oe(e)) {
|
103
104
|
case "sc:Collection":
|
104
105
|
return this.traverseCollection(e);
|
105
106
|
case "sc:Manifest":
|
@@ -152,8 +153,8 @@ var Oe = class Z {
|
|
152
153
|
return typeof n > "u" && !this.options.allowUndefinedReturn ? i : n;
|
153
154
|
}, e);
|
154
155
|
}
|
155
|
-
},
|
156
|
-
function
|
156
|
+
}, De = "http://library.stanford.edu/iiif/image-api/compliance.html#level1", Ne = "http://library.stanford.edu/iiif/image-api/compliance.html#level2", Ee = "http://library.stanford.edu/iiif/image-api/conformance.html#level1", qe = "http://library.stanford.edu/iiif/image-api/conformance.html#level2", _e = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1", Be = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2", Ve = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level1", Fe = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level2", We = "http://iiif.io/api/image/1/level1.json", He = "http://iiif.io/api/image/1/profiles/level1.json", Je = "http://iiif.io/api/image/1/level2.json", ze = "http://iiif.io/api/image/1/profiles/level2.json", Ge = "http://iiif.io/api/image/2/level1.json", Ke = "http://iiif.io/api/image/2/profiles/level1.json", Qe = "http://iiif.io/api/image/2/level2.json", Xe = "http://iiif.io/api/image/2/profiles/level2.json", Ye = "level1", Ze = "level2", et = "http://iiif.io/api/image/2/level1", tt = "http://iiif.io/api/image/2/level2", rt = [et, tt, De, Ne, Ee, qe, _e, Be, Ve, Fe, We, He, Je, ze, Ge, Ke, Qe, Xe, Ye, Ze], k = { attributionLabel: "Attribution", providerId: "http://example.org/provider", providerName: "Unknown" };
|
157
|
+
function it(t) {
|
157
158
|
if (typeof t == "string") return [t];
|
158
159
|
if (!t) return [];
|
159
160
|
let e = Array.isArray(t) ? t : [t], r = [];
|
@@ -168,7 +169,7 @@ function rt(t) {
|
|
168
169
|
}
|
169
170
|
function I(t, e = "none") {
|
170
171
|
if (!t) return { none: [""] };
|
171
|
-
let r =
|
172
|
+
let r = it(t), i = {};
|
172
173
|
for (let s of r) {
|
173
174
|
if (typeof s == "string") {
|
174
175
|
i[e] = i[e] ? i[e] : [], i[e].push(s || "");
|
@@ -183,14 +184,14 @@ function I(t, e = "none") {
|
|
183
184
|
}
|
184
185
|
return Object.keys(i).length === 0 ? { none: [""] } : i;
|
185
186
|
}
|
186
|
-
function
|
187
|
-
if (Array.isArray(t)) return
|
188
|
-
if (
|
189
|
-
if (
|
190
|
-
if (
|
187
|
+
function Z(t) {
|
188
|
+
if (Array.isArray(t)) return Z(t.find((e) => typeof e == "string"));
|
189
|
+
if ($e.indexOf(t) !== -1) return "level2";
|
190
|
+
if (rt.indexOf(t) !== -1) return "level1";
|
191
|
+
if (je.indexOf(t) !== -1) return "level0";
|
191
192
|
if (typeof t == "string") return t;
|
192
193
|
}
|
193
|
-
function
|
194
|
+
function st(t) {
|
194
195
|
let e = Array.isArray(t) ? t : [t];
|
195
196
|
for (let r of e) switch (r) {
|
196
197
|
case "http://iiif.io/api/image/2/context.json":
|
@@ -203,7 +204,7 @@ function it(t) {
|
|
203
204
|
return "ImageApiSelector";
|
204
205
|
}
|
205
206
|
}
|
206
|
-
function
|
207
|
+
function nt(t) {
|
207
208
|
switch (t) {
|
208
209
|
case "http://iiif.io/api/image/2/level0.json":
|
209
210
|
case "http://iiif.io/api/image/2/level1.json":
|
@@ -236,15 +237,15 @@ function E(t) {
|
|
236
237
|
for (let e of ["sc", "oa", "dcterms", "dctypes", "iiif"]) if (t.startsWith(`${e}:`)) return t.slice(e.length + 1);
|
237
238
|
return t;
|
238
239
|
}
|
239
|
-
var
|
240
|
+
var at = ["Collection", "Manifest", "Annotation", "AnnotationPage", "Range", "Service"];
|
240
241
|
function U(t) {
|
241
242
|
let e = t["@id"] || t.id, r = t["@type"] || t.type, i = t.profile || void 0, s = t["@context"] || void 0;
|
242
243
|
if (i) {
|
243
|
-
let n =
|
244
|
+
let n = nt(i);
|
244
245
|
if (n) return n;
|
245
246
|
}
|
246
247
|
if (s) {
|
247
|
-
let n =
|
248
|
+
let n = st(s);
|
248
249
|
if (n) return n;
|
249
250
|
}
|
250
251
|
if (r) {
|
@@ -266,7 +267,7 @@ function U(t) {
|
|
266
267
|
return "TextualBody";
|
267
268
|
}
|
268
269
|
}
|
269
|
-
if (r &&
|
270
|
+
if (r && at.indexOf(r) !== -1) return r;
|
270
271
|
if (t.format) {
|
271
272
|
if (t.format.startsWith("image/")) return "Image";
|
272
273
|
if (t.format.startsWith("text/") || t.format === "application/pdf") return "Text";
|
@@ -274,15 +275,15 @@ function U(t) {
|
|
274
275
|
}
|
275
276
|
return e && (e.endsWith(".jpg") || e.endsWith(".png") || e.endsWith(".jpeg")) ? "Image" : r || "unknown";
|
276
277
|
}
|
277
|
-
var
|
278
|
-
function
|
279
|
-
let e = t.match(
|
278
|
+
var ot = /http(s)?:\/\/(creativecommons.org|rightsstatements.org)[^"'\\<\n]+/gm;
|
279
|
+
function ct(t) {
|
280
|
+
let e = t.match(ot);
|
280
281
|
return e ? e[0] : t;
|
281
282
|
}
|
282
|
-
function
|
283
|
+
function lt(t, e = "Rights/License", r = "none") {
|
283
284
|
let i = null, s = [], n = Array.isArray(t) ? t : [t];
|
284
285
|
for (let o of n) {
|
285
|
-
let c = o ?
|
286
|
+
let c = o ? ct(o) : void 0;
|
286
287
|
if (c && (c.indexOf("creativecommons.org") !== -1 || c.indexOf("rightsstatements.org") !== -1)) {
|
287
288
|
c.startsWith("https://") ? i = `http://${c.slice(8)}` : i = c;
|
288
289
|
continue;
|
@@ -291,15 +292,15 @@ function ct(t, e = "Rights/License", r = "none") {
|
|
291
292
|
}
|
292
293
|
return [i, s];
|
293
294
|
}
|
294
|
-
var
|
295
|
-
function
|
295
|
+
var pt = ["http://iiif.io/api/presentation/2/context.json", "http://iiif.io/api/image/2/context.json", "http://iiif.io/api/image/1/context.json", "http://library.stanford.edu/iiif/image-api/1.1/context.json", "http://iiif.io/api/search/1/context.json", "http://iiif.io/api/search/0/context.json", "http://iiif.io/api/auth/1/context.json", "http://iiif.io/api/auth/0/context.json", "http://iiif.io/api/annex/openannotation/context.json"];
|
296
|
+
function vt(t) {
|
296
297
|
if (t) {
|
297
298
|
let e = Array.isArray(t) ? t : [t], r = [];
|
298
|
-
for (let i of e) i === "http://iiif.io/api/presentation/2/context.json" && r.push("http://iiif.io/api/presentation/3/context.json"),
|
299
|
+
for (let i of e) i === "http://iiif.io/api/presentation/2/context.json" && r.push("http://iiif.io/api/presentation/3/context.json"), pt.indexOf(i) === -1 && r.push(i);
|
299
300
|
if (e.length) return r.length === 1 ? r[0] : r;
|
300
301
|
}
|
301
302
|
}
|
302
|
-
function
|
303
|
+
function ht(t) {
|
303
304
|
return t ? t.map((e) => ({ label: I(e.label), value: I(e.value) })) : [];
|
304
305
|
}
|
305
306
|
var q = 0;
|
@@ -311,16 +312,16 @@ function A(t) {
|
|
311
312
|
let e = [...t.behavior || []];
|
312
313
|
t.viewingHint && e.push(t.viewingHint);
|
313
314
|
let r;
|
314
|
-
return Array.isArray(t.motivation) ? r = t.motivation.map(E) : t.motivation && (r = E(t.motivation)), { "@context": t["@context"] ?
|
315
|
+
return Array.isArray(t.motivation) ? r = t.motivation.map(E) : t.motivation && (r = E(t.motivation)), { "@context": t["@context"] ? vt(t["@context"]) : void 0, id: (t["@id"] || ee(t)).trim(), type: U(t), behavior: e.length ? e : void 0, height: t.height ? t.height : void 0, width: t.width ? t.width : void 0, motivation: r, viewingDirection: t.viewingDirection, profile: t.profile, format: t.format ? t.format : void 0, duration: void 0, timeMode: void 0 };
|
315
316
|
}
|
316
317
|
function C(t) {
|
317
|
-
let [e, r] =
|
318
|
-
return { rights: e, metadata: i.length ? i : void 0, label: t.label ? I(t.label) : void 0, requiredStatement: t.attribution ? { label: I(k.attributionLabel), value: I(t.attribution) } : void 0, navDate: t.navDate, summary: t.description ? I(t.description) : void 0, thumbnail:
|
318
|
+
let [e, r] = lt(t.license), i = [...t.metadata ? ht(t.metadata) : [], ...r];
|
319
|
+
return { rights: e, metadata: i.length ? i : void 0, label: t.label ? I(t.label) : void 0, requiredStatement: t.attribution ? { label: I(k.attributionLabel), value: I(t.attribution) } : void 0, navDate: t.navDate, summary: t.description ? I(t.description) : void 0, thumbnail: ut(t.thumbnail) };
|
319
320
|
}
|
320
|
-
function
|
321
|
+
function ut(t) {
|
321
322
|
return t && (Array.isArray(t) ? t : [t]).map((e) => typeof e == "string" ? { id: e, type: "Image" } : (e.type === "unknown" && (e.type = "Image"), e));
|
322
323
|
}
|
323
|
-
function
|
324
|
+
function ft(t) {
|
324
325
|
if (!t.within) return;
|
325
326
|
let e = Array.isArray(t.within) ? t.within : [t.within], r = [];
|
326
327
|
for (let i of e) if (typeof i == "string") {
|
@@ -334,21 +335,21 @@ function ut(t) {
|
|
334
335
|
}
|
335
336
|
function R(t) {
|
336
337
|
let e = t.related ? Array.isArray(t.related) ? t.related : [t.related] : [], r = t.contentLayer;
|
337
|
-
return { provider: t.logo || e.length ? [{ id: k.providerId, type: "Agent", homepage: e.length ? [e[0]] : void 0, logo: t.logo ? Array.isArray(t.logo) ? t.logo : [t.logo] : void 0, label: I(k.providerName) }] : void 0, partOf:
|
338
|
+
return { provider: t.logo || e.length ? [{ id: k.providerId, type: "Agent", homepage: e.length ? [e[0]] : void 0, logo: t.logo ? Array.isArray(t.logo) ? t.logo : [t.logo] : void 0, label: I(k.providerName) }] : void 0, partOf: ft(t), rendering: t.rendering, seeAlso: t.seeAlso, start: t.startCanvas, service: t.service ? w(t.service) : void 0, supplementary: r ? [r] : void 0 };
|
338
339
|
}
|
339
|
-
function
|
340
|
+
function gt(t) {
|
340
341
|
return { chars: t.chars, format: t.format ? t.format : void 0, language: t.language };
|
341
342
|
}
|
342
343
|
function mt(t) {
|
343
|
-
return
|
344
|
+
return m({ ...A(t), ...C(t), ...R(t), items: t.members });
|
344
345
|
}
|
345
|
-
function
|
346
|
+
function dt(t) {
|
346
347
|
let e = [], r = [], i;
|
347
348
|
for (let n of t.sequences || []) n.canvases.length && e.push(...n.canvases), n.behavior && r.push(...n.behavior), n.startCanvas && (i = n.startCanvas);
|
348
349
|
let s = A(t);
|
349
|
-
return r.length && (s.behavior ? s.behavior.push(...r) : s.behavior = r),
|
350
|
+
return r.length && (s.behavior ? s.behavior.push(...r) : s.behavior = r), m({ ...s, ...C(t), ...R(t), start: i, items: e, structures: yt(t.structures) });
|
350
351
|
}
|
351
|
-
function
|
352
|
+
function yt(t) {
|
352
353
|
if (!t) return t;
|
353
354
|
let e = /* @__PURE__ */ new Map();
|
354
355
|
for (let i of t) e.set(i.id, i);
|
@@ -359,16 +360,16 @@ function dt(t) {
|
|
359
360
|
}
|
360
361
|
return t.filter((i) => r.indexOf(i.id) === -1);
|
361
362
|
}
|
362
|
-
function yt(t) {
|
363
|
-
return g({ ...A(t), ...C(t), ...R(t), annotations: t.otherContent && t.otherContent.length ? t.otherContent : void 0, items: t.images && t.images.length ? [{ id: ee(t, "annotation-page"), type: "AnnotationPage", items: t.images }] : void 0 });
|
364
|
-
}
|
365
363
|
function At(t) {
|
366
|
-
return
|
364
|
+
return m({ ...A(t), ...C(t), ...R(t), annotations: t.otherContent && t.otherContent.length ? t.otherContent : void 0, items: t.images && t.images.length ? [{ id: ee(t, "annotation-page"), type: "AnnotationPage", items: t.images }] : void 0 });
|
367
365
|
}
|
368
366
|
function Ct(t) {
|
369
|
-
return
|
367
|
+
return m({ ...A(t), ...C(t), ...R(t), items: t.resources && t.resources.length ? t.resources : void 0 });
|
370
368
|
}
|
371
369
|
function bt(t) {
|
370
|
+
return !t.canvases || t.canvases.length === 0 ? { canvases: [], behavior: [] } : { canvases: t.canvases, behavior: t.viewingHint ? [t.viewingHint] : [], startCanvas: t.startCanvas };
|
371
|
+
}
|
372
|
+
function Rt(t) {
|
372
373
|
function e(r) {
|
373
374
|
if (Array.isArray(r)) {
|
374
375
|
if (r.length > 1) return { type: "List", items: r.map(e) };
|
@@ -384,32 +385,32 @@ function bt(t) {
|
|
384
385
|
return { type: "SpecificResource", source: i, selector: P(r.selector) };
|
385
386
|
} else return encodeURI(r["@id"]).trim();
|
386
387
|
}
|
387
|
-
return
|
388
|
+
return m({ ...A(t), ...C(t), ...R(t), target: e(t.on), body: Array.isArray(t.resource) ? t.resource.map(_) : _(t.resource) });
|
388
389
|
}
|
389
390
|
function _(t) {
|
390
391
|
return t.type === "Choice" ? t : te(t);
|
391
392
|
}
|
392
393
|
function te(t) {
|
393
394
|
let e = t;
|
394
|
-
return
|
395
|
-
}
|
396
|
-
function Rt(t) {
|
397
|
-
let e = [];
|
398
|
-
return t.default && t.default !== "rdf:nil" && e.push(t.default), t.item && t.item !== "rdf:nil" && e.push(...t.item), g({ ...A(t), ...C(t), items: e });
|
395
|
+
return m({ ...A(e), ...C(e), ...R(e), ...gt(e) });
|
399
396
|
}
|
400
397
|
function Lt(t) {
|
401
|
-
|
398
|
+
let e = [];
|
399
|
+
return t.default && t.default !== "rdf:nil" && e.push(t.default), t.item && t.item !== "rdf:nil" && e.push(...t.item), m({ ...A(t), ...C(t), items: e });
|
402
400
|
}
|
403
401
|
function wt(t) {
|
404
|
-
|
405
|
-
return e && (o["@id"] = e), o["@type"] = U(t), o["@type"] === "unknown" && (i && i.length && (o["@context"] = i), o["@type"] = "Service"), s && (o.profile = z(s)), g({ ...o, ...n });
|
402
|
+
return m({ ...A(t), ...C(t), ...R(t), items: t.members });
|
406
403
|
}
|
407
404
|
function It(t) {
|
408
|
-
|
405
|
+
let { "@id": e, "@type": r, "@context": i, profile: s, ...n } = t, o = {};
|
406
|
+
return e && (o["@id"] = e), o["@type"] = U(t), o["@type"] === "unknown" && (i && i.length && (o["@context"] = i), o["@type"] = "Service"), s && (o.profile = Z(s)), m({ ...o, ...n });
|
407
|
+
}
|
408
|
+
function St(t) {
|
409
|
+
return m({ ...A(t), ...C(t), ...R(t) });
|
409
410
|
}
|
410
|
-
var
|
411
|
+
var xt = new Ue({ collection: [mt], manifest: [dt], canvas: [At], annotationList: [Ct], sequence: [bt], annotation: [Rt], contentResource: [te], choice: [Lt], range: [wt], service: [It], layer: [St] });
|
411
412
|
function re(t) {
|
412
|
-
return t && t["@context"] && (t["@context"] === "http://iiif.io/api/presentation/2/context.json" || t["@context"].indexOf("http://iiif.io/api/presentation/2/context.json") !== -1 || t["@context"] === "http://www.shared-canvas.org/ns/context.json") || t["@context"] === "http://iiif.io/api/image/2/context.json" ?
|
413
|
+
return t && t["@context"] && (t["@context"] === "http://iiif.io/api/presentation/2/context.json" || t["@context"].indexOf("http://iiif.io/api/presentation/2/context.json") !== -1 || t["@context"] === "http://www.shared-canvas.org/ns/context.json") || t["@context"] === "http://iiif.io/api/image/2/context.json" ? xt.traverseUnknown(t) : t;
|
413
414
|
}
|
414
415
|
function P(t) {
|
415
416
|
if ((Array.isArray(t["@type"]) && t["@type"].includes("oa:SvgSelector") || t["@type"] == "oa:SvgSelector") && ("chars" in t || "value" in t)) return { type: "SvgSelector", value: "chars" in t ? t.chars : t.value };
|
@@ -421,10 +422,10 @@ function P(t) {
|
|
421
422
|
function M(t) {
|
422
423
|
return typeof t == "string" ? !1 : t && !t.type && "source" in t ? (t.type = "SpecificResource", !0) : !!t && t.type === "SpecificResource";
|
423
424
|
}
|
424
|
-
function
|
425
|
+
function x(...t) {
|
425
426
|
return (e) => t.reduce((r, i) => i(r), e);
|
426
427
|
}
|
427
|
-
var
|
428
|
+
var B = ["Collection", "Manifest", "Canvas", "AnnotationPage", "AnnotationCollection", "Annotation", "ContentResource", "Range", "Service", "Selector", "Agent"];
|
428
429
|
function Tt(t, e) {
|
429
430
|
if (typeof t > "u" || t === null) throw new Error("Null or undefined is not a valid entity.");
|
430
431
|
if (Array.isArray(t)) throw new Error("Array is not a valid entity");
|
@@ -433,15 +434,15 @@ function Tt(t, e) {
|
|
433
434
|
throw new Error(`${typeof t} is not a valid entity`);
|
434
435
|
}
|
435
436
|
if (typeof t.type == "string") {
|
436
|
-
let r =
|
437
|
-
if (r !== -1) return
|
437
|
+
let r = B.indexOf(t.type);
|
438
|
+
if (r !== -1) return B[r];
|
438
439
|
}
|
439
440
|
if (t.profile) return "Service";
|
440
441
|
throw new Error("Resource type is not known");
|
441
442
|
}
|
442
443
|
var D = class ie {
|
443
444
|
constructor(e, r = {}) {
|
444
|
-
b(this, "traversals"), b(this, "options"), b(this, "_traverseManifest",
|
445
|
+
b(this, "traversals"), b(this, "options"), b(this, "_traverseManifest", x(this.traverseManifestItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this), this.traverseManifestStructures.bind(this), this.traverseInlineAnnotationPages.bind(this))), b(this, "_traverseCanvas", x(this.traverseCanvasItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this), this.traverseInlineAnnotationPages.bind(this))), b(this, "_traverseAnnotationPage", x(this.traverseAnnotationPageItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this))), b(this, "_traverseRange", x(this.traverseRangeRanges.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this))), this.traversals = { collection: [], manifest: [], canvas: [], annotationCollection: [], annotationPage: [], annotation: [], contentResource: [], choice: [], range: [], service: [], agent: [], specificResource: [], geoJson: [], ...e }, this.options = { allowUndefinedReturn: !1, ...r };
|
445
446
|
}
|
446
447
|
static all(e) {
|
447
448
|
return new ie({ collection: [e], manifest: [e], canvas: [e], annotationCollection: [e], annotationPage: [e], annotation: [e], contentResource: [e], choice: [e], range: [e], service: [e], geoJson: [e], specificResource: [e], agent: [e] });
|
@@ -552,15 +553,15 @@ var D = class ie {
|
|
552
553
|
}
|
553
554
|
}
|
554
555
|
};
|
555
|
-
const se = (t) =>
|
556
|
-
const e =
|
556
|
+
const se = (t) => g(t, "type").startsWith("ImageService") || t.profile && t.profile.toString().includes("iiif.io/api/image/"), ne = (t) => {
|
557
|
+
const e = g(t, "type"), r = g(t, "context");
|
557
558
|
if (e === "ImageService2" || r != null && r.includes("image/2")) {
|
558
559
|
const i = t, s = ["level0", "level1", "level2"];
|
559
560
|
return { majorVersion: 2, profileLevel: (Array.isArray(i.profile) ? i.profile : [i.profile]).map((c) => s.findIndex((a) => c.toString().includes(a))).filter((c) => c > -1).sort((c, a) => a - c)[0] };
|
560
561
|
} else if (e || r)
|
561
562
|
return { majorVersion: 3, profileLevel: parseInt(t.profile) };
|
562
563
|
}, O = (t, e, r) => {
|
563
|
-
const i =
|
564
|
+
const i = g(t, "id"), s = t.profile || "";
|
564
565
|
if (typeof s == "string" && (s.includes("level0") || s.includes("level:0"))) {
|
565
566
|
if ("sizes" in t && Array.isArray(t.sizes)) {
|
566
567
|
const o = t.sizes.sort((c, a) => a.width * a.height - c.width * c.height).filter((c) => c.width * c.height >= e * r)[0];
|
@@ -570,16 +571,16 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
570
571
|
return `${i}/full/full/0/default.jpg`;
|
571
572
|
}
|
572
573
|
return `${i}/full/!${e},${r}/0/default.jpg`;
|
573
|
-
},
|
574
|
-
const i =
|
574
|
+
}, $t = (t, e, r) => {
|
575
|
+
const i = g(t, "id"), s = t.profile || "";
|
575
576
|
if (typeof s == "string" && (s.includes("level0") || s.includes("level:0"))) return;
|
576
577
|
const { x: o, y: c, w: a, h: l } = e, u = a / l, v = u < 1, d = Math.ceil(v ? r / u : r), p = Math.ceil(v ? r : r / u), f = `${Math.round(o)},${Math.round(c)},${Math.round(a)},${Math.round(l)}`;
|
577
578
|
return `${i}/${f}/!${p},${d}/0/default.jpg`;
|
578
|
-
},
|
579
|
+
}, Mt = (t) => (e, r = 400) => {
|
579
580
|
if (t.type === "dynamic")
|
580
|
-
return
|
581
|
+
return $t(t.service, e, r);
|
581
582
|
console.error("Level 0 or static image canvas: unsupported");
|
582
|
-
},
|
583
|
+
}, jt = (t, e = []) => (r = 400) => {
|
583
584
|
const { width: i, height: s } = t;
|
584
585
|
if (!i || !s) return;
|
585
586
|
const n = i / s, o = n < 1, c = Math.ceil(o ? r / n : r), a = Math.ceil(o ? r : r / n);
|
@@ -598,31 +599,36 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
598
599
|
if (l.type === "static")
|
599
600
|
return l.url;
|
600
601
|
}
|
601
|
-
},
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
602
|
+
}, ae = (t) => t.endsWith("/info.json") ? t : `${t.endsWith("/") ? t : `${t}/`}info.json`, kt = (t, e, r) => (i = 800) => {
|
603
|
+
if (!t || !e) return;
|
604
|
+
const s = t / e, n = s < 1, o = Math.ceil(n ? i / s : i), c = Math.ceil(n ? i : i / s);
|
605
|
+
return O(r, c, o);
|
606
|
+
}, Pt = (t) => () => fetch(t).then((e) => e.json()).then((e) => {
|
607
|
+
const r = e.width, i = e.height;
|
608
|
+
return r !== void 0 && i !== void 0 ? { width: r, height: i } : void 0;
|
609
|
+
}), Ot = (t) => () => {
|
610
|
+
const e = typeof window < "u";
|
611
|
+
return fetch(t).then((r) => r.blob()).then((r) => e ? createImageBitmap(r).then((i) => {
|
612
|
+
const { width: s, height: n } = i;
|
613
|
+
return i.close(), { width: s, height: n };
|
614
|
+
}) : r.arrayBuffer().then((i) => ce(new Uint8Array(i))));
|
615
|
+
}, Ut = (t) => {
|
616
|
+
const { format: e, height: r, width: i } = t, s = g(t, "id"), n = (t.service || []).find(se), o = n ? ne(n) : void 0;
|
617
|
+
if (n && o) {
|
618
|
+
const c = ae(g(n, "id")), a = {
|
615
619
|
source: t,
|
616
620
|
type: o.profileLevel === 0 ? "level0" : "dynamic",
|
617
621
|
service: n,
|
618
622
|
width: i,
|
619
623
|
height: r,
|
620
624
|
majorVersion: o.majorVersion,
|
621
|
-
serviceUrl:
|
625
|
+
serviceUrl: c,
|
626
|
+
getImageURL: kt(i, r, n),
|
627
|
+
getPixelSize: Pt(c)
|
622
628
|
};
|
623
|
-
return o.profileLevel === 0 ?
|
624
|
-
...
|
625
|
-
getRegionURL:
|
629
|
+
return o.profileLevel === 0 ? a : {
|
630
|
+
...a,
|
631
|
+
getRegionURL: Mt(a)
|
626
632
|
};
|
627
633
|
} else
|
628
634
|
return {
|
@@ -631,19 +637,21 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
631
637
|
width: i,
|
632
638
|
height: r,
|
633
639
|
url: s,
|
634
|
-
format: e
|
640
|
+
format: e,
|
641
|
+
getImageURL: () => s,
|
642
|
+
getPixelSize: Ot(s)
|
635
643
|
};
|
636
|
-
},
|
644
|
+
}, Dt = (t) => {
|
637
645
|
const e = [];
|
638
646
|
return new D({
|
639
647
|
annotation: [(i) => {
|
640
648
|
if (i.motivation === "painting" || !i.motivation) {
|
641
649
|
const n = (i.body ? Array.isArray(i.body) ? i.body : [i.body] : []).filter((o) => o.type === "Image");
|
642
|
-
e.push(...n.map((o) =>
|
650
|
+
e.push(...n.map((o) => Ut(o)));
|
643
651
|
}
|
644
652
|
}]
|
645
653
|
}).traverseCanvas(t), e;
|
646
|
-
},
|
654
|
+
}, Nt = (t) => () => {
|
647
655
|
const e = /* @__PURE__ */ new Map(), r = (a, l, u = 0) => {
|
648
656
|
const v = {
|
649
657
|
id: a.id,
|
@@ -658,8 +666,8 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
658
666
|
};
|
659
667
|
a.items && a.items.length > 0 && a.items.forEach((h) => {
|
660
668
|
if (h.source.type === "Range") {
|
661
|
-
const
|
662
|
-
v.children.push(
|
669
|
+
const T = r(h, v, u + 1);
|
670
|
+
v.children.push(T);
|
663
671
|
} else {
|
664
672
|
const L = {
|
665
673
|
id: h.id,
|
@@ -690,7 +698,7 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
690
698
|
const u = (v, d = []) => v.parent ? u(v.parent, [v, ...d]) : [v, ...d];
|
691
699
|
return u(l);
|
692
700
|
}, getNode: (a) => e.get(a) };
|
693
|
-
},
|
701
|
+
}, Et = async (t) => {
|
694
702
|
try {
|
695
703
|
new URL(t);
|
696
704
|
} catch {
|
@@ -744,7 +752,7 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
744
752
|
code: "INVALID_MANIFEST",
|
745
753
|
message: "Missing @context"
|
746
754
|
};
|
747
|
-
const i =
|
755
|
+
const i = g(t, "id");
|
748
756
|
if (!i)
|
749
757
|
return {
|
750
758
|
type: "error",
|
@@ -753,18 +761,18 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
753
761
|
};
|
754
762
|
if (r.includes("presentation/2") || r.includes("presentation/3")) {
|
755
763
|
const s = r.includes("presentation/2") ? 2 : 3;
|
756
|
-
return
|
764
|
+
return g(t, "type").includes("Collection") ? {
|
757
765
|
type: "collection",
|
758
766
|
url: e || i,
|
759
|
-
resource:
|
767
|
+
resource: qt(t, s)
|
760
768
|
} : {
|
761
769
|
type: "manifest",
|
762
770
|
url: e || i,
|
763
|
-
resource:
|
771
|
+
resource: _t(t, s)
|
764
772
|
};
|
765
773
|
}
|
766
774
|
if (r.includes("image/2") || r.includes("image/3")) {
|
767
|
-
const s =
|
775
|
+
const s = Bt(t);
|
768
776
|
return s ? {
|
769
777
|
type: "iiif-image",
|
770
778
|
url: e || i,
|
@@ -780,7 +788,7 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
780
788
|
code: "INVALID_MANIFEST",
|
781
789
|
message: "JSON resource is not a recognized IIIF format"
|
782
790
|
};
|
783
|
-
},
|
791
|
+
}, qt = (t, e) => {
|
784
792
|
const r = (n) => {
|
785
793
|
const o = [];
|
786
794
|
return new D({
|
@@ -800,7 +808,7 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
800
808
|
getLabel: S(i),
|
801
809
|
getMetadata: j(i)
|
802
810
|
};
|
803
|
-
},
|
811
|
+
}, _t = (t, e) => {
|
804
812
|
const r = (o) => {
|
805
813
|
const c = [], a = [];
|
806
814
|
new D({
|
@@ -812,7 +820,7 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
812
820
|
}]
|
813
821
|
}).traverseManifest(o);
|
814
822
|
const u = c.map((p) => {
|
815
|
-
const f =
|
823
|
+
const f = Dt(p);
|
816
824
|
return {
|
817
825
|
source: p,
|
818
826
|
id: p.id,
|
@@ -820,18 +828,19 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
820
828
|
height: p.height,
|
821
829
|
images: f,
|
822
830
|
annotations: p.annotations || [],
|
823
|
-
getImageURL:
|
831
|
+
getImageURL: f.length > 0 ? f[0].getImageURL : () => {
|
832
|
+
},
|
824
833
|
getLabel: S(p),
|
825
834
|
getMetadata: j(p),
|
826
|
-
getThumbnailURL:
|
835
|
+
getThumbnailURL: jt(p, f)
|
827
836
|
};
|
828
837
|
}), v = (p) => {
|
829
|
-
const f = p.items || [], h = f.filter((y) => y.type === "Canvas").map((y) => u.find(($) => $.id === y.id)).filter(Boolean), L = f.filter((y) => y.type === "Range").map((y) => v(y)),
|
838
|
+
const f = p.items || [], h = f.filter((y) => y.type === "Canvas").map((y) => u.find(($) => $.id === y.id)).filter(Boolean), L = f.filter((y) => y.type === "Range").map((y) => v(y)), T = [...h, ...L];
|
830
839
|
return {
|
831
840
|
source: p,
|
832
841
|
id: p.id,
|
833
842
|
// Maintain original order
|
834
|
-
items: f.map((y) =>
|
843
|
+
items: f.map((y) => T.find(($) => $.id === y.id)),
|
835
844
|
canvases: h,
|
836
845
|
ranges: L,
|
837
846
|
getLabel: S(p)
|
@@ -847,9 +856,9 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
847
856
|
structure: n,
|
848
857
|
getLabel: S(i),
|
849
858
|
getMetadata: j(i),
|
850
|
-
getTableOfContents:
|
859
|
+
getTableOfContents: Nt(n)
|
851
860
|
};
|
852
|
-
},
|
861
|
+
}, Bt = (t) => {
|
853
862
|
const { width: e, height: r } = t, i = ne(t);
|
854
863
|
if (i)
|
855
864
|
return {
|
@@ -858,22 +867,21 @@ const se = (t) => m(t, "type").startsWith("ImageService") || t.profile && t.prof
|
|
858
867
|
width: e,
|
859
868
|
height: r,
|
860
869
|
majorVersion: i.majorVersion,
|
861
|
-
serviceUrl: ae(
|
870
|
+
serviceUrl: ae(g(t, "id"))
|
862
871
|
};
|
863
|
-
},
|
872
|
+
}, Wt = { parse: oe, parseURL: Et };
|
864
873
|
export {
|
865
|
-
|
866
|
-
jt as getImageURL,
|
874
|
+
Wt as Cozy,
|
867
875
|
O as getImageURLFromService,
|
868
|
-
|
876
|
+
Dt as getImages,
|
869
877
|
S as getLabel,
|
870
878
|
j as getMetadata,
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
879
|
+
g as getPropertyValue,
|
880
|
+
Mt as getRegionURL,
|
881
|
+
$t as getRegionURLFromService,
|
882
|
+
zt as getStringValue,
|
883
|
+
Nt as getTableOfContents,
|
884
|
+
jt as getThumbnailURL,
|
877
885
|
se as isImageService,
|
878
886
|
ae as normalizeServiceUrl,
|
879
887
|
ne as parseImageService
|
package/dist/level-0/index.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import "image-size";
|
1
2
|
import { g as $ } from "../resource-DS2brz47.js";
|
2
3
|
const F = (t) => ({ id: $(t, "id"), ...t }), T = (t) => fetch(t.serviceUrl).then((e) => e.json()).then(F), P = new FinalizationRegistry(({ signal: t, aborted: e }) => {
|
3
4
|
t == null || t.removeEventListener("abort", e);
|
@@ -92,7 +93,7 @@ const H = () => {
|
|
92
93
|
});
|
93
94
|
}
|
94
95
|
return d;
|
95
|
-
},
|
96
|
+
}, O = async (t, e) => {
|
96
97
|
const c = await T(t), i = R(c, e), r = document.createElement("canvas"), n = r.getContext("2d");
|
97
98
|
if (!n)
|
98
99
|
throw new Error("Error initializing canvas context");
|
@@ -164,7 +165,7 @@ const H = () => {
|
|
164
165
|
});
|
165
166
|
}
|
166
167
|
return a;
|
167
|
-
},
|
168
|
+
}, X = async (t, e) => {
|
168
169
|
const c = await T(t), i = k(c, e), r = b(c, e), n = document.createElement("canvas");
|
169
170
|
n.width = r.width, n.height = r.height;
|
170
171
|
const o = n.getContext("2d");
|
@@ -181,6 +182,6 @@ const H = () => {
|
|
181
182
|
});
|
182
183
|
};
|
183
184
|
export {
|
184
|
-
|
185
|
-
|
185
|
+
O as cropRegion,
|
186
|
+
X as getThumbnail
|
186
187
|
};
|
package/dist/types.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Manifest, Canvas,
|
1
|
+
import { Manifest, Canvas, IIIFExternalWebResource, Collection, Range, AnnotationPage, Service } from '@iiif/presentation-3';
|
2
2
|
export type CozyParseResult = {
|
3
3
|
type: 'collection';
|
4
4
|
url: string;
|
@@ -94,6 +94,11 @@ interface BaseImageResource {
|
|
94
94
|
readonly type: 'static' | 'dynamic' | 'level0';
|
95
95
|
readonly width: number;
|
96
96
|
readonly height: number;
|
97
|
+
getImageURL(minSize?: number): string;
|
98
|
+
getPixelSize(): Promise<{
|
99
|
+
width: number;
|
100
|
+
height: number;
|
101
|
+
}>;
|
97
102
|
}
|
98
103
|
export interface StaticImageResource extends BaseImageResource {
|
99
104
|
readonly type: 'static';
|
@@ -101,7 +106,7 @@ export interface StaticImageResource extends BaseImageResource {
|
|
101
106
|
}
|
102
107
|
export interface DynamicImageServiceResource extends BaseImageResource {
|
103
108
|
readonly type: 'dynamic';
|
104
|
-
readonly service:
|
109
|
+
readonly service: Service;
|
105
110
|
readonly serviceUrl: string;
|
106
111
|
readonly majorVersion: number;
|
107
112
|
getRegionURL(bounds: Bounds, minSize?: number): string;
|
@@ -109,7 +114,7 @@ export interface DynamicImageServiceResource extends BaseImageResource {
|
|
109
114
|
export interface Level0ImageServiceResource extends BaseImageResource {
|
110
115
|
readonly type: 'level0';
|
111
116
|
readonly majorVersion: number;
|
112
|
-
readonly service:
|
117
|
+
readonly service: Service;
|
113
118
|
readonly serviceUrl: string;
|
114
119
|
}
|
115
120
|
export interface ImageRequestOptions {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "cozy-iiif",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.3.1",
|
4
4
|
"description": "A developer-friendly collection of abstractions and utilities built on top of @iiif/presentation-3 and @iiif/parser",
|
5
5
|
"license": "MIT",
|
6
6
|
"author": "Rainer Simon",
|
@@ -30,11 +30,12 @@
|
|
30
30
|
"devDependencies": {
|
31
31
|
"vite": "^6.3.5",
|
32
32
|
"vite-plugin-dts": "^4.5.4",
|
33
|
-
"vitest": "^3.2.
|
33
|
+
"vitest": "^3.2.3"
|
34
34
|
},
|
35
35
|
"dependencies": {
|
36
36
|
"@iiif/parser": "2.1.7",
|
37
37
|
"@iiif/presentation-3": "^2.2.3",
|
38
|
+
"image-size": "^2.0.2",
|
38
39
|
"p-throttle": "^7.0.0",
|
39
40
|
"uuid": "^11.1.0"
|
40
41
|
}
|
package/src/Cozy.ts
CHANGED
@@ -2,8 +2,7 @@ import type { Canvas, Collection, Manifest, Range } from '@iiif/presentation-3';
|
|
2
2
|
import { convertPresentation2 } from '@iiif/parser/presentation-2';
|
3
3
|
import { Traverse } from '@iiif/parser';
|
4
4
|
import {
|
5
|
-
getImages,
|
6
|
-
getImageURL,
|
5
|
+
getImages,
|
7
6
|
getLabel,
|
8
7
|
getMetadata,
|
9
8
|
getPropertyValue,
|
@@ -15,7 +14,7 @@ import {
|
|
15
14
|
import type {
|
16
15
|
CozyCanvas,
|
17
16
|
CozyCollection,
|
18
|
-
CozyCollectionItem,
|
17
|
+
CozyCollectionItem,
|
19
18
|
CozyManifest,
|
20
19
|
CozyParseResult,
|
21
20
|
CozyRange,
|
@@ -194,7 +193,7 @@ const parseManifestResource = (resource: any, majorVersion: number): CozyManifes
|
|
194
193
|
height: c.height,
|
195
194
|
images,
|
196
195
|
annotations: (c.annotations || []),
|
197
|
-
getImageURL: getImageURL(
|
196
|
+
getImageURL: images.length > 0 ? images[0].getImageURL : () => undefined,
|
198
197
|
getLabel: getLabel(c),
|
199
198
|
getMetadata: getMetadata(c),
|
200
199
|
getThumbnailURL: getThumbnailURL(c, images)
|
package/src/core/canvas.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
import
|
1
|
+
import { imageSize } from 'image-size';
|
2
|
+
import type { Canvas, IIIFExternalWebResource, Service } from '@iiif/presentation-3';
|
2
3
|
import { Traverse } from '@iiif/parser';
|
3
4
|
import { getPropertyValue } from './resource';
|
4
5
|
import { getImageURLFromService, getRegionURL, isImageService, parseImageService } from './image-service';
|
@@ -42,9 +43,14 @@ export const getThumbnailURL = (canvas: Canvas, images: CozyImageResource[] = []
|
|
42
43
|
}
|
43
44
|
}
|
44
45
|
|
45
|
-
export const
|
46
|
-
|
46
|
+
export const normalizeServiceUrl = (url: string) =>
|
47
|
+
url.endsWith('/info.json') ? url : `${url.endsWith('/') ? url : `${url}/`}info.json`;
|
47
48
|
|
49
|
+
const getImageURL = (
|
50
|
+
width: number | undefined,
|
51
|
+
height: number | undefined,
|
52
|
+
service: Service
|
53
|
+
) => (minSize = 800) => {
|
48
54
|
if (!width || !height) return;
|
49
55
|
|
50
56
|
const aspect = width / height;
|
@@ -53,17 +59,31 @@ export const getImageURL = (canvas: Canvas, images: CozyImageResource[] = []) =>
|
|
53
59
|
const h = Math.ceil(isPortrait ? minSize / aspect : minSize);
|
54
60
|
const w = Math.ceil(isPortrait ? minSize : minSize / aspect);
|
55
61
|
|
56
|
-
|
57
|
-
if (image.type === 'dynamic' || image.type === 'level0') {
|
58
|
-
return getImageURLFromService(image.service, w, h);
|
59
|
-
} else if (image.type === 'static') {
|
60
|
-
return image.url;
|
61
|
-
}
|
62
|
-
}
|
62
|
+
return getImageURLFromService(service!, w, h);
|
63
63
|
}
|
64
64
|
|
65
|
-
|
66
|
-
|
65
|
+
const getPixelSizeFromServiceUrl = (serviceUrl: string) => () =>
|
66
|
+
fetch(serviceUrl).then(res => res.json()).then(data => {
|
67
|
+
const width: number = data.width;
|
68
|
+
const height: number = data.height;
|
69
|
+
return (width !== undefined && height !== undefined) ? { width, height } : undefined;
|
70
|
+
});
|
71
|
+
|
72
|
+
const getStaticImagePixelSize = (url: string) => () => {
|
73
|
+
const isBrowser = typeof window !== 'undefined';
|
74
|
+
|
75
|
+
return fetch(url).then(res => res.blob()).then(blob => {
|
76
|
+
if (isBrowser) {
|
77
|
+
return createImageBitmap(blob).then(bitmap => {
|
78
|
+
const { width, height } = bitmap;
|
79
|
+
bitmap.close();
|
80
|
+
return { width, height }
|
81
|
+
});
|
82
|
+
} else { return blob.arrayBuffer().then(buffer =>
|
83
|
+
imageSize(new Uint8Array(buffer)));
|
84
|
+
}
|
85
|
+
});
|
86
|
+
}
|
67
87
|
|
68
88
|
const toCozyImageResource = (resource: IIIFExternalWebResource) => {
|
69
89
|
const { format, height, width } = resource;
|
@@ -74,7 +94,9 @@ const toCozyImageResource = (resource: IIIFExternalWebResource) => {
|
|
74
94
|
|
75
95
|
const service = imageService ? parseImageService(imageService) : undefined;
|
76
96
|
|
77
|
-
if (service) {
|
97
|
+
if (imageService && service) {
|
98
|
+
const serviceUrl = normalizeServiceUrl(getPropertyValue<string>(imageService, 'id'));
|
99
|
+
|
78
100
|
const image = {
|
79
101
|
source: resource,
|
80
102
|
type: service.profileLevel === 0 ? 'level0' : 'dynamic',
|
@@ -82,7 +104,9 @@ const toCozyImageResource = (resource: IIIFExternalWebResource) => {
|
|
82
104
|
width,
|
83
105
|
height,
|
84
106
|
majorVersion: service.majorVersion,
|
85
|
-
serviceUrl
|
107
|
+
serviceUrl,
|
108
|
+
getImageURL: getImageURL(width, height, imageService),
|
109
|
+
getPixelSize: getPixelSizeFromServiceUrl(serviceUrl)
|
86
110
|
} as ImageServiceResource;
|
87
111
|
|
88
112
|
if (service.profileLevel === 0) {
|
@@ -100,7 +124,9 @@ const toCozyImageResource = (resource: IIIFExternalWebResource) => {
|
|
100
124
|
width,
|
101
125
|
height,
|
102
126
|
url: id,
|
103
|
-
format
|
127
|
+
format,
|
128
|
+
getImageURL: () => id,
|
129
|
+
getPixelSize: getStaticImagePixelSize(id)
|
104
130
|
} as StaticImageResource;
|
105
131
|
}
|
106
132
|
}
|
@@ -36,7 +36,7 @@ export const parseImageService = (service: Service) => {
|
|
36
36
|
}
|
37
37
|
|
38
38
|
export const getImageURLFromService = (
|
39
|
-
service:
|
39
|
+
service: Service,
|
40
40
|
width: number,
|
41
41
|
height: number
|
42
42
|
): string => {
|
@@ -66,7 +66,7 @@ export const getImageURLFromService = (
|
|
66
66
|
}
|
67
67
|
|
68
68
|
export const getRegionURLFromService = (
|
69
|
-
service:
|
69
|
+
service: Service,
|
70
70
|
bounds: Bounds,
|
71
71
|
minSize: number
|
72
72
|
): string | undefined => {
|
@@ -102,4 +102,4 @@ export const getRegionURL = (
|
|
102
102
|
} else {
|
103
103
|
console.error('Level 0 or static image canvas: unsupported');
|
104
104
|
}
|
105
|
-
}
|
105
|
+
}
|
package/src/types.ts
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
import type {
|
2
2
|
Manifest,
|
3
|
-
Canvas,
|
4
|
-
ImageService2,
|
5
|
-
ImageService3,
|
3
|
+
Canvas,
|
6
4
|
IIIFExternalWebResource,
|
7
5
|
Collection,
|
8
6
|
Range,
|
9
|
-
AnnotationPage
|
7
|
+
AnnotationPage,
|
8
|
+
Service
|
10
9
|
} from '@iiif/presentation-3';
|
11
10
|
|
12
11
|
export type CozyParseResult =
|
@@ -169,6 +168,10 @@ interface BaseImageResource {
|
|
169
168
|
|
170
169
|
readonly height: number;
|
171
170
|
|
171
|
+
getImageURL(minSize?: number): string;
|
172
|
+
|
173
|
+
getPixelSize(): Promise<{ width: number, height: number }>;
|
174
|
+
|
172
175
|
}
|
173
176
|
|
174
177
|
export interface StaticImageResource extends BaseImageResource {
|
@@ -183,7 +186,7 @@ export interface DynamicImageServiceResource extends BaseImageResource {
|
|
183
186
|
|
184
187
|
readonly type: 'dynamic';
|
185
188
|
|
186
|
-
readonly service:
|
189
|
+
readonly service: Service;
|
187
190
|
|
188
191
|
readonly serviceUrl: string;
|
189
192
|
|
@@ -199,7 +202,7 @@ export interface Level0ImageServiceResource extends BaseImageResource {
|
|
199
202
|
|
200
203
|
readonly majorVersion: number;
|
201
204
|
|
202
|
-
readonly service:
|
205
|
+
readonly service: Service;
|
203
206
|
|
204
207
|
readonly serviceUrl: string;
|
205
208
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
2
|
+
import { Cozy, CozyManifest } from '../../src';
|
3
|
+
|
4
|
+
import { STATIC_IMAGE, WITH_DIFFERENT_CANVAS_DIMENSIONS } from './fixtures';
|
5
|
+
|
6
|
+
describe('canvas', () => {
|
7
|
+
|
8
|
+
it('should determine correct pixel size for image service', async () => {
|
9
|
+
const result = await Cozy.parseURL(WITH_DIFFERENT_CANVAS_DIMENSIONS);
|
10
|
+
expect(result.type).toBe('manifest');
|
11
|
+
expect('resource' in result).toBeTruthy();
|
12
|
+
|
13
|
+
const manifest = (result as any).resource as CozyManifest;
|
14
|
+
expect(manifest.canvases.length).toBe(66);
|
15
|
+
|
16
|
+
const page2 = manifest.canvases[1];
|
17
|
+
expect(page2.getLabel()).toBe('Page 2');
|
18
|
+
expect(page2.images.length).toBe(1);
|
19
|
+
|
20
|
+
const image = page2.images[0];
|
21
|
+
const { width, height } = await image.getPixelSize();
|
22
|
+
expect(width).toBe(3796);
|
23
|
+
expect(height).toBe(5910);
|
24
|
+
});
|
25
|
+
|
26
|
+
it('should determine correct pixel size for static image', async () => {
|
27
|
+
const result = await Cozy.parseURL(STATIC_IMAGE);
|
28
|
+
expect(result.type).toBe('manifest');
|
29
|
+
expect('resource' in result).toBeTruthy();
|
30
|
+
|
31
|
+
const manifest = (result as any).resource as CozyManifest;
|
32
|
+
expect(manifest.canvases.length).toBe(1);
|
33
|
+
|
34
|
+
const image = manifest.canvases[0].images[0];
|
35
|
+
expect(image.type).toBe('static');
|
36
|
+
|
37
|
+
const { width, height } = await image.getPixelSize();
|
38
|
+
expect(width).toBe(1200);
|
39
|
+
expect(height).toBe(1800);
|
40
|
+
});
|
41
|
+
|
42
|
+
});
|
package/test/core/fixtures.ts
CHANGED
@@ -1,2 +1,12 @@
|
|
1
|
+
// IIIF cookbook static image
|
2
|
+
export const STATIC_IMAGE =
|
3
|
+
'https://iiif.io/api/cookbook/recipe/0001-mvm-image/manifest.json';
|
4
|
+
|
5
|
+
// Manifest that uses `structures` to define a Table of Contents
|
1
6
|
export const WITH_STRUCTURES =
|
2
|
-
'https://lib.is/IE19255085/manifest';
|
7
|
+
'https://lib.is/IE19255085/manifest';
|
8
|
+
|
9
|
+
// Manifest that specifies a different size for the canvas
|
10
|
+
// then the physical image pixel size
|
11
|
+
export const WITH_DIFFERENT_CANVAS_DIMENSIONS =
|
12
|
+
'https://www.loc.gov/item/00552972/manifest.json';
|
package/vite.config.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import { defineConfig } from 'vite';
|
2
|
-
import { resolve } from 'path';
|
3
2
|
import dts from 'vite-plugin-dts';
|
4
3
|
|
5
4
|
export default defineConfig({
|
@@ -7,11 +6,14 @@ export default defineConfig({
|
|
7
6
|
build: {
|
8
7
|
lib: {
|
9
8
|
entry: {
|
10
|
-
'index':
|
11
|
-
'helpers/index':
|
12
|
-
'level-0/index':
|
9
|
+
'index': './src/index.ts',
|
10
|
+
'helpers/index': './src/helpers/index.ts',
|
11
|
+
'level-0/index': './src/level-0/index.ts',
|
13
12
|
},
|
14
13
|
formats: ['es']
|
14
|
+
},
|
15
|
+
rollupOptions: {
|
16
|
+
external: ['image-size']
|
15
17
|
}
|
16
18
|
}
|
17
19
|
});
|