modern-pdf-lib 0.37.0 → 0.38.0
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 +3 -3
- package/dist/browser.cjs +15 -1
- package/dist/browser.d.cts +2 -2
- package/dist/browser.d.mts +2 -2
- package/dist/browser.mjs +2 -2
- package/dist/{index-n0WBuf3b.d.mts → index-CDg5gwYg.d.mts} +414 -4
- package/dist/index-CDg5gwYg.d.mts.map +1 -0
- package/dist/{index-BnS4WpNK.d.cts → index-CNtfRlyP.d.cts} +414 -4
- package/dist/index-CNtfRlyP.d.cts.map +1 -0
- package/dist/index.cjs +15 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{src-CbPUzRbg.cjs → src-B0gmgVEs.cjs} +884 -19
- package/dist/{src-DGxzt-jG.mjs → src-DlRTrvWg.mjs} +801 -20
- package/package.json +1 -1
- package/dist/index-BnS4WpNK.d.cts.map +0 -1
- package/dist/index-n0WBuf3b.d.mts.map +0 -1
|
@@ -9599,7 +9599,7 @@ function readU16$1(data, offset, le) {
|
|
|
9599
9599
|
* Read a 32-bit unsigned integer.
|
|
9600
9600
|
* @internal
|
|
9601
9601
|
*/
|
|
9602
|
-
function readU32$
|
|
9602
|
+
function readU32$2(data, offset, le) {
|
|
9603
9603
|
return getView(data).getUint32(offset, le);
|
|
9604
9604
|
}
|
|
9605
9605
|
/**
|
|
@@ -9614,8 +9614,8 @@ function parseIfd(data, offset, le) {
|
|
|
9614
9614
|
if (entryOffset + 12 > data.length) break;
|
|
9615
9615
|
const tag = readU16$1(data, entryOffset, le);
|
|
9616
9616
|
const type = readU16$1(data, entryOffset + 2, le);
|
|
9617
|
-
const cnt = readU32$
|
|
9618
|
-
const valueOrOffset = readU32$
|
|
9617
|
+
const cnt = readU32$2(data, entryOffset + 4, le);
|
|
9618
|
+
const valueOrOffset = readU32$2(data, entryOffset + 8, le);
|
|
9619
9619
|
entries.push({
|
|
9620
9620
|
tag,
|
|
9621
9621
|
type,
|
|
@@ -9653,7 +9653,7 @@ function readOffsetArray(data, entry, le) {
|
|
|
9653
9653
|
const pos = offset + i * elementSize;
|
|
9654
9654
|
if (pos + elementSize > data.length) break;
|
|
9655
9655
|
if (entry.type === 3) values.push(readU16$1(data, pos, le));
|
|
9656
|
-
else values.push(readU32$
|
|
9656
|
+
else values.push(readU32$2(data, pos, le));
|
|
9657
9657
|
}
|
|
9658
9658
|
return values;
|
|
9659
9659
|
}
|
|
@@ -9662,13 +9662,13 @@ function readOffsetArray(data, entry, le) {
|
|
|
9662
9662
|
* @internal
|
|
9663
9663
|
*/
|
|
9664
9664
|
function findIfdOffset(data, le, page) {
|
|
9665
|
-
let ifdOffset = readU32$
|
|
9665
|
+
let ifdOffset = readU32$2(data, 4, le);
|
|
9666
9666
|
for (let i = 0; i < page; i++) {
|
|
9667
9667
|
if (ifdOffset === 0 || ifdOffset + 2 > data.length) throw new Error(`TIFF page ${page} not found (only ${i} pages available)`);
|
|
9668
9668
|
const entryCount = readU16$1(data, ifdOffset, le);
|
|
9669
9669
|
const nextIfdOffset = ifdOffset + 2 + entryCount * 12;
|
|
9670
9670
|
if (nextIfdOffset + 4 > data.length) throw new Error(`TIFF page ${page} not found (only ${i + 1} pages available)`);
|
|
9671
|
-
ifdOffset = readU32$
|
|
9671
|
+
ifdOffset = readU32$2(data, nextIfdOffset, le);
|
|
9672
9672
|
if (ifdOffset === 0) throw new Error(`TIFF page ${page} not found (only ${i + 1} pages available)`);
|
|
9673
9673
|
}
|
|
9674
9674
|
return ifdOffset;
|
|
@@ -9725,7 +9725,7 @@ function canDirectEmbed(data) {
|
|
|
9725
9725
|
if (!isLE && !isBE) return false;
|
|
9726
9726
|
const le = isLE;
|
|
9727
9727
|
if (readU16$1(data, 2, le) !== 42) return false;
|
|
9728
|
-
const ifdOffset = readU32$
|
|
9728
|
+
const ifdOffset = readU32$2(data, 4, le);
|
|
9729
9729
|
if (ifdOffset === 0 || ifdOffset + 2 > data.length) return false;
|
|
9730
9730
|
const compression = getTag(parseIfd(data, ifdOffset, le), TAG_COMPRESSION, data, le) ?? 1;
|
|
9731
9731
|
return compression === COMPRESSION_NONE || compression === COMPRESSION_DEFLATE || compression === COMPRESSION_DEFLATE_PKZIP || compression === COMPRESSION_JPEG || compression === COMPRESSION_OLD_JPEG;
|
|
@@ -25147,7 +25147,7 @@ function readU16(data, offset) {
|
|
|
25147
25147
|
/**
|
|
25148
25148
|
* Read a 32-bit big-endian unsigned integer.
|
|
25149
25149
|
*/
|
|
25150
|
-
function readU32(data, offset) {
|
|
25150
|
+
function readU32$1(data, offset) {
|
|
25151
25151
|
return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0;
|
|
25152
25152
|
}
|
|
25153
25153
|
/**
|
|
@@ -25158,7 +25158,7 @@ function findCodestreamStart(data) {
|
|
|
25158
25158
|
if (data.length >= 12 && data[0] === 0 && data[1] === 0 && data[2] === 0 && data[3] === 12 && data[4] === 106 && data[5] === 80) {
|
|
25159
25159
|
let offset = 0;
|
|
25160
25160
|
while (offset + 8 <= data.length) {
|
|
25161
|
-
const boxLen = readU32(data, offset);
|
|
25161
|
+
const boxLen = readU32$1(data, offset);
|
|
25162
25162
|
if (String.fromCharCode(data[offset + 4], data[offset + 5], data[offset + 6], data[offset + 7]) === "jp2c") return offset + 8;
|
|
25163
25163
|
const advance = boxLen === 0 ? data.length - offset : boxLen < 8 ? 8 : boxLen;
|
|
25164
25164
|
offset += advance;
|
|
@@ -25184,14 +25184,14 @@ function parseTileInfo(data) {
|
|
|
25184
25184
|
if (sizOffset < 0) throw new Error("JPEG2000 Tiles: SIZ marker (0xFF51) not found");
|
|
25185
25185
|
const base = sizOffset + 2;
|
|
25186
25186
|
if (base + 38 > data.length) throw new Error("JPEG2000 Tiles: SIZ marker segment is truncated");
|
|
25187
|
-
const xsiz = readU32(data, base + 4);
|
|
25188
|
-
const ysiz = readU32(data, base + 8);
|
|
25189
|
-
const xosiz = readU32(data, base + 12);
|
|
25190
|
-
const yosiz = readU32(data, base + 16);
|
|
25191
|
-
const xtsiz = readU32(data, base + 20);
|
|
25192
|
-
const ytsiz = readU32(data, base + 24);
|
|
25193
|
-
const xtosiz = readU32(data, base + 28);
|
|
25194
|
-
const ytosiz = readU32(data, base + 32);
|
|
25187
|
+
const xsiz = readU32$1(data, base + 4);
|
|
25188
|
+
const ysiz = readU32$1(data, base + 8);
|
|
25189
|
+
const xosiz = readU32$1(data, base + 12);
|
|
25190
|
+
const yosiz = readU32$1(data, base + 16);
|
|
25191
|
+
const xtsiz = readU32$1(data, base + 20);
|
|
25192
|
+
const ytsiz = readU32$1(data, base + 24);
|
|
25193
|
+
const xtosiz = readU32$1(data, base + 28);
|
|
25194
|
+
const ytosiz = readU32$1(data, base + 32);
|
|
25195
25195
|
const csiz = readU16(data, base + 36);
|
|
25196
25196
|
const imageWidth = xsiz - xosiz;
|
|
25197
25197
|
const imageHeight = ysiz - yosiz;
|
|
@@ -25231,7 +25231,7 @@ function findTileParts(data, csStart) {
|
|
|
25231
25231
|
if (offset + 12 > data.length) break;
|
|
25232
25232
|
const lsot = readU16(data, offset + 2);
|
|
25233
25233
|
const isot = readU16(data, offset + 4);
|
|
25234
|
-
const psot = readU32(data, offset + 6);
|
|
25234
|
+
const psot = readU32$1(data, offset + 6);
|
|
25235
25235
|
let sodOffset = offset + 2 + lsot;
|
|
25236
25236
|
while (sodOffset + 1 < data.length) {
|
|
25237
25237
|
if (data[sodOffset] === 255 && data[sodOffset + 1] === 147) break;
|
|
@@ -31386,6 +31386,787 @@ function rgbToLab(r, g, b) {
|
|
|
31386
31386
|
];
|
|
31387
31387
|
}
|
|
31388
31388
|
//#endregion
|
|
31389
|
+
//#region src/assets/image/nextGenImageDetect.ts
|
|
31390
|
+
/** AVIF file-level brands (AV1 Image File Format §4). */
|
|
31391
|
+
const AVIF_BRANDS = /* @__PURE__ */ new Set(["avif", "avis"]);
|
|
31392
|
+
/** HEVC-coded HEIF brands (ISO/IEC 23008-12 Annex B). */
|
|
31393
|
+
const HEIC_BRANDS = /* @__PURE__ */ new Set([
|
|
31394
|
+
"heic",
|
|
31395
|
+
"heix",
|
|
31396
|
+
"heim",
|
|
31397
|
+
"heis",
|
|
31398
|
+
"hevc",
|
|
31399
|
+
"hevx"
|
|
31400
|
+
]);
|
|
31401
|
+
/** Generic (codec-agnostic) HEIF brands (ISO/IEC 23008-12 Annex B). */
|
|
31402
|
+
const HEIF_BRANDS = /* @__PURE__ */ new Set(["mif1", "msf1"]);
|
|
31403
|
+
/** Read a 4-byte big-endian unsigned integer at `offset`. */
|
|
31404
|
+
function readU32(bytes, offset) {
|
|
31405
|
+
const b0 = bytes[offset] ?? 0;
|
|
31406
|
+
const b1 = bytes[offset + 1] ?? 0;
|
|
31407
|
+
const b2 = bytes[offset + 2] ?? 0;
|
|
31408
|
+
const b3 = bytes[offset + 3] ?? 0;
|
|
31409
|
+
return b0 * 16777216 + (b1 << 16 | b2 << 8 | b3);
|
|
31410
|
+
}
|
|
31411
|
+
/** Decode a 4-byte FourCC at `offset` as an ASCII string. */
|
|
31412
|
+
function readFourCC(bytes, offset) {
|
|
31413
|
+
return String.fromCharCode(bytes[offset] ?? 0, bytes[offset + 1] ?? 0, bytes[offset + 2] ?? 0, bytes[offset + 3] ?? 0);
|
|
31414
|
+
}
|
|
31415
|
+
/**
|
|
31416
|
+
* Parse an ISOBMFF box header starting at `offset` (ISO/IEC 14496-12 §4.2).
|
|
31417
|
+
*
|
|
31418
|
+
* Handles the standard 32-bit `size`, the 64-bit `largesize` (`size == 1`),
|
|
31419
|
+
* and the to-EOF form (`size == 0`). Returns `null` on a malformed / truncated
|
|
31420
|
+
* header.
|
|
31421
|
+
*/
|
|
31422
|
+
function parseBoxHeader(bytes, offset, end) {
|
|
31423
|
+
if (offset + 8 > end) return null;
|
|
31424
|
+
let size = readU32(bytes, offset);
|
|
31425
|
+
const type = readFourCC(bytes, offset + 4);
|
|
31426
|
+
let headerLen = 8;
|
|
31427
|
+
if (size === 1) {
|
|
31428
|
+
if (offset + 16 > end) return null;
|
|
31429
|
+
const high = readU32(bytes, offset + 8);
|
|
31430
|
+
const low = readU32(bytes, offset + 12);
|
|
31431
|
+
size = high * 4294967296 + low;
|
|
31432
|
+
headerLen = 16;
|
|
31433
|
+
} else if (size === 0) size = end - offset;
|
|
31434
|
+
const boxEnd = offset + size;
|
|
31435
|
+
if (size < headerLen || boxEnd > end) return null;
|
|
31436
|
+
return {
|
|
31437
|
+
type,
|
|
31438
|
+
contentStart: offset + headerLen,
|
|
31439
|
+
boxEnd
|
|
31440
|
+
};
|
|
31441
|
+
}
|
|
31442
|
+
/**
|
|
31443
|
+
* Find a direct child box of a given `type` within [start, end).
|
|
31444
|
+
* Returns the matching {@link BoxHeader} or `null`.
|
|
31445
|
+
*/
|
|
31446
|
+
function findChildBox(bytes, start, end, type) {
|
|
31447
|
+
let cursor = start;
|
|
31448
|
+
while (cursor + 8 <= end) {
|
|
31449
|
+
const header = parseBoxHeader(bytes, cursor, end);
|
|
31450
|
+
if (header === null) return null;
|
|
31451
|
+
if (header.type === type) return header;
|
|
31452
|
+
if (header.boxEnd <= cursor) return null;
|
|
31453
|
+
cursor = header.boxEnd;
|
|
31454
|
+
}
|
|
31455
|
+
return null;
|
|
31456
|
+
}
|
|
31457
|
+
/** Verify a buffer begins with the given byte sequence. */
|
|
31458
|
+
function startsWith(bytes, sig) {
|
|
31459
|
+
if (bytes.length < sig.length) return false;
|
|
31460
|
+
for (let i = 0; i < sig.length; i++) if (bytes[i] !== sig[i]) return false;
|
|
31461
|
+
return true;
|
|
31462
|
+
}
|
|
31463
|
+
/** JPEG XL bare-codestream signature `FF 0A` (ISO/IEC 18181-1). */
|
|
31464
|
+
const JXL_CODESTREAM_SIG = [255, 10];
|
|
31465
|
+
/**
|
|
31466
|
+
* JPEG XL ISOBMFF container signature box:
|
|
31467
|
+
* `00 00 00 0C 'JXL ' 0D 0A 87 0A` (ISO/IEC 18181-1 / 18181-2).
|
|
31468
|
+
*/
|
|
31469
|
+
const JXL_CONTAINER_SIG = [
|
|
31470
|
+
0,
|
|
31471
|
+
0,
|
|
31472
|
+
0,
|
|
31473
|
+
12,
|
|
31474
|
+
74,
|
|
31475
|
+
88,
|
|
31476
|
+
76,
|
|
31477
|
+
32,
|
|
31478
|
+
13,
|
|
31479
|
+
10,
|
|
31480
|
+
135,
|
|
31481
|
+
10
|
|
31482
|
+
];
|
|
31483
|
+
/**
|
|
31484
|
+
* Inspect an ISOBMFF `ftyp` box and classify its brand set into a next-gen
|
|
31485
|
+
* format. Precedence: AVIF > HEIC > HEIF. Returns `null` if no brand matches.
|
|
31486
|
+
*/
|
|
31487
|
+
function classifyFtypBrands(bytes, ftyp) {
|
|
31488
|
+
const brands = [];
|
|
31489
|
+
if (ftyp.contentStart + 4 <= ftyp.boxEnd) brands.push(readFourCC(bytes, ftyp.contentStart));
|
|
31490
|
+
for (let off = ftyp.contentStart + 8; off + 4 <= ftyp.boxEnd; off += 4) brands.push(readFourCC(bytes, off));
|
|
31491
|
+
if (brands.some((b) => AVIF_BRANDS.has(b))) return "avif";
|
|
31492
|
+
if (brands.some((b) => HEIC_BRANDS.has(b))) return "heic";
|
|
31493
|
+
if (brands.some((b) => HEIF_BRANDS.has(b))) return "heif";
|
|
31494
|
+
return null;
|
|
31495
|
+
}
|
|
31496
|
+
/** Locate the top-level `ftyp` box (it must be the first box). */
|
|
31497
|
+
function findFtyp(bytes) {
|
|
31498
|
+
if (bytes.length < 8 || readFourCC(bytes, 4) !== "ftyp") return null;
|
|
31499
|
+
return parseBoxHeader(bytes, 0, bytes.length);
|
|
31500
|
+
}
|
|
31501
|
+
/**
|
|
31502
|
+
* Detect a next-generation image format from raw bytes.
|
|
31503
|
+
*
|
|
31504
|
+
* Recognizes AVIF / HEIC / HEIF via the ISOBMFF `ftyp` brand set, and JPEG XL
|
|
31505
|
+
* via either the bare codestream signature (`FF 0A`) or the container
|
|
31506
|
+
* signature box (`00 00 00 0C 'JXL ' 0D 0A 87 0A`).
|
|
31507
|
+
*
|
|
31508
|
+
* @param bytes Raw image file bytes.
|
|
31509
|
+
* @returns The detected {@link NextGenFormat}, or `null` if unrecognized.
|
|
31510
|
+
*/
|
|
31511
|
+
function detectNextGenFormat(bytes) {
|
|
31512
|
+
if (startsWith(bytes, JXL_CODESTREAM_SIG)) return "jpegxl";
|
|
31513
|
+
if (startsWith(bytes, JXL_CONTAINER_SIG)) return "jpegxl";
|
|
31514
|
+
const ftyp = findFtyp(bytes);
|
|
31515
|
+
if (ftyp === null) return null;
|
|
31516
|
+
return classifyFtypBrands(bytes, ftyp);
|
|
31517
|
+
}
|
|
31518
|
+
/**
|
|
31519
|
+
* Walk an ISOBMFF box tree to `meta` > `iprp` > `ipco` and read the first
|
|
31520
|
+
* `ispe` (dimensions) and `pixi` (bit depth) property boxes.
|
|
31521
|
+
*/
|
|
31522
|
+
function probeIsobmffDimensions(bytes) {
|
|
31523
|
+
const result = {};
|
|
31524
|
+
const ftyp = findFtyp(bytes);
|
|
31525
|
+
if (ftyp === null) return result;
|
|
31526
|
+
const meta = findChildBox(bytes, ftyp.boxEnd, bytes.length, "meta");
|
|
31527
|
+
if (meta === null) return result;
|
|
31528
|
+
const metaChildren = meta.contentStart + 4;
|
|
31529
|
+
if (metaChildren > meta.boxEnd) return result;
|
|
31530
|
+
const iprp = findChildBox(bytes, metaChildren, meta.boxEnd, "iprp");
|
|
31531
|
+
if (iprp === null) return result;
|
|
31532
|
+
const ipco = findChildBox(bytes, iprp.contentStart, iprp.boxEnd, "ipco");
|
|
31533
|
+
if (ipco === null) return result;
|
|
31534
|
+
const ispe = findChildBox(bytes, ipco.contentStart, ipco.boxEnd, "ispe");
|
|
31535
|
+
if (ispe !== null && ispe.contentStart + 12 <= ispe.boxEnd) {
|
|
31536
|
+
result.width = readU32(bytes, ispe.contentStart + 4);
|
|
31537
|
+
result.height = readU32(bytes, ispe.contentStart + 8);
|
|
31538
|
+
}
|
|
31539
|
+
const pixi = findChildBox(bytes, ipco.contentStart, ipco.boxEnd, "pixi");
|
|
31540
|
+
if (pixi !== null && pixi.contentStart + 5 <= pixi.boxEnd) {
|
|
31541
|
+
const numChannels = bytes[pixi.contentStart + 4] ?? 0;
|
|
31542
|
+
if (numChannels > 0 && pixi.contentStart + 5 + numChannels <= pixi.boxEnd) result.bitDepth = bytes[pixi.contentStart + 5] ?? 0;
|
|
31543
|
+
}
|
|
31544
|
+
return result;
|
|
31545
|
+
}
|
|
31546
|
+
const REASON_AVIF = "AVIF detected; pure-JS AV1 decoding is not bundled — decode/convert to PNG or JPEG, or register a WASM decoder.";
|
|
31547
|
+
const REASON_HEIC = "HEIC detected; pure-JS HEVC decoding is not bundled — decode/convert to PNG or JPEG, or register a WASM decoder.";
|
|
31548
|
+
const REASON_HEIF = "HEIF detected; pure-JS HEVC/AV1 decoding is not bundled — decode/convert to PNG or JPEG, or register a WASM decoder.";
|
|
31549
|
+
const REASON_JXL = "JPEG XL detected; pure-JS JPEG XL decoding is not bundled — decode/convert to PNG or JPEG, or register a WASM decoder.";
|
|
31550
|
+
/** Map a detected format to its non-decodable explanation. */
|
|
31551
|
+
function reasonFor(format) {
|
|
31552
|
+
switch (format) {
|
|
31553
|
+
case "avif": return REASON_AVIF;
|
|
31554
|
+
case "heic": return REASON_HEIC;
|
|
31555
|
+
case "heif": return REASON_HEIF;
|
|
31556
|
+
case "jpegxl": return REASON_JXL;
|
|
31557
|
+
}
|
|
31558
|
+
}
|
|
31559
|
+
/**
|
|
31560
|
+
* Probe a next-generation image for container metadata WITHOUT decoding pixels.
|
|
31561
|
+
*
|
|
31562
|
+
* For AVIF / HEIC / HEIF, walks the ISOBMFF box tree
|
|
31563
|
+
* (`meta` > `iprp` > `ipco` > `ispe`/`pixi`) to recover width, height, and
|
|
31564
|
+
* bit depth when present. For JPEG XL, the format is identified but dimensions
|
|
31565
|
+
* are not parsed (the `SizeHeader` is a packed-bit codestream field and is
|
|
31566
|
+
* intentionally scoped out here); only `format` is returned.
|
|
31567
|
+
*
|
|
31568
|
+
* The returned {@link NextGenImageInfo} **always** has `decodable: false`.
|
|
31569
|
+
* No pixel data is ever produced.
|
|
31570
|
+
*
|
|
31571
|
+
* @param bytes Raw image file bytes.
|
|
31572
|
+
* @returns A {@link NextGenImageInfo}, or `null` if not a next-gen image.
|
|
31573
|
+
*/
|
|
31574
|
+
function probeNextGenImage(bytes) {
|
|
31575
|
+
const format = detectNextGenFormat(bytes);
|
|
31576
|
+
if (format === null) return null;
|
|
31577
|
+
const info = {
|
|
31578
|
+
format,
|
|
31579
|
+
decodable: false,
|
|
31580
|
+
reason: reasonFor(format)
|
|
31581
|
+
};
|
|
31582
|
+
if (format === "jpegxl") return info;
|
|
31583
|
+
const dims = probeIsobmffDimensions(bytes);
|
|
31584
|
+
if (dims.width !== void 0) info.width = dims.width;
|
|
31585
|
+
if (dims.height !== void 0) info.height = dims.height;
|
|
31586
|
+
if (dims.bitDepth !== void 0) info.bitDepth = dims.bitDepth;
|
|
31587
|
+
return info;
|
|
31588
|
+
}
|
|
31589
|
+
//#endregion
|
|
31590
|
+
//#region src/assets/image/imageDecoderRegistry.ts
|
|
31591
|
+
/**
|
|
31592
|
+
* The single, module-scoped decoder registry, keyed by normalized format name.
|
|
31593
|
+
*/
|
|
31594
|
+
const registry = /* @__PURE__ */ new Map();
|
|
31595
|
+
/**
|
|
31596
|
+
* Normalize a format key: trim surrounding whitespace and lowercase it, so that
|
|
31597
|
+
* `'AVIF'`, `' avif '`, and `'avif'` all map to the same entry.
|
|
31598
|
+
*
|
|
31599
|
+
* @param format The caller-supplied format key.
|
|
31600
|
+
* @returns The normalized key.
|
|
31601
|
+
*/
|
|
31602
|
+
function normalizeFormat(format) {
|
|
31603
|
+
return format.trim().toLowerCase();
|
|
31604
|
+
}
|
|
31605
|
+
/**
|
|
31606
|
+
* Register a decoder for a given image format.
|
|
31607
|
+
*
|
|
31608
|
+
* If a decoder is already registered for the (normalized) format, it is
|
|
31609
|
+
* replaced.
|
|
31610
|
+
*
|
|
31611
|
+
* @param format Format key, e.g. `'avif'`, `'heic'`, `'jpegxl'`. The key is
|
|
31612
|
+
* normalized (trimmed + lowercased) before storage.
|
|
31613
|
+
* @param decoder The {@link ImageDecoder} that turns encoded bytes into RGBA.
|
|
31614
|
+
*/
|
|
31615
|
+
function registerImageDecoder(format, decoder) {
|
|
31616
|
+
registry.set(normalizeFormat(format), decoder);
|
|
31617
|
+
}
|
|
31618
|
+
/**
|
|
31619
|
+
* Remove the decoder registered for a given format, if any.
|
|
31620
|
+
*
|
|
31621
|
+
* This is a no-op when no decoder is registered for the (normalized) format.
|
|
31622
|
+
*
|
|
31623
|
+
* @param format Format key; normalized (trimmed + lowercased) before lookup.
|
|
31624
|
+
*/
|
|
31625
|
+
function unregisterImageDecoder(format) {
|
|
31626
|
+
registry.delete(normalizeFormat(format));
|
|
31627
|
+
}
|
|
31628
|
+
/**
|
|
31629
|
+
* Report whether a decoder is currently registered for a given format.
|
|
31630
|
+
*
|
|
31631
|
+
* @param format Format key; normalized (trimmed + lowercased) before lookup.
|
|
31632
|
+
* @returns `true` if a decoder is registered, otherwise `false`.
|
|
31633
|
+
*/
|
|
31634
|
+
function hasImageDecoder(format) {
|
|
31635
|
+
return registry.has(normalizeFormat(format));
|
|
31636
|
+
}
|
|
31637
|
+
/**
|
|
31638
|
+
* Get the decoder registered for a given format, if any.
|
|
31639
|
+
*
|
|
31640
|
+
* @param format Format key; normalized (trimmed + lowercased) before lookup.
|
|
31641
|
+
* @returns The registered {@link ImageDecoder}, or `undefined` if none.
|
|
31642
|
+
*/
|
|
31643
|
+
function getImageDecoder(format) {
|
|
31644
|
+
return registry.get(normalizeFormat(format));
|
|
31645
|
+
}
|
|
31646
|
+
/**
|
|
31647
|
+
* Validate that a value returned by a decoder is a well-formed
|
|
31648
|
+
* {@link DecodedRasterImage}.
|
|
31649
|
+
*
|
|
31650
|
+
* Throws a descriptive error (naming the format) if the result is malformed:
|
|
31651
|
+
* not an object, non-positive-integer dimensions, a non-`Uint8Array` `rgba`, or
|
|
31652
|
+
* an `rgba` length that does not equal `width * height * 4`.
|
|
31653
|
+
*
|
|
31654
|
+
* @param format Normalized format key, used only for error messages.
|
|
31655
|
+
* @param result The value returned by the decoder.
|
|
31656
|
+
* @returns The same value, narrowed to {@link DecodedRasterImage}.
|
|
31657
|
+
*/
|
|
31658
|
+
function validateDecodedResult(format, result) {
|
|
31659
|
+
if (result === null || typeof result !== "object") throw new Error(`Image decoder for format "${format}" returned a malformed result: expected an object with { width, height, rgba }, got ${typeof result}.`);
|
|
31660
|
+
const { width, height, rgba } = result;
|
|
31661
|
+
if (typeof width !== "number" || !Number.isInteger(width) || width <= 0) throw new Error(`Image decoder for format "${format}" returned a malformed result: width must be a positive integer, got ${String(width)}.`);
|
|
31662
|
+
if (typeof height !== "number" || !Number.isInteger(height) || height <= 0) throw new Error(`Image decoder for format "${format}" returned a malformed result: height must be a positive integer, got ${String(height)}.`);
|
|
31663
|
+
if (!(rgba instanceof Uint8Array)) throw new Error(`Image decoder for format "${format}" returned a malformed result: rgba must be a Uint8Array, got ${rgba === null ? "null" : typeof rgba}.`);
|
|
31664
|
+
const expected = width * height * 4;
|
|
31665
|
+
if (rgba.length !== expected) throw new Error(`Image decoder for format "${format}" returned a malformed result: rgba length ${rgba.length} does not match width*height*4 = ${width}*${height}*4 = ${expected}.`);
|
|
31666
|
+
return {
|
|
31667
|
+
width,
|
|
31668
|
+
height,
|
|
31669
|
+
rgba
|
|
31670
|
+
};
|
|
31671
|
+
}
|
|
31672
|
+
/**
|
|
31673
|
+
* Decode raw image bytes using a previously-registered decoder for `format`.
|
|
31674
|
+
*
|
|
31675
|
+
* Looks up the decoder by (normalized) format key, awaits its result, validates
|
|
31676
|
+
* the result shape (`rgba.length === width * height * 4`, positive-integer
|
|
31677
|
+
* dimensions, `Uint8Array` pixel buffer), and returns it.
|
|
31678
|
+
*
|
|
31679
|
+
* This function does **not** decode anything itself — it dispatches to the
|
|
31680
|
+
* consumer-supplied {@link ImageDecoder}. If no decoder is registered for the
|
|
31681
|
+
* format, it throws an error naming the format and explaining how to register
|
|
31682
|
+
* one via {@link registerImageDecoder}.
|
|
31683
|
+
*
|
|
31684
|
+
* @param format Format key, e.g. `'avif'`; normalized before lookup.
|
|
31685
|
+
* @param bytes Raw, encoded image bytes, forwarded verbatim to the decoder.
|
|
31686
|
+
* @returns A validated {@link DecodedRasterImage}.
|
|
31687
|
+
* @throws If no decoder is registered for the format, or if the
|
|
31688
|
+
* registered decoder returns a malformed result.
|
|
31689
|
+
*/
|
|
31690
|
+
async function decodeRegisteredImage(format, bytes) {
|
|
31691
|
+
const normalized = normalizeFormat(format);
|
|
31692
|
+
const decoder = registry.get(normalized);
|
|
31693
|
+
if (decoder === void 0) throw new Error(`No image decoder registered for format "${normalized}". This library does not bundle a decoder for this format; supply one with registerImageDecoder(${JSON.stringify(normalized)}, decoder), where decoder turns the encoded bytes into RGBA8888 ({ width, height, rgba }).`);
|
|
31694
|
+
return validateDecodedResult(normalized, await decoder(bytes));
|
|
31695
|
+
}
|
|
31696
|
+
//#endregion
|
|
31697
|
+
//#region src/assets/image/svgFilters.ts
|
|
31698
|
+
/** Clamp a number to the closed interval [0, 255] and round to an integer. */
|
|
31699
|
+
function clamp8(v) {
|
|
31700
|
+
if (v <= 0) return 0;
|
|
31701
|
+
if (v >= 255) return 255;
|
|
31702
|
+
return Math.round(v);
|
|
31703
|
+
}
|
|
31704
|
+
/** Allocate a transparent-black buffer of the given dimensions. */
|
|
31705
|
+
function allocBuffer(width, height) {
|
|
31706
|
+
return {
|
|
31707
|
+
width,
|
|
31708
|
+
height,
|
|
31709
|
+
rgba: new Uint8Array(width * height * 4)
|
|
31710
|
+
};
|
|
31711
|
+
}
|
|
31712
|
+
/** Throw if two buffers differ in dimensions (an op needs them equal). */
|
|
31713
|
+
function assertSameSize(a, b) {
|
|
31714
|
+
if (a.width !== b.width || a.height !== b.height) throw new Error(`svgFilters: buffer size mismatch (${a.width}x${a.height} vs ${b.width}x${b.height})`);
|
|
31715
|
+
}
|
|
31716
|
+
/**
|
|
31717
|
+
* Convert a straight RGBA8888 buffer to a premultiplied Float32Array in the
|
|
31718
|
+
* 0..1 range, channel order R,G,B,A. Premultiplying = colour × alpha.
|
|
31719
|
+
*/
|
|
31720
|
+
function toPremultipliedF32(src) {
|
|
31721
|
+
const n = src.width * src.height;
|
|
31722
|
+
const out = new Float32Array(n * 4);
|
|
31723
|
+
for (let i = 0; i < n; i++) {
|
|
31724
|
+
const a = src.rgba[i * 4 + 3] / 255;
|
|
31725
|
+
out[i * 4 + 0] = src.rgba[i * 4 + 0] / 255 * a;
|
|
31726
|
+
out[i * 4 + 1] = src.rgba[i * 4 + 1] / 255 * a;
|
|
31727
|
+
out[i * 4 + 2] = src.rgba[i * 4 + 2] / 255 * a;
|
|
31728
|
+
out[i * 4 + 3] = a;
|
|
31729
|
+
}
|
|
31730
|
+
return out;
|
|
31731
|
+
}
|
|
31732
|
+
/**
|
|
31733
|
+
* Convert a premultiplied Float32Array (0..1) back to a straight RGBA8888
|
|
31734
|
+
* RasterBuffer, un-premultiplying (colour ÷ alpha) and clamping.
|
|
31735
|
+
*/
|
|
31736
|
+
function fromPremultipliedF32(buf, width, height) {
|
|
31737
|
+
const out = allocBuffer(width, height);
|
|
31738
|
+
const n = width * height;
|
|
31739
|
+
for (let i = 0; i < n; i++) {
|
|
31740
|
+
const a = buf[i * 4 + 3];
|
|
31741
|
+
if (a <= 0) {
|
|
31742
|
+
out.rgba[i * 4 + 0] = 0;
|
|
31743
|
+
out.rgba[i * 4 + 1] = 0;
|
|
31744
|
+
out.rgba[i * 4 + 2] = 0;
|
|
31745
|
+
out.rgba[i * 4 + 3] = 0;
|
|
31746
|
+
} else {
|
|
31747
|
+
out.rgba[i * 4 + 0] = clamp8(buf[i * 4 + 0] / a * 255);
|
|
31748
|
+
out.rgba[i * 4 + 1] = clamp8(buf[i * 4 + 1] / a * 255);
|
|
31749
|
+
out.rgba[i * 4 + 2] = clamp8(buf[i * 4 + 2] / a * 255);
|
|
31750
|
+
out.rgba[i * 4 + 3] = clamp8(a * 255);
|
|
31751
|
+
}
|
|
31752
|
+
}
|
|
31753
|
+
return out;
|
|
31754
|
+
}
|
|
31755
|
+
/**
|
|
31756
|
+
* Produce a buffer filled with a single constant colour.
|
|
31757
|
+
*
|
|
31758
|
+
* Implements `feFlood` (SVG 1.1 §15.12): every pixel is set to the given
|
|
31759
|
+
* straight RGBA8888 colour.
|
|
31760
|
+
*
|
|
31761
|
+
* @param width Output width in pixels (must be > 0).
|
|
31762
|
+
* @param height Output height in pixels (must be > 0).
|
|
31763
|
+
* @param rgba The fill colour as `[R, G, B, A]`, each 0..255.
|
|
31764
|
+
* @returns A new buffer of `width × height` filled with `rgba`.
|
|
31765
|
+
*/
|
|
31766
|
+
function feFlood(width, height, rgba) {
|
|
31767
|
+
if (width <= 0 || height <= 0 || !Number.isInteger(width) || !Number.isInteger(height)) throw new Error(`svgFilters.feFlood: invalid dimensions ${width}x${height}`);
|
|
31768
|
+
const out = allocBuffer(width, height);
|
|
31769
|
+
const r = clamp8(rgba[0]);
|
|
31770
|
+
const g = clamp8(rgba[1]);
|
|
31771
|
+
const b = clamp8(rgba[2]);
|
|
31772
|
+
const a = clamp8(rgba[3]);
|
|
31773
|
+
const n = width * height;
|
|
31774
|
+
for (let i = 0; i < n; i++) {
|
|
31775
|
+
out.rgba[i * 4 + 0] = r;
|
|
31776
|
+
out.rgba[i * 4 + 1] = g;
|
|
31777
|
+
out.rgba[i * 4 + 2] = b;
|
|
31778
|
+
out.rgba[i * 4 + 3] = a;
|
|
31779
|
+
}
|
|
31780
|
+
return out;
|
|
31781
|
+
}
|
|
31782
|
+
/**
|
|
31783
|
+
* Apply a 4×5 colour matrix to every pixel.
|
|
31784
|
+
*
|
|
31785
|
+
* Implements `feColorMatrix` with `type="matrix"` (SVG 1.1 §15.10). The 20
|
|
31786
|
+
* values are row-major:
|
|
31787
|
+
*
|
|
31788
|
+
* ```
|
|
31789
|
+
* | R' | | m0 m1 m2 m3 m4 | | R |
|
|
31790
|
+
* | G' | | m5 m6 m7 m8 m9 | | G |
|
|
31791
|
+
* | B' | = | m10 m11 m12 m13 m14 | · | B |
|
|
31792
|
+
* | A' | | m15 m16 m17 m18 m19 | | A |
|
|
31793
|
+
* | 1 | ( the implicit identity row ) | 1 |
|
|
31794
|
+
* ```
|
|
31795
|
+
*
|
|
31796
|
+
* Channels are normalised to 0..1, the matrix is applied to the **straight**
|
|
31797
|
+
* (un-premultiplied) `[R, G, B, A, 1]` vector, then the result is scaled back
|
|
31798
|
+
* to 0..255 with clamping.
|
|
31799
|
+
*
|
|
31800
|
+
* @param src Source buffer.
|
|
31801
|
+
* @param matrix Exactly 20 numbers (4 rows × 5 columns).
|
|
31802
|
+
* @returns A new buffer with the matrix applied.
|
|
31803
|
+
* @throws If `matrix` does not contain exactly 20 values.
|
|
31804
|
+
*/
|
|
31805
|
+
function feColorMatrix(src, matrix) {
|
|
31806
|
+
if (matrix.length !== 20) throw new Error(`svgFilters.feColorMatrix: matrix must have 20 values, got ${matrix.length}`);
|
|
31807
|
+
const m = matrix;
|
|
31808
|
+
const out = allocBuffer(src.width, src.height);
|
|
31809
|
+
const n = src.width * src.height;
|
|
31810
|
+
for (let i = 0; i < n; i++) {
|
|
31811
|
+
const r = src.rgba[i * 4 + 0] / 255;
|
|
31812
|
+
const g = src.rgba[i * 4 + 1] / 255;
|
|
31813
|
+
const b = src.rgba[i * 4 + 2] / 255;
|
|
31814
|
+
const a = src.rgba[i * 4 + 3] / 255;
|
|
31815
|
+
const nr = m[0] * r + m[1] * g + m[2] * b + m[3] * a + m[4];
|
|
31816
|
+
const ng = m[5] * r + m[6] * g + m[7] * b + m[8] * a + m[9];
|
|
31817
|
+
const nb = m[10] * r + m[11] * g + m[12] * b + m[13] * a + m[14];
|
|
31818
|
+
const na = m[15] * r + m[16] * g + m[17] * b + m[18] * a + m[19];
|
|
31819
|
+
out.rgba[i * 4 + 0] = clamp8(nr * 255);
|
|
31820
|
+
out.rgba[i * 4 + 1] = clamp8(ng * 255);
|
|
31821
|
+
out.rgba[i * 4 + 2] = clamp8(nb * 255);
|
|
31822
|
+
out.rgba[i * 4 + 3] = clamp8(na * 255);
|
|
31823
|
+
}
|
|
31824
|
+
return out;
|
|
31825
|
+
}
|
|
31826
|
+
/**
|
|
31827
|
+
* Apply the `saturate` shorthand colour matrix.
|
|
31828
|
+
*
|
|
31829
|
+
* Implements `feColorMatrix type="saturate"` (SVG 1.1 §15.10). The luma
|
|
31830
|
+
* coefficients are the spec's exact constants 0.213 (R), 0.715 (G),
|
|
31831
|
+
* 0.072 (B). `s = 1` is the identity; `s = 0` fully desaturates each pixel to
|
|
31832
|
+
* its luma (so R = G = B); `s > 1` over-saturates.
|
|
31833
|
+
*
|
|
31834
|
+
* The spec saturate matrix (rows R, G, B; alpha untouched):
|
|
31835
|
+
* ```
|
|
31836
|
+
* | 0.213+0.787s 0.715-0.715s 0.072-0.072s 0 0 |
|
|
31837
|
+
* | 0.213-0.213s 0.715+0.285s 0.072-0.072s 0 0 |
|
|
31838
|
+
* | 0.213-0.213s 0.715-0.715s 0.072+0.928s 0 0 |
|
|
31839
|
+
* | 0 0 0 1 0 |
|
|
31840
|
+
* ```
|
|
31841
|
+
*
|
|
31842
|
+
* @param src Source buffer.
|
|
31843
|
+
* @param s Saturation factor (0 = greyscale, 1 = identity, >1 = boosted).
|
|
31844
|
+
* @returns A new buffer with the saturate matrix applied.
|
|
31845
|
+
*/
|
|
31846
|
+
function feColorMatrixSaturate(src, s) {
|
|
31847
|
+
const rl = .213;
|
|
31848
|
+
const gl = .715;
|
|
31849
|
+
const bl = .072;
|
|
31850
|
+
return feColorMatrix(src, [
|
|
31851
|
+
rl + .787 * s,
|
|
31852
|
+
gl - gl * s,
|
|
31853
|
+
bl - bl * s,
|
|
31854
|
+
0,
|
|
31855
|
+
0,
|
|
31856
|
+
rl - rl * s,
|
|
31857
|
+
gl + .285 * s,
|
|
31858
|
+
bl - bl * s,
|
|
31859
|
+
0,
|
|
31860
|
+
0,
|
|
31861
|
+
rl - rl * s,
|
|
31862
|
+
gl - gl * s,
|
|
31863
|
+
bl + .928 * s,
|
|
31864
|
+
0,
|
|
31865
|
+
0,
|
|
31866
|
+
0,
|
|
31867
|
+
0,
|
|
31868
|
+
0,
|
|
31869
|
+
1,
|
|
31870
|
+
0
|
|
31871
|
+
]);
|
|
31872
|
+
}
|
|
31873
|
+
/**
|
|
31874
|
+
* Shift the image by an integer offset, leaving exposed edges transparent.
|
|
31875
|
+
*
|
|
31876
|
+
* Implements `feOffset` (SVG 1.1 §15.15). Pixels are copied to
|
|
31877
|
+
* `(x + dx, y + dy)`; destinations that fall outside the buffer are dropped
|
|
31878
|
+
* and exposed areas remain transparent black. `dx` / `dy` are rounded to the
|
|
31879
|
+
* nearest integer pixel.
|
|
31880
|
+
*
|
|
31881
|
+
* @param src Source buffer.
|
|
31882
|
+
* @param dx Horizontal offset in pixels (positive = right).
|
|
31883
|
+
* @param dy Vertical offset in pixels (positive = down).
|
|
31884
|
+
* @returns A new buffer of the same size with the shifted content.
|
|
31885
|
+
*/
|
|
31886
|
+
function feOffset(src, dx, dy) {
|
|
31887
|
+
const out = allocBuffer(src.width, src.height);
|
|
31888
|
+
const idx = Math.round(dx);
|
|
31889
|
+
const idy = Math.round(dy);
|
|
31890
|
+
const { width, height } = src;
|
|
31891
|
+
for (let y = 0; y < height; y++) {
|
|
31892
|
+
const sy = y + idy;
|
|
31893
|
+
if (sy < 0 || sy >= height) continue;
|
|
31894
|
+
for (let x = 0; x < width; x++) {
|
|
31895
|
+
const sx = x + idx;
|
|
31896
|
+
if (sx < 0 || sx >= width) continue;
|
|
31897
|
+
const di = (sy * width + sx) * 4;
|
|
31898
|
+
const si = (y * width + x) * 4;
|
|
31899
|
+
out.rgba[di + 0] = src.rgba[si + 0];
|
|
31900
|
+
out.rgba[di + 1] = src.rgba[si + 1];
|
|
31901
|
+
out.rgba[di + 2] = src.rgba[si + 2];
|
|
31902
|
+
out.rgba[di + 3] = src.rgba[si + 3];
|
|
31903
|
+
}
|
|
31904
|
+
}
|
|
31905
|
+
return out;
|
|
31906
|
+
}
|
|
31907
|
+
/**
|
|
31908
|
+
* Compute the box size `d` for the three-box-blur approximation.
|
|
31909
|
+
*
|
|
31910
|
+
* SVG 1.1 §15.17: `d = floor(s · 3 · √(2π) / 4 + 0.5)`.
|
|
31911
|
+
*/
|
|
31912
|
+
function boxBlurD(stdDev) {
|
|
31913
|
+
return Math.floor(stdDev * 3 * Math.sqrt(2 * Math.PI) / 4 + .5);
|
|
31914
|
+
}
|
|
31915
|
+
/**
|
|
31916
|
+
* One horizontal box blur of the given (odd) length, premultiplied float
|
|
31917
|
+
* data, with an asymmetric left/right radius to support the even-`d` rule.
|
|
31918
|
+
* The window covers offsets `[-leftRadius, +rightRadius]` inclusive. Edge
|
|
31919
|
+
* samples are clamped (extend-edge) rather than treated as transparent so a
|
|
31920
|
+
* flat region stays flat.
|
|
31921
|
+
*/
|
|
31922
|
+
function boxBlurH(data, width, height, leftRadius, rightRadius) {
|
|
31923
|
+
const out = new Float32Array(data.length);
|
|
31924
|
+
const windowLen = leftRadius + rightRadius + 1;
|
|
31925
|
+
for (let y = 0; y < height; y++) {
|
|
31926
|
+
const row = y * width;
|
|
31927
|
+
for (let c = 0; c < 4; c++) {
|
|
31928
|
+
let sum = 0;
|
|
31929
|
+
for (let k = -leftRadius; k <= rightRadius; k++) {
|
|
31930
|
+
const cx = k < 0 ? 0 : k >= width ? width - 1 : k;
|
|
31931
|
+
sum += data[(row + cx) * 4 + c];
|
|
31932
|
+
}
|
|
31933
|
+
for (let x = 0; x < width; x++) {
|
|
31934
|
+
out[(row + x) * 4 + c] = sum / windowLen;
|
|
31935
|
+
const dropX = x - leftRadius;
|
|
31936
|
+
const addX = x + rightRadius + 1;
|
|
31937
|
+
const dc = dropX < 0 ? 0 : dropX >= width ? width - 1 : dropX;
|
|
31938
|
+
const ac = addX < 0 ? 0 : addX >= width ? width - 1 : addX;
|
|
31939
|
+
sum += data[(row + ac) * 4 + c] - data[(row + dc) * 4 + c];
|
|
31940
|
+
}
|
|
31941
|
+
}
|
|
31942
|
+
}
|
|
31943
|
+
return out;
|
|
31944
|
+
}
|
|
31945
|
+
/** One vertical box blur — the transpose of {@link boxBlurH}. */
|
|
31946
|
+
function boxBlurV(data, width, height, topRadius, bottomRadius) {
|
|
31947
|
+
const out = new Float32Array(data.length);
|
|
31948
|
+
const windowLen = topRadius + bottomRadius + 1;
|
|
31949
|
+
for (let x = 0; x < width; x++) for (let c = 0; c < 4; c++) {
|
|
31950
|
+
let sum = 0;
|
|
31951
|
+
for (let k = -topRadius; k <= bottomRadius; k++) {
|
|
31952
|
+
const cy = k < 0 ? 0 : k >= height ? height - 1 : k;
|
|
31953
|
+
sum += data[(cy * width + x) * 4 + c];
|
|
31954
|
+
}
|
|
31955
|
+
for (let y = 0; y < height; y++) {
|
|
31956
|
+
out[(y * width + x) * 4 + c] = sum / windowLen;
|
|
31957
|
+
const dropY = y - topRadius;
|
|
31958
|
+
const addY = y + bottomRadius + 1;
|
|
31959
|
+
const dc = dropY < 0 ? 0 : dropY >= height ? height - 1 : dropY;
|
|
31960
|
+
const ac = addY < 0 ? 0 : addY >= height ? height - 1 : addY;
|
|
31961
|
+
sum += data[(ac * width + x) * 4 + c] - data[(dc * width + x) * 4 + c];
|
|
31962
|
+
}
|
|
31963
|
+
}
|
|
31964
|
+
return out;
|
|
31965
|
+
}
|
|
31966
|
+
/**
|
|
31967
|
+
* Apply the three successive box blurs that approximate a Gaussian along one
|
|
31968
|
+
* axis, following the SVG 1.1 §15.17 odd/even centring rule for box size `d`.
|
|
31969
|
+
*
|
|
31970
|
+
* - `d` odd: three box blurs of size `d`, centred on the output pixel
|
|
31971
|
+
* (`radius = (d-1)/2` each side).
|
|
31972
|
+
* - `d` even: two box blurs of size `d` (one offset left-of-centre, one
|
|
31973
|
+
* right-of-centre) plus one box blur of size `d + 1` centred.
|
|
31974
|
+
* - `d <= 1`: identity (no perceivable blur on this axis).
|
|
31975
|
+
*/
|
|
31976
|
+
function threeBoxBlurAxis(data, width, height, d, horizontal) {
|
|
31977
|
+
if (d <= 1) return data;
|
|
31978
|
+
const blur = horizontal ? boxBlurH : boxBlurV;
|
|
31979
|
+
if (d % 2 === 1) {
|
|
31980
|
+
const r = (d - 1) / 2;
|
|
31981
|
+
let cur = blur(data, width, height, r, r);
|
|
31982
|
+
cur = blur(cur, width, height, r, r);
|
|
31983
|
+
cur = blur(cur, width, height, r, r);
|
|
31984
|
+
return cur;
|
|
31985
|
+
}
|
|
31986
|
+
const half = d / 2;
|
|
31987
|
+
let cur = blur(data, width, height, half, half - 1);
|
|
31988
|
+
cur = blur(cur, width, height, half - 1, half);
|
|
31989
|
+
cur = blur(cur, width, height, half, half);
|
|
31990
|
+
return cur;
|
|
31991
|
+
}
|
|
31992
|
+
/**
|
|
31993
|
+
* Approximate a Gaussian blur via three successive box blurs.
|
|
31994
|
+
*
|
|
31995
|
+
* Implements `feGaussianBlur` (SVG 1.1 §15.17). The blur is performed in
|
|
31996
|
+
* **premultiplied** colour space (the correct space for averaging colours
|
|
31997
|
+
* with varying alpha) and un-premultiplied on output. A standard deviation of
|
|
31998
|
+
* 0 on an axis is a no-op for that axis.
|
|
31999
|
+
*
|
|
32000
|
+
* The per-axis box size is `d = floor(s · 3 · √(2π) / 4 + 0.5)` with the
|
|
32001
|
+
* spec's odd/even centring rule.
|
|
32002
|
+
*
|
|
32003
|
+
* @param src Source buffer.
|
|
32004
|
+
* @param stdDevX Standard deviation along X (>= 0).
|
|
32005
|
+
* @param stdDevY Standard deviation along Y; defaults to `stdDevX`.
|
|
32006
|
+
* @returns A new, blurred buffer of the same size.
|
|
32007
|
+
* @throws If either standard deviation is negative.
|
|
32008
|
+
*/
|
|
32009
|
+
function feGaussianBlur(src, stdDevX, stdDevY) {
|
|
32010
|
+
const sx = stdDevX;
|
|
32011
|
+
const sy = stdDevY ?? stdDevX;
|
|
32012
|
+
if (sx < 0 || sy < 0 || Number.isNaN(sx) || Number.isNaN(sy)) throw new Error(`svgFilters.feGaussianBlur: standard deviation must be >= 0 (got ${sx}, ${sy})`);
|
|
32013
|
+
if (sx === 0 && sy === 0) return {
|
|
32014
|
+
width: src.width,
|
|
32015
|
+
height: src.height,
|
|
32016
|
+
rgba: src.rgba.slice()
|
|
32017
|
+
};
|
|
32018
|
+
let data = toPremultipliedF32(src);
|
|
32019
|
+
if (sx > 0) data = threeBoxBlurAxis(data, src.width, src.height, boxBlurD(sx), true);
|
|
32020
|
+
if (sy > 0) data = threeBoxBlurAxis(data, src.width, src.height, boxBlurD(sy), false);
|
|
32021
|
+
return fromPremultipliedF32(data, src.width, src.height);
|
|
32022
|
+
}
|
|
32023
|
+
/**
|
|
32024
|
+
* Composite two buffers with a Porter-Duff operator.
|
|
32025
|
+
*
|
|
32026
|
+
* Implements `feComposite` with operators `over`, `in`, `out`, `atop`, `xor`
|
|
32027
|
+
* (SVG 1.1 §15.13; Porter & Duff, SIGGRAPH 1984). The general form on
|
|
32028
|
+
* premultiplied colour is:
|
|
32029
|
+
*
|
|
32030
|
+
* ```
|
|
32031
|
+
* cr = ca · Fa + cb · Fb
|
|
32032
|
+
* ar = aa · Fa + ab · Fb
|
|
32033
|
+
* ```
|
|
32034
|
+
*
|
|
32035
|
+
* with coefficients (`aa`, `ab` = source/destination alpha):
|
|
32036
|
+
*
|
|
32037
|
+
* | op | Fa | Fb |
|
|
32038
|
+
* | ---- | --------- | --------- |
|
|
32039
|
+
* | over | 1 | 1 − aa |
|
|
32040
|
+
* | in | ab | 0 |
|
|
32041
|
+
* | out | 1 − ab | 0 |
|
|
32042
|
+
* | atop | ab | 1 − aa |
|
|
32043
|
+
* | xor | 1 − ab | 1 − aa |
|
|
32044
|
+
*
|
|
32045
|
+
* Here `a` is the source (foreground) and `b` is the destination
|
|
32046
|
+
* (background). Both buffers must be the same size.
|
|
32047
|
+
*
|
|
32048
|
+
* @param a Source (foreground) buffer.
|
|
32049
|
+
* @param b Destination (background) buffer.
|
|
32050
|
+
* @param op Porter-Duff operator.
|
|
32051
|
+
* @returns A new composited buffer of the same size.
|
|
32052
|
+
* @throws If the buffers differ in size.
|
|
32053
|
+
*/
|
|
32054
|
+
function feComposite(a, b, op) {
|
|
32055
|
+
assertSameSize(a, b);
|
|
32056
|
+
const out = allocBuffer(a.width, a.height);
|
|
32057
|
+
const n = a.width * a.height;
|
|
32058
|
+
for (let i = 0; i < n; i++) {
|
|
32059
|
+
const aa = a.rgba[i * 4 + 3] / 255;
|
|
32060
|
+
const ab = b.rgba[i * 4 + 3] / 255;
|
|
32061
|
+
const ar = a.rgba[i * 4 + 0] / 255 * aa;
|
|
32062
|
+
const ag = a.rgba[i * 4 + 1] / 255 * aa;
|
|
32063
|
+
const abl = a.rgba[i * 4 + 2] / 255 * aa;
|
|
32064
|
+
const br = b.rgba[i * 4 + 0] / 255 * ab;
|
|
32065
|
+
const bg = b.rgba[i * 4 + 1] / 255 * ab;
|
|
32066
|
+
const bb = b.rgba[i * 4 + 2] / 255 * ab;
|
|
32067
|
+
let fa;
|
|
32068
|
+
let fb;
|
|
32069
|
+
switch (op) {
|
|
32070
|
+
case "over":
|
|
32071
|
+
fa = 1;
|
|
32072
|
+
fb = 1 - aa;
|
|
32073
|
+
break;
|
|
32074
|
+
case "in":
|
|
32075
|
+
fa = ab;
|
|
32076
|
+
fb = 0;
|
|
32077
|
+
break;
|
|
32078
|
+
case "out":
|
|
32079
|
+
fa = 1 - ab;
|
|
32080
|
+
fb = 0;
|
|
32081
|
+
break;
|
|
32082
|
+
case "atop":
|
|
32083
|
+
fa = ab;
|
|
32084
|
+
fb = 1 - aa;
|
|
32085
|
+
break;
|
|
32086
|
+
case "xor":
|
|
32087
|
+
fa = 1 - ab;
|
|
32088
|
+
fb = 1 - aa;
|
|
32089
|
+
break;
|
|
32090
|
+
default: throw new Error(`svgFilters.feComposite: unknown operator ${String(op)}`);
|
|
32091
|
+
}
|
|
32092
|
+
const cr = ar * fa + br * fb;
|
|
32093
|
+
const cg = ag * fa + bg * fb;
|
|
32094
|
+
const cb = abl * fa + bb * fb;
|
|
32095
|
+
const car = aa * fa + ab * fb;
|
|
32096
|
+
if (car <= 0) {
|
|
32097
|
+
out.rgba[i * 4 + 0] = 0;
|
|
32098
|
+
out.rgba[i * 4 + 1] = 0;
|
|
32099
|
+
out.rgba[i * 4 + 2] = 0;
|
|
32100
|
+
out.rgba[i * 4 + 3] = 0;
|
|
32101
|
+
} else {
|
|
32102
|
+
out.rgba[i * 4 + 0] = clamp8(cr / car * 255);
|
|
32103
|
+
out.rgba[i * 4 + 1] = clamp8(cg / car * 255);
|
|
32104
|
+
out.rgba[i * 4 + 2] = clamp8(cb / car * 255);
|
|
32105
|
+
out.rgba[i * 4 + 3] = clamp8(car * 255);
|
|
32106
|
+
}
|
|
32107
|
+
}
|
|
32108
|
+
return out;
|
|
32109
|
+
}
|
|
32110
|
+
/**
|
|
32111
|
+
* Blend two buffers with one of the basic SVG 1.1 blend modes.
|
|
32112
|
+
*
|
|
32113
|
+
* Implements `feBlend` (SVG 1.1 §15.11). The spec defines the result on
|
|
32114
|
+
* **premultiplied** colour with `qa` = source alpha, `qb` = destination
|
|
32115
|
+
* alpha:
|
|
32116
|
+
*
|
|
32117
|
+
* - normal: `cr = (1 − qa)·cb + ca`
|
|
32118
|
+
* - multiply: `cr = (1 − qa)·cb + (1 − qb)·ca + ca·cb`
|
|
32119
|
+
* - screen: `cr = cb + ca − ca·cb`
|
|
32120
|
+
* - darken: `cr = min((1 − qa)·cb + ca, (1 − qb)·ca + cb)`
|
|
32121
|
+
* - lighten: `cr = max((1 − qa)·cb + ca, (1 − qb)·ca + cb)`
|
|
32122
|
+
*
|
|
32123
|
+
* with the common result alpha `ar = 1 − (1 − qa)·(1 − qb)`. Inputs `a`
|
|
32124
|
+
* (source) and `b` (destination) must be the same size.
|
|
32125
|
+
*
|
|
32126
|
+
* @param a Source (top) buffer.
|
|
32127
|
+
* @param b Destination (bottom) buffer.
|
|
32128
|
+
* @param mode Blend mode.
|
|
32129
|
+
* @returns A new blended buffer of the same size.
|
|
32130
|
+
* @throws If the buffers differ in size.
|
|
32131
|
+
*/
|
|
32132
|
+
function feBlend(a, b, mode) {
|
|
32133
|
+
assertSameSize(a, b);
|
|
32134
|
+
const out = allocBuffer(a.width, a.height);
|
|
32135
|
+
const n = a.width * a.height;
|
|
32136
|
+
for (let i = 0; i < n; i++) {
|
|
32137
|
+
const qa = a.rgba[i * 4 + 3] / 255;
|
|
32138
|
+
const qb = b.rgba[i * 4 + 3] / 255;
|
|
32139
|
+
const ar = 1 - (1 - qa) * (1 - qb);
|
|
32140
|
+
out.rgba[i * 4 + 3] = clamp8(ar * 255);
|
|
32141
|
+
for (let c = 0; c < 3; c++) {
|
|
32142
|
+
const ca = a.rgba[i * 4 + c] / 255 * qa;
|
|
32143
|
+
const cb = b.rgba[i * 4 + c] / 255 * qb;
|
|
32144
|
+
let cr;
|
|
32145
|
+
switch (mode) {
|
|
32146
|
+
case "normal":
|
|
32147
|
+
cr = (1 - qa) * cb + ca;
|
|
32148
|
+
break;
|
|
32149
|
+
case "multiply":
|
|
32150
|
+
cr = (1 - qa) * cb + (1 - qb) * ca + ca * cb;
|
|
32151
|
+
break;
|
|
32152
|
+
case "screen":
|
|
32153
|
+
cr = cb + ca - ca * cb;
|
|
32154
|
+
break;
|
|
32155
|
+
case "darken":
|
|
32156
|
+
cr = Math.min((1 - qa) * cb + ca, (1 - qb) * ca + cb);
|
|
32157
|
+
break;
|
|
32158
|
+
case "lighten":
|
|
32159
|
+
cr = Math.max((1 - qa) * cb + ca, (1 - qb) * ca + cb);
|
|
32160
|
+
break;
|
|
32161
|
+
default: throw new Error(`svgFilters.feBlend: unknown mode ${String(mode)}`);
|
|
32162
|
+
}
|
|
32163
|
+
if (ar <= 0) out.rgba[i * 4 + c] = 0;
|
|
32164
|
+
else out.rgba[i * 4 + c] = clamp8(cr / ar * 255);
|
|
32165
|
+
}
|
|
32166
|
+
}
|
|
32167
|
+
return out;
|
|
32168
|
+
}
|
|
32169
|
+
//#endregion
|
|
31389
32170
|
//#region src/render/matrix.ts
|
|
31390
32171
|
/** The identity transform. */
|
|
31391
32172
|
function identity() {
|
|
@@ -35213,6 +35994,6 @@ async function initWasm(options) {
|
|
|
35213
35994
|
wasmInitialized = true;
|
|
35214
35995
|
}
|
|
35215
35996
|
//#endregion
|
|
35216
|
-
export {
|
|
35997
|
+
export { feBlend as $, getLinearizationInfo as $a, encodeEan13 as $i, generateCiiXml as $n, generateUnderlineAppearance as $o, flattenForm as $r, validatePdfX as $t, buildSoftMaskNone as A, generatePdfAXmpBytes as Aa, applyPreset as Ai, decodeWoff as An, PdfCaretAnnotation as Ao, buildPieceInfo as Ar, parseVariableFont as At, redactRegions as B, isValidLevel as Ba, readEan8 as Bi, renderToPdf as Bn, PdfHighlightAnnotation as Bo, StreamingPdfParser as Br, verifyOfflineRevocation as Bt, tagTableHeaderCell as C, downscaleImage as Ca, toRoman as Ci, validateFieldValue as Cn, saveIncrementalWithSignaturePreservation as Co, SARIF_SCHEMA_URI as Cr, buildCoonsPatchShading as Ct, buildImageSoftMask as D, applyRedaction as Da, shrinkFontSize as Di, parseAcrobatDate as Dn, requestTimestamp as Do, PDF2_NAMESPACE as Dr, getColorGlyphLayers as Dt, buildColorKeyMask as E, recompressImage as Ea, estimateTextWidth as Ei, formatDate as En, parseTimestampResponse as Eo, MATHML_NAMESPACE as Er, buildTensorPatchShading as Et, attachAssociatedFiles as F, extractXmpMetadata as Fa, stripedPreset as Fi, createWorkerPool as Fn, PdfCircleAnnotation as Fo, tableToCsv as Fr, verifyRedactions as Ft, extractImages as G, buildOutputIntent as Ga, dataMatrixToOperators as Gi, generateXRechnungCii as Gn, generateCircleAppearance as Go, batchMerge as Gr, buildCertificateChain as Gt, compareImages as H, generateWinAnsiToUnicodeCmap as Ha, renderStyledBarcode as Hi, resolveFallback as Hn, PdfStrikeOutAnnotation as Ho, enforcePdfUa as Hr, validateCertificatePolicy as Ht, registerEmbeddedFile as I, parseXmpMetadata as Ia, readBarcode as Ii, buildPdfVtDParts as In, PdfLineAnnotation as Io, tableToJson as Ir, sanitizePdf as It, renderPageToCanvas as J, detectTransparency as Ja, encodeUpcA as Ji, buildFunctionShading as Jn, generateInkAppearance as Jo, getBookmarks as Jr, layoutColumns as Jt, generateThumbnail as K, SRGB_ICC_PROFILE as Ka, encodeDataMatrix as Ki, buildPdfA4Xmp as Kn, generateFreeTextAppearance as Ko, processBatch as Kr, validateCertificateChain as Kt, RenderCache as L, validateXmpMetadata as La, readCode128 as Li, buildVtDpm as Ln, PdfPolyLineAnnotation as Lo, accessibilityPlugin as Lr, scanPdfThreats as Lt, buildUnencryptedWrapper as M, stripProhibitedFeatures as Ma, borderedPreset as Mi, isWoff2 as Mn, PdfRedactAnnotation as Mo, buildRequirements as Mr, reorderVisual as Mt, attachOutputIntents as N, buildAfArray as Na, minimalPreset as Ni, readWoffHeader as Nn, PdfInkAnnotation as No, buildDPartRoot as Nr, resolveBidi as Nt, buildStencilMask as O, enforcePdfAFull as Oa, truncateText as Oi, AFNumber_Format as On, searchTextItems as Oo, buildNamespace as Or, parseColorFont as Ot, buildPageOutputIntent as P, createAssociatedFile as Pa, professionalPreset as Pi, signDeferred as Pn, PdfStampAnnotation as Po, extractTables as Pr, inspectEncryption as Pt, interpretPage as Q, delinearizePdf as Qa, ean8ToOperators as Qi, renderCodeFrame as Qn, generateStrikeOutAppearance as Qo, flattenFields as Qr, enforcePdfX as Qt, computeTileGrid as R, getProfile as Ra, readCode39 as Ri, gtsPdfVtVersion as Rn, PdfPolygonAnnotation as Ro, metadataPlugin as Rr, buildCertPath as Rt, tagTableDataCell as S, analyzeJpegMarkers as Sa, toAlpha as Si, setFieldVisibility as Sn, parseExistingTrailer as So, DEFAULT_SARIF_TOOL_NAME as Sr, xyzToLab as St, buildBlackPointCompensationExtGState as T, optimizeImage as Ta, ellipsisText as Ti, AFDate_FormatEx as Tn, buildTimestampRequest as To, toSarif as Tr, buildLatticeFormGouraudShading as Tt, comparePages as U, generateZapfDingbatsToUnicodeCmap as Ua, encodePdf417 as Ui, splitByScript as Un, PdfUnderlineAnnotation as Uo, validatePdfUa as Ur, validateExtendedKeyUsage as Ut, applyOcr as V, generateSymbolToUnicodeCmap as Va, calculateBarcodeDimensions as Vi, createRangeFetcher as Vn, PdfSquigglyAnnotation as Vo, PdfDocumentBuilder as Vr, EKU_OIDS as Vt, extractFonts as W, getToUnicodeCmap as Wa, pdf417ToOperators as Wi, generateOrderX as Wn, PdfFreeTextAnnotation as Wo, batchFlatten as Wr, validateKeyUsage as Wt, renderPageToImage as X, enforcePdfA as Xa, calculateEanCheckDigit as Xi, didYouMean as Xn, generateSquareAppearance as Xo, removeBookmark as Xr, layoutTextFlow as Xt, rasterize as Y, flattenTransparency as Ya, upcAToOperators as Yi, sampleShadingColor as Yn, generateLineAppearance as Yo, removeAllBookmarks as Yr, layoutParagraph as Yt, interpretContentStream as Z, validatePdfA as Za, ean13ToOperators as Zi, levenshtein as Zn, generateSquigglyAppearance as Zo, flattenField as Zr, buildPdfXOutputIntent as Zt, tagLink as _, convertTiffCmykToRgb as _a, UnexpectedFieldTypeError as _i, createSandbox as _n, getCertificationLevel as _o, buildDocTimeStampDict as _r, rgbToLab as _t, assembleFacturX as a, encodeCode39 as aa, FieldExistsAsNonTerminalError as ai, upscale8To16 as an, buildDssDictionary as ao, buildSampledTransferFunction as ar, PDFOperator as as, feOffset as at, tagParagraph as b, extractJpegMetadata as ba, formatDate$1 as bi, setFieldValue as bn, appendIncrementalUpdate as bo, buildLab as br, deviceRgbToXyz as bt, buildWtpdfIdentificationXmp as c, encodeCode128Values as ca, InvalidColorError as ci, decodeTileRegion as cn, addCounterSignature as co, buildType5Halftone as cr, ChangeTracker as cs, hasImageDecoder as ct, autoTagPage as d, canDirectEmbed as da, MissingOnValueCheckError as di, TrustStore as dn, addFieldLock as do, evaluateFunction as dr, detectNextGenFormat as dt, encodeEan8 as ea, BatchProcessingError as ei, downscale16To8 as en, isLinearized as eo, buildBoxDict as er, PdfLinkAnnotation as es, feColorMatrix as et, buildPdfUa2Xmp as f, embedTiffDirect as fa, NoSuchFieldError as fi, downloadCrl as fn, buildFieldLockDict as fo, markdownToPdf as fr, probeNextGenImage as ft, tagHeading as g, webpToPng as ga, StreamingParseError as gi, extractOcspUrl as gn, buildDocMdpReference as go, DEFAULT_DOC_TIMESTAMP_CONTENTS_SIZE as gr, rgbToHsv as gt, tagFigure as h, webpToJpeg as ha, RichTextFieldReadError as hi, checkCertificateStatus as hn, MdpPermission as ho, reconstructParagraphs as hr, rgbToHsl as ht, validateEn16931 as i, computeCode39CheckDigit as ia, FieldAlreadyExistsError as ii, summarizeBitDepth as in, optimizeIncrementalSave as io, STANDARD_SPOT_FUNCTIONS as ir, parseXmpMetadata$1 as is, feGaussianBlur as it, buildEncryptedPayload as j, countOccurrences as ja, applyTablePreset as ji, isWoff as jn, PdfPopupAnnotation as jo, buildRequirement as jr, resolveInstanceCoordinates as jt, buildSoftMaskGroupExtGState as k, generatePdfAXmp as ka, wrapText$2 as ki, formatNumber$1 as kn, PdfFileAttachmentAnnotation as ko, buildNamespacesArray as kr, normalizeAxisCoordinate as kt, convertPdfAConformanceXmp as l, valuesToModules as la, InvalidFieldNamePartError as li, parseTileInfo as ln, getCounterSignatures as lo, identityTransferFunction as lr, saveDocumentIncremental as ls, registerImageDecoder as lt, LIST_NUMBERING_KEY as m, recompressWebP as ma, RemovePageFromEmptyDocumentError as mi, isCertificateRevoked as mn, detectModifications as mo, reconstructLines as mr, hsvToRgb as mt, detectFacturXProfile as n, itfToOperators as na, EncryptedPdfError as ni, normalizeComponentDepth as nn, computeObjectHash as no, buildPdfX6OutputIntent as nr, buildXmpMetadata as ns, feComposite as nt, buildFacturXXmp as o, code128ToOperators as oa, FontNotEmbeddedError as oi, assembleTiles as on, embedLtvData as oo, buildThresholdHalftone as or, buildDeviceNColorSpace as os, decodeRegisteredImage as ot, validatePdfUa2 as p, encodePngFromPixels as pa, PluginError as pi, extractCrlUrls as pn, getFieldLocks as po, buildCollection as pr, hslToRgb as pt, renderDisplayListToCanvas as q, generateSrgbIccProfile as qa, calculateUpcCheckDigit as qi, pdfA4Rules as qn, generateHighlightAppearance as qo, addBookmark as qr, findHyphenationPoints as qt, parseCiiXml as r, code39ToOperators as ra, ExceededMaxLengthError as ri, offsetSignedToUnsigned as rn, findChangedObjects as ro, validateBoxGeometry as rr, createXmpStream as rs, feFlood as rt, buildPdfRIdentificationXmp as s, encodeCode128 as sa, ForeignPageError as si, decodeTile as sn, hasLtvData as so, buildType1Halftone as sr, buildSeparationColorSpace as ss, getImageDecoder as st, initWasm as t, encodeItf as ta, CombedTextLayoutError as ti, getComponentDepths as tn, linearizePdf as to, buildGtsPdfxVersion as tr, PdfTextAnnotation as ts, feColorMatrixSaturate as tt, preflightPdfA as u, PdfWorker as ua, InvalidPageSizeError as ui, verifySignatureDetailed as un, diffSignedContent as uo, nameHalftone as ur, saveIncremental as us, unregisterImageDecoder as ut, tagList as v, embedTiffCmyk as va, applyHeaderFooter as vi, getFieldValue as vn, setCertificationLevel as vo, buildCalGray as vr, rgbToXyz as vt, tagTableRow as w, estimateJpegQuality as wa, applyOverflow as wi, AFSpecial_Format as wn, validateByteRangeIntegrity as wo, toJsonReport as wr, buildFreeFormGouraudShading as wt, tagTable as x, injectJpegMetadata as xa, replaceTemplateVariables as xi, addVisibilityAction as xn, findExistingSignatures as xo, labToRgb as xr, parseIccTransform as xt, tagListItem as y, isCmykTiff as ya, applyHeaderFooterToPage as yi, resolveFieldReference as yn, validateSignatureChain as yo, buildCalRGB as yr, xyzToRgb as yt, renderPageTile as z, getSupportedLevels as za, readEan13 as zi, h as zn, PdfSquareAnnotation as zo, timestampPlugin as zr, extractEmbeddedRevocationData as zt };
|
|
35217
35998
|
|
|
35218
|
-
//# sourceMappingURL=src-
|
|
35999
|
+
//# sourceMappingURL=src-DlRTrvWg.mjs.map
|