modern-pdf-lib 0.36.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.
@@ -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$1(data, offset, le) {
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$1(data, entryOffset + 4, le);
9618
- const valueOrOffset = readU32$1(data, entryOffset + 8, le);
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$1(data, pos, le));
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$1(data, 4, le);
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$1(data, nextIfdOffset, le);
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$1(data, 4, le);
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;
@@ -19503,15 +19503,15 @@ const D50_WHITE_POINT = [
19503
19503
  .8249
19504
19504
  ];
19505
19505
  /** CIE constant δ = 6/29; the linear/cubic break is at t ≤ δ. */
19506
- const LAB_DELTA = 6 / 29;
19506
+ const LAB_DELTA$2 = 6 / 29;
19507
19507
  /** 3δ² — slope of the inverse linear branch. */
19508
- const LAB_3_DELTA_SQUARED = 3 * LAB_DELTA * LAB_DELTA;
19508
+ const LAB_3_DELTA_SQUARED$1 = 3 * LAB_DELTA$2 * LAB_DELTA$2;
19509
19509
  /** Inverse of the CIE L*a*b* nonlinearity f(t). */
19510
19510
  function labInverseF(t) {
19511
- return t > LAB_DELTA ? t * t * t : LAB_3_DELTA_SQUARED * (t - 4 / 29);
19511
+ return t > LAB_DELTA$2 ? t * t * t : LAB_3_DELTA_SQUARED$1 * (t - 4 / 29);
19512
19512
  }
19513
19513
  /** Apply the sRGB transfer function (linear → companded), input clamped 0..1. */
19514
- function linearToSrgb(c) {
19514
+ function linearToSrgb$1(c) {
19515
19515
  const clamped = c < 0 ? 0 : c > 1 ? 1 : c;
19516
19516
  const v = clamped <= .0031308 ? 12.92 * clamped : 1.055 * clamped ** (1 / 2.4) - .055;
19517
19517
  return v < 0 ? 0 : v > 1 ? 1 : v;
@@ -19545,9 +19545,9 @@ function labToRgb(L, a, b, whitePoint = D50_WHITE_POINT) {
19545
19545
  const gLin = -.9787684 * X + 1.9161415 * Y + .033454 * Z;
19546
19546
  const bLin = .0719453 * X - .2289914 * Y + 1.4052427 * Z;
19547
19547
  return [
19548
- linearToSrgb(rLin),
19549
- linearToSrgb(gLin),
19550
- linearToSrgb(bLin)
19548
+ linearToSrgb$1(rLin),
19549
+ linearToSrgb$1(gLin),
19550
+ linearToSrgb$1(bLin)
19551
19551
  ];
19552
19552
  }
19553
19553
  //#endregion
@@ -20153,7 +20153,7 @@ function breakLongWord$1(word, font, size, limit) {
20153
20153
  //#endregion
20154
20154
  //#region src/core/pdfFunctions.ts
20155
20155
  /** Clamp `x` into the inclusive `[lo, hi]` interval. */
20156
- function clamp(x, lo, hi) {
20156
+ function clamp$1(x, lo, hi) {
20157
20157
  if (x < lo) return lo;
20158
20158
  if (x > hi) return hi;
20159
20159
  return x;
@@ -20173,14 +20173,14 @@ function clampToRange(out, range) {
20173
20173
  for (let i = 0; i < out.length; i++) {
20174
20174
  const lo = range[2 * i];
20175
20175
  const hi = range[2 * i + 1];
20176
- if (lo !== void 0 && hi !== void 0) out[i] = clamp(out[i], lo, hi);
20176
+ if (lo !== void 0 && hi !== void 0) out[i] = clamp$1(out[i], lo, hi);
20177
20177
  }
20178
20178
  return out;
20179
20179
  }
20180
20180
  function evaluateExponential(fn, inputs) {
20181
20181
  const c0 = fn.c0 ?? [0];
20182
20182
  const c1 = fn.c1 ?? [1];
20183
- const x = clamp(inputs[0] ?? 0, fn.domain[0] ?? 0, fn.domain[1] ?? 1);
20183
+ const x = clamp$1(inputs[0] ?? 0, fn.domain[0] ?? 0, fn.domain[1] ?? 1);
20184
20184
  const xn = fn.n === 1 ? x : x ** fn.n;
20185
20185
  const count = Math.max(c0.length, c1.length);
20186
20186
  const out = [];
@@ -20194,7 +20194,7 @@ function evaluateExponential(fn, inputs) {
20194
20194
  function evaluateStitching(fn, inputs) {
20195
20195
  const d0 = fn.domain[0] ?? 0;
20196
20196
  const d1 = fn.domain[1] ?? 1;
20197
- const x = clamp(inputs[0] ?? 0, d0, d1);
20197
+ const x = clamp$1(inputs[0] ?? 0, d0, d1);
20198
20198
  const k = fn.functions.length;
20199
20199
  let i = 0;
20200
20200
  while (i < fn.bounds.length && x >= fn.bounds[i]) i++;
@@ -20212,10 +20212,10 @@ function evaluateSampled(fn, inputs) {
20212
20212
  for (let j = 0; j < m; j++) {
20213
20213
  const dMin = fn.domain[2 * j] ?? 0;
20214
20214
  const dMax = fn.domain[2 * j + 1] ?? 1;
20215
- const x = clamp(inputs[j] ?? 0, dMin, dMax);
20215
+ const x = clamp$1(inputs[j] ?? 0, dMin, dMax);
20216
20216
  const size = fn.size[j] ?? 1;
20217
20217
  const enc = interpolate(x, dMin, dMax, fn.encode ? fn.encode[2 * j] ?? 0 : 0, fn.encode ? fn.encode[2 * j + 1] ?? size - 1 : size - 1);
20218
- e.push(clamp(enc, 0, size - 1));
20218
+ e.push(clamp$1(enc, 0, size - 1));
20219
20219
  }
20220
20220
  const lower = [];
20221
20221
  const frac = [];
@@ -20561,7 +20561,7 @@ function evaluatePostScript(fn, inputs) {
20561
20561
  for (let j = 0; j < m; j++) {
20562
20562
  const dMin = fn.domain[2 * j] ?? 0;
20563
20563
  const dMax = fn.domain[2 * j + 1] ?? 1;
20564
- stack.push(clamp(inputs[j] ?? 0, dMin, dMax));
20564
+ stack.push(clamp$1(inputs[j] ?? 0, dMin, dMax));
20565
20565
  }
20566
20566
  execPostScript(program, stack);
20567
20567
  const nOut = Math.floor(fn.range.length / 2);
@@ -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;
@@ -30527,6 +30527,1646 @@ function getColorGlyphLayers(fontData, glyphId, paletteIndex = 0) {
30527
30527
  return layers;
30528
30528
  }
30529
30529
  //#endregion
30530
+ //#region src/core/meshShading.ts
30531
+ /**
30532
+ * @module core/meshShading
30533
+ *
30534
+ * Mesh shadings — ShadingType 4, 5, 6 and 7 (ISO 32000-2:2020 §8.7.4.5.5–.8).
30535
+ *
30536
+ * Mesh shadings define colour over a 2-D region by tessellating it into either
30537
+ * Gouraud-shaded triangles (types 4 and 5) or parametric patches (types 6 and
30538
+ * 7). Unlike the dictionary-only shadings (types 1–3), a mesh shading's data is
30539
+ * carried in a **stream** whose body is a packed sequence of binary records.
30540
+ *
30541
+ * Bit-packing rule (ISO 32000-2 §8.7.4.5.5, "All vertex coordinates and colour
30542
+ * values shall be encoded as ... a sequence of bits ... most significant bit
30543
+ * first"): every value — flag, coordinate and colour component — is written
30544
+ * big-endian, MSB-first, into a continuous bit stream with **no padding between
30545
+ * values**. Only the very end of the stream is padded with zero bits up to the
30546
+ * next byte boundary. (§8.7.4.5.5 further notes each value may begin at any bit
30547
+ * position; there is no per-record byte alignment.)
30548
+ *
30549
+ * Numeric mapping (ISO 32000-2 §8.7.4.5.5, Table 84 /Decode semantics): a
30550
+ * coordinate or colour value is stored as an unsigned integer `v` in the range
30551
+ * `[0, 2^bits − 1]` and decoded as
30552
+ * `decoded = Dmin + v · (Dmax − Dmin) / (2^bits − 1)`
30553
+ * where `[Dmin, Dmax]` is the matching pair in the shading's /Decode array. The
30554
+ * /Decode layout is `[xmin xmax ymin ymax c1min c1max … cnmin cnmax]` (or, when
30555
+ * /Function is present, a single `[tmin tmax]` colour pair). The builders here
30556
+ * take **decoded** user values and invert that mapping to obtain the raw
30557
+ * integers to pack, rounding to nearest.
30558
+ *
30559
+ * Record layouts verified against ISO 32000-2:2020:
30560
+ * - Type 4 (§8.7.4.5.5): per vertex → flag (BitsPerFlag) · x · y · colour[n].
30561
+ * - Type 5 (§8.7.4.5.6): per vertex → x · y · colour[n]; NO flag; adds
30562
+ * /VerticesPerRow (≥ 2). Vertices are given row by row.
30563
+ * - Type 6 (§8.7.4.5.7): per patch → flag (BitsPerFlag) · coordinate pairs ·
30564
+ * colours. Flag 0 (new patch) = 12 coordinate pairs + 4 colours; flags 1–3
30565
+ * (shared edge) = 8 coordinate pairs + 2 colours.
30566
+ * - Type 7 (§8.7.4.5.8): like type 6 but flag 0 = 16 coordinate pairs +
30567
+ * 4 colours; flags 1–3 = 12 coordinate pairs + 2 colours.
30568
+ *
30569
+ * No Buffer — uses Uint8Array exclusively.
30570
+ */
30571
+ /**
30572
+ * Accumulates unsigned integer values of arbitrary bit width into a byte
30573
+ * stream, big-endian and most-significant-bit-first, with no inter-value
30574
+ * padding. The final byte is zero-padded to the byte boundary on
30575
+ * {@link BitPacker.finish}.
30576
+ *
30577
+ * @internal
30578
+ */
30579
+ var BitPacker = class {
30580
+ bytes = [];
30581
+ /** Bits already filled in the current (pending) byte, 0–7. */
30582
+ bitPos = 0;
30583
+ /** The partially filled current byte (high bits set first). */
30584
+ current = 0;
30585
+ /**
30586
+ * Append `bits`-wide unsigned integer `value`, MSB first.
30587
+ *
30588
+ * @param value - non-negative integer in `[0, 2^bits − 1]`.
30589
+ * @param bits - field width (1–32).
30590
+ */
30591
+ push(value, bits) {
30592
+ for (let i = bits - 1; i >= 0; i--) {
30593
+ const bit = value >>> i & 1;
30594
+ this.current = this.current << 1 | bit;
30595
+ this.bitPos++;
30596
+ if (this.bitPos === 8) {
30597
+ this.bytes.push(this.current & 255);
30598
+ this.current = 0;
30599
+ this.bitPos = 0;
30600
+ }
30601
+ }
30602
+ }
30603
+ /**
30604
+ * Flush the pending partial byte (zero-padded on the low bits) and return the
30605
+ * packed buffer.
30606
+ */
30607
+ finish() {
30608
+ if (this.bitPos > 0) {
30609
+ this.bytes.push(this.current << 8 - this.bitPos & 255);
30610
+ this.current = 0;
30611
+ this.bitPos = 0;
30612
+ }
30613
+ return Uint8Array.from(this.bytes);
30614
+ }
30615
+ };
30616
+ /**
30617
+ * Invert the /Decode mapping for one value: given a decoded user value and its
30618
+ * `[min, max]` pair, return the raw unsigned integer in `[0, 2^bits − 1]`.
30619
+ *
30620
+ * `raw = round((decoded − min) / (max − min) · (2^bits − 1))`, clamped to the
30621
+ * representable range (ISO 32000-2 §8.7.4.5.5, /Decode semantics). A degenerate
30622
+ * `min == max` pair maps everything to 0.
30623
+ *
30624
+ * @internal
30625
+ */
30626
+ function encodeValue(decoded, min, max, bits) {
30627
+ const maxRaw = bits >= 32 ? 4294967295 : (1 << bits) - 1;
30628
+ if (max === min) return 0;
30629
+ const t = (decoded - min) / (max - min);
30630
+ const raw = Math.round(t * maxRaw);
30631
+ if (raw < 0) return 0;
30632
+ if (raw > maxRaw) return maxRaw;
30633
+ return raw;
30634
+ }
30635
+ /**
30636
+ * Number of colour components carried per vertex/corner:
30637
+ * 1 when a /Function is present (parametric `t`), else the count implied by the
30638
+ * colour /Decode pairs.
30639
+ *
30640
+ * @internal
30641
+ */
30642
+ function colorComponentCount(common) {
30643
+ if (common.function !== void 0) return 1;
30644
+ const colorPairs = (common.decode.length - 4) / 2;
30645
+ return Math.max(1, Math.trunc(colorPairs));
30646
+ }
30647
+ /**
30648
+ * Pack one vertex's coordinates then its colours (no flag) into `packer`.
30649
+ *
30650
+ * @internal
30651
+ */
30652
+ function packVertexData(packer, vertex, common, nColor) {
30653
+ const { decode, bitsPerCoordinate: bpcoord, bitsPerComponent: bpcomp } = common;
30654
+ packer.push(encodeValue(vertex.x, decode[0] ?? 0, decode[1] ?? 1, bpcoord), bpcoord);
30655
+ packer.push(encodeValue(vertex.y, decode[2] ?? 0, decode[3] ?? 1, bpcoord), bpcoord);
30656
+ for (let k = 0; k < nColor; k++) {
30657
+ const cmin = decode[4 + 2 * k] ?? 0;
30658
+ const cmax = decode[5 + 2 * k] ?? 1;
30659
+ const comp = vertex.color[k] ?? 0;
30660
+ packer.push(encodeValue(comp, cmin, cmax, bpcomp), bpcomp);
30661
+ }
30662
+ }
30663
+ /**
30664
+ * Pack a single `[x, y]` control point (coordinates only) into `packer`.
30665
+ *
30666
+ * @internal
30667
+ */
30668
+ function packPoint(packer, point, common) {
30669
+ const { decode, bitsPerCoordinate: bpcoord } = common;
30670
+ packer.push(encodeValue(point[0], decode[0] ?? 0, decode[1] ?? 1, bpcoord), bpcoord);
30671
+ packer.push(encodeValue(point[1], decode[2] ?? 0, decode[3] ?? 1, bpcoord), bpcoord);
30672
+ }
30673
+ /**
30674
+ * Pack one colour (n components) into `packer`.
30675
+ *
30676
+ * @internal
30677
+ */
30678
+ function packColor(packer, color, common, nColor) {
30679
+ const { decode, bitsPerComponent: bpcomp } = common;
30680
+ for (let k = 0; k < nColor; k++) {
30681
+ const cmin = decode[4 + 2 * k] ?? 0;
30682
+ const cmax = decode[5 + 2 * k] ?? 1;
30683
+ const comp = color[k] ?? 0;
30684
+ packer.push(encodeValue(comp, cmin, cmax, bpcomp), bpcomp);
30685
+ }
30686
+ }
30687
+ /**
30688
+ * Build the dictionary shared by every mesh shading and set the common keys.
30689
+ *
30690
+ * @internal
30691
+ */
30692
+ function buildCommonDict(shadingType, common, includeFlag) {
30693
+ const dict = new PdfDict();
30694
+ dict.set("/ShadingType", PdfNumber.of(shadingType));
30695
+ dict.set("/ColorSpace", common.colorSpace);
30696
+ dict.set("/BitsPerCoordinate", PdfNumber.of(common.bitsPerCoordinate));
30697
+ dict.set("/BitsPerComponent", PdfNumber.of(common.bitsPerComponent));
30698
+ if (includeFlag) dict.set("/BitsPerFlag", PdfNumber.of(common.bitsPerFlag));
30699
+ dict.set("/Decode", PdfArray.fromNumbers([...common.decode]));
30700
+ if (common.function !== void 0) dict.set("/Function", common.function);
30701
+ return dict;
30702
+ }
30703
+ /**
30704
+ * Build a free-form Gouraud-shaded triangle mesh shading
30705
+ * (ISO 32000-2 §8.7.4.5.5, /ShadingType 4).
30706
+ *
30707
+ * Each vertex is packed as `flag · x · y · colour[n]`, MSB-first, with the flag
30708
+ * `bitsPerFlag` wide.
30709
+ *
30710
+ * @param options - the common mesh keys plus the triangle/vertex data.
30711
+ * @returns a {@link PdfStream} whose dict has /ShadingType 4 and whose body is
30712
+ * the packed vertex stream.
30713
+ */
30714
+ function buildFreeFormGouraudShading(options) {
30715
+ const dict = buildCommonDict(4, options, true);
30716
+ const nColor = colorComponentCount(options);
30717
+ const packer = new BitPacker();
30718
+ for (const tri of options.triangles) for (const vertex of tri.vertices) {
30719
+ packer.push(vertex.flag, options.bitsPerFlag);
30720
+ packVertexData(packer, vertex, options, nColor);
30721
+ }
30722
+ const data = packer.finish();
30723
+ return PdfStream.fromBytes(data, dict);
30724
+ }
30725
+ /**
30726
+ * Build a lattice-form Gouraud-shaded triangle mesh shading
30727
+ * (ISO 32000-2 §8.7.4.5.6, /ShadingType 5).
30728
+ *
30729
+ * Vertices carry **no** flag; the mesh topology is implied by /VerticesPerRow.
30730
+ * Each vertex is packed as `x · y · colour[n]`, MSB-first.
30731
+ *
30732
+ * @param options - the common mesh keys (sans /BitsPerFlag) plus
30733
+ * /VerticesPerRow and the row-major vertex list.
30734
+ * @returns a {@link PdfStream} with /ShadingType 5 and /VerticesPerRow.
30735
+ */
30736
+ function buildLatticeFormGouraudShading(options) {
30737
+ const common = {
30738
+ colorSpace: options.colorSpace,
30739
+ bitsPerCoordinate: options.bitsPerCoordinate,
30740
+ bitsPerComponent: options.bitsPerComponent,
30741
+ bitsPerFlag: 8,
30742
+ decode: options.decode,
30743
+ function: options.function
30744
+ };
30745
+ const dict = buildCommonDict(5, common, false);
30746
+ dict.set("/VerticesPerRow", PdfNumber.of(options.verticesPerRow));
30747
+ const nColor = colorComponentCount(common);
30748
+ const packer = new BitPacker();
30749
+ for (const vertex of options.vertices) packVertexData(packer, vertex, common, nColor);
30750
+ const data = packer.finish();
30751
+ return PdfStream.fromBytes(data, dict);
30752
+ }
30753
+ /**
30754
+ * Build a Coons patch mesh shading
30755
+ * (ISO 32000-2 §8.7.4.5.7, /ShadingType 6).
30756
+ *
30757
+ * Each patch is packed as `flag · points · colours`. A flag-0 patch carries 12
30758
+ * control points and 4 corner colours; flags 1–3 carry 8 control points and 2
30759
+ * colours (the rest are inherited from the shared edge of the previous patch).
30760
+ *
30761
+ * @param options - the common mesh keys plus the patch list.
30762
+ * @returns a {@link PdfStream} with /ShadingType 6.
30763
+ */
30764
+ function buildCoonsPatchShading(options) {
30765
+ const dict = buildCommonDict(6, options, true);
30766
+ const nColor = colorComponentCount(options);
30767
+ const packer = new BitPacker();
30768
+ for (const patch of options.patches) {
30769
+ packer.push(patch.flag, options.bitsPerFlag);
30770
+ for (const point of patch.points) packPoint(packer, point, options);
30771
+ for (const color of patch.colors) packColor(packer, color, options, nColor);
30772
+ }
30773
+ const data = packer.finish();
30774
+ return PdfStream.fromBytes(data, dict);
30775
+ }
30776
+ /**
30777
+ * Build a tensor-product patch mesh shading
30778
+ * (ISO 32000-2 §8.7.4.5.8, /ShadingType 7).
30779
+ *
30780
+ * Identical packing to type 6 but a flag-0 patch carries 16 control points (the
30781
+ * 4 internal tensor points in addition to the 12 boundary points) plus 4 corner
30782
+ * colours; flags 1–3 carry 12 control points and 2 colours.
30783
+ *
30784
+ * @param options - the common mesh keys plus the patch list.
30785
+ * @returns a {@link PdfStream} with /ShadingType 7.
30786
+ */
30787
+ function buildTensorPatchShading(options) {
30788
+ const dict = buildCommonDict(7, options, true);
30789
+ const nColor = colorComponentCount(options);
30790
+ const packer = new BitPacker();
30791
+ for (const patch of options.patches) {
30792
+ packer.push(patch.flag, options.bitsPerFlag);
30793
+ for (const point of patch.points) packPoint(packer, point, options);
30794
+ for (const color of patch.colors) packColor(packer, color, options, nColor);
30795
+ }
30796
+ const data = packer.finish();
30797
+ return PdfStream.fromBytes(data, dict);
30798
+ }
30799
+ //#endregion
30800
+ //#region src/color/iccTransform.ts
30801
+ /**
30802
+ * ICC PCS reference white, D50, in XYZ (ICC.1:2010 §6.3.4.3 / Annex A,
30803
+ * encoded white point `[0.9642, 1.0000, 0.8249]`).
30804
+ */
30805
+ const D50_WHITE = [
30806
+ .9642,
30807
+ 1,
30808
+ .8249
30809
+ ];
30810
+ /** CIE L\*a\*b\* threshold δ = 6/29 (CIE 15:2004 §8.2.1). */
30811
+ const LAB_DELTA$1 = 6 / 29;
30812
+ /** δ³ — the f(t) breakpoint in the t domain. */
30813
+ const LAB_DELTA_CUBED$1 = LAB_DELTA$1 * LAB_DELTA$1 * LAB_DELTA$1;
30814
+ /** 1 / (3·δ²) — slope of the linear segment of f(t). */
30815
+ const LAB_LINEAR_SLOPE = 1 / (3 * LAB_DELTA$1 * LAB_DELTA$1);
30816
+ /** 4/29 — intercept of the linear segment of f(t). */
30817
+ const LAB_LINEAR_INTERCEPT = 4 / 29;
30818
+ const HEADER_SIZE = 128;
30819
+ const TAG_COUNT_OFFSET = 128;
30820
+ const TAG_TABLE_OFFSET = 132;
30821
+ const TAG_RECORD_SIZE = 12;
30822
+ /** Decode a 4-byte ASCII signature at `off`. */
30823
+ function readSig(data, off) {
30824
+ return String.fromCharCode(data[off], data[off + 1], data[off + 2], data[off + 3]);
30825
+ }
30826
+ /** s15Fixed16Number → JS number (ICC.1:2010 §4.2): signed int32 / 65536. */
30827
+ function readS15Fixed16(view, off) {
30828
+ return view.getInt32(off, false) / 65536;
30829
+ }
30830
+ /**
30831
+ * Read the tag table into a `sig → {offset,size}` map.
30832
+ *
30833
+ * @throws if the profile is shorter than a header + tag count, or the tag
30834
+ * table extends past the end of the data.
30835
+ */
30836
+ function readTagTable(data) {
30837
+ if (data.length < TAG_TABLE_OFFSET) throw new Error(`ICC profile too short: ${data.length} bytes (need at least ${TAG_TABLE_OFFSET}).`);
30838
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
30839
+ const count = view.getUint32(TAG_COUNT_OFFSET, false);
30840
+ if (TAG_TABLE_OFFSET + count * TAG_RECORD_SIZE > data.length) throw new Error(`ICC tag table (${count} tags) overruns profile of ${data.length} bytes.`);
30841
+ const table = /* @__PURE__ */ new Map();
30842
+ for (let i = 0; i < count; i++) {
30843
+ const rec = TAG_TABLE_OFFSET + i * TAG_RECORD_SIZE;
30844
+ const sig = readSig(data, rec);
30845
+ const offset = view.getUint32(rec + 4, false);
30846
+ const size = view.getUint32(rec + 8, false);
30847
+ table.set(sig, {
30848
+ offset,
30849
+ size
30850
+ });
30851
+ }
30852
+ return table;
30853
+ }
30854
+ /**
30855
+ * Parse the matrix/TRC-relevant header fields and detect whether the profile
30856
+ * carries a complete matrix/TRC model.
30857
+ *
30858
+ * Reads the 128-byte ICC header (ICC.1:2010 §7.2): version (offset 8),
30859
+ * deviceClass (offset 12), data colour space (offset 16) and PCS (offset 20),
30860
+ * then inspects the tag table (§7.3) for the colorant + TRC tags.
30861
+ *
30862
+ * @param profile - Raw ICC profile bytes.
30863
+ * @returns Parsed {@link IccTransformInfo}.
30864
+ * @throws if the profile is too short to contain a header and tag table.
30865
+ *
30866
+ * @example
30867
+ * ```ts
30868
+ * import { parseIccTransform } from 'modern-pdf-lib';
30869
+ *
30870
+ * const info = parseIccTransform(profileBytes);
30871
+ * if (info.hasMatrixTrc && info.colorSpace === 'RGB ') {
30872
+ * // safe to call deviceRgbToXyz
30873
+ * }
30874
+ * ```
30875
+ */
30876
+ function parseIccTransform(profile) {
30877
+ if (profile.length < HEADER_SIZE) throw new Error(`ICC profile too short: ${profile.length} bytes (need at least ${HEADER_SIZE}).`);
30878
+ const version = new DataView(profile.buffer, profile.byteOffset, profile.byteLength).getUint32(8, false);
30879
+ const deviceClass = readSig(profile, 12);
30880
+ const colorSpace = readSig(profile, 16);
30881
+ const pcs = readSig(profile, 20);
30882
+ const table = readTagTable(profile);
30883
+ let hasMatrixTrc;
30884
+ if (colorSpace === "GRAY") hasMatrixTrc = table.has("kTRC");
30885
+ else hasMatrixTrc = table.has("rXYZ") && table.has("gXYZ") && table.has("bXYZ") && table.has("rTRC") && table.has("gTRC") && table.has("bTRC");
30886
+ return {
30887
+ version,
30888
+ deviceClass,
30889
+ colorSpace,
30890
+ pcs,
30891
+ hasMatrixTrc
30892
+ };
30893
+ }
30894
+ /**
30895
+ * Evaluate a TRC tag (`curv` or `para`) at a normalised input `x ∈ [0,1]`,
30896
+ * returning the linearised value in `[0,1]`.
30897
+ *
30898
+ * - `curv` (ICC.1:2010 §10.6): `count` u16 follows the 8-byte type header.
30899
+ * `count == 0` → identity; `count == 1` → a single u8Fixed8Number gamma
30900
+ * (Y = X^g); `count >= 2` → a uInt16 sampled curve over the input domain
30901
+ * [0,1], linearly interpolated, output normalised by 65535.
30902
+ * - `para` (ICC.1:2010 §10.18): a u16 function type + s15Fixed16 parameters.
30903
+ * Implements function types 0–4 from the spec.
30904
+ *
30905
+ * @throws if the tag type is neither `curv` nor `para`, or is truncated.
30906
+ */
30907
+ function evalTrc(data, tag, x) {
30908
+ const start = tag.offset;
30909
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
30910
+ const type = readSig(data, start);
30911
+ const xi = x < 0 ? 0 : x > 1 ? 1 : x;
30912
+ if (type === "curv") {
30913
+ const count = view.getUint32(start + 8, false);
30914
+ if (count === 0) return xi;
30915
+ if (count === 1) return xi ** (view.getUint16(start + 12, false) / 256);
30916
+ const lutStart = start + 12;
30917
+ const pos = xi * (count - 1);
30918
+ const i0 = Math.floor(pos);
30919
+ const i1 = i0 >= count - 1 ? count - 1 : i0 + 1;
30920
+ const frac = pos - i0;
30921
+ const v0 = view.getUint16(lutStart + i0 * 2, false);
30922
+ return (v0 + (view.getUint16(lutStart + i1 * 2, false) - v0) * frac) / 65535;
30923
+ }
30924
+ if (type === "para") {
30925
+ const funcType = view.getUint16(start + 8, false);
30926
+ const p = (i) => readS15Fixed16(view, start + 12 + i * 4);
30927
+ const g = p(0);
30928
+ switch (funcType) {
30929
+ case 0: return xi ** g;
30930
+ case 1: {
30931
+ const a = p(1);
30932
+ const b = p(2);
30933
+ return a * xi + b >= 0 ? (a * xi + b) ** g : 0;
30934
+ }
30935
+ case 2: {
30936
+ const a = p(1);
30937
+ const b = p(2);
30938
+ const c = p(3);
30939
+ return (a * xi + b >= 0 ? (a * xi + b) ** g : 0) + c;
30940
+ }
30941
+ case 3: {
30942
+ const a = p(1);
30943
+ const b = p(2);
30944
+ const c = p(3);
30945
+ return xi >= p(4) ? (a * xi + b) ** g : c * xi;
30946
+ }
30947
+ case 4: {
30948
+ const a = p(1);
30949
+ const b = p(2);
30950
+ const c = p(3);
30951
+ const d = p(4);
30952
+ const e = p(5);
30953
+ const f = p(6);
30954
+ return xi >= d ? (a * xi + b) ** g + e : c * xi + f;
30955
+ }
30956
+ default: throw new Error(`Unsupported parametricCurveType function type ${funcType} (ICC.1:2010 §10.18 defines 0–4).`);
30957
+ }
30958
+ }
30959
+ throw new Error(`Unsupported TRC tag type '${type}': only 'curv' and 'para' are matrix/TRC curves (got a LUT/other type).`);
30960
+ }
30961
+ /** Read a 3-component colorant XYZ from an 'XYZ ' tag. */
30962
+ function readXyzTag(data, tag) {
30963
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
30964
+ const type = readSig(data, tag.offset);
30965
+ if (type !== "XYZ ") throw new Error(`Expected an 'XYZ ' colorant tag but found '${type}' (ICC.1:2010 §10.31).`);
30966
+ return [
30967
+ readS15Fixed16(view, tag.offset + 8),
30968
+ readS15Fixed16(view, tag.offset + 12),
30969
+ readS15Fixed16(view, tag.offset + 16)
30970
+ ];
30971
+ }
30972
+ /**
30973
+ * Transform a device colour through a **matrix/TRC** ICC profile into the
30974
+ * D50-relative PCS XYZ.
30975
+ *
30976
+ * For RGB (`colorSpace === 'RGB '`): each channel is linearised through its
30977
+ * `rTRC`/`gTRC`/`bTRC` curve, then multiplied by the colorant matrix whose
30978
+ * columns are the `rXYZ`/`gXYZ`/`bXYZ` tags (ICC.1:2010 §E.1.1).
30979
+ *
30980
+ * For GRAY (`colorSpace === 'GRAY'`): the single value is linearised through
30981
+ * `kTRC` and scaled by the media white point (`wtpt`, defaulting to D50).
30982
+ *
30983
+ * The result is **D50-relative XYZ**, matching the ICC PCS reference
30984
+ * illuminant; feed it directly to {@link xyzToLab} (whose default white point
30985
+ * is D50).
30986
+ *
30987
+ * @param profile - Raw ICC profile bytes.
30988
+ * @param rgb - Device colour in `[0,1]`. For gray profiles only the first
30989
+ * component is used.
30990
+ * @returns PCS XYZ `[X, Y, Z]`, D50-relative.
30991
+ * @throws if the profile is **not** matrix/TRC (i.e. it is LUT-based —
30992
+ * `mft1`/`mft2`/`mAB `/`mBA `), or its colour space is unsupported.
30993
+ *
30994
+ * @example
30995
+ * ```ts
30996
+ * import { deviceRgbToXyz } from 'modern-pdf-lib';
30997
+ *
30998
+ * const xyz = deviceRgbToXyz(srgbProfileBytes, [1, 1, 1]);
30999
+ * // ~ [0.9642, 1.0, 0.8249] (D50 white)
31000
+ * ```
31001
+ */
31002
+ function deviceRgbToXyz(profile, rgb) {
31003
+ const info = parseIccTransform(profile);
31004
+ const table = readTagTable(profile);
31005
+ if (info.colorSpace === "GRAY") {
31006
+ const kTrc = table.get("kTRC");
31007
+ if (!kTrc) throw new Error("Gray ICC profile lacks a 'kTRC' tag; not a matrix/TRC profile.");
31008
+ const lin = evalTrc(profile, kTrc, rgb[0]);
31009
+ const wtptRec = table.get("wtpt");
31010
+ const white = wtptRec ? readXyzTag(profile, wtptRec) : [
31011
+ D50_WHITE[0],
31012
+ D50_WHITE[1],
31013
+ D50_WHITE[2]
31014
+ ];
31015
+ return [
31016
+ lin * white[0],
31017
+ lin * white[1],
31018
+ lin * white[2]
31019
+ ];
31020
+ }
31021
+ if (info.colorSpace !== "RGB ") throw new Error(`deviceRgbToXyz supports 'RGB ' and 'GRAY' profiles; got '${info.colorSpace}'.`);
31022
+ if (!info.hasMatrixTrc) throw new Error("ICC profile is not matrix/TRC (LUT-based: mft1/mft2/mAB /mBA ); matrix/TRC transform cannot be applied. Use a CMM/LUT evaluator instead.");
31023
+ const rTrc = table.get("rTRC");
31024
+ const gTrc = table.get("gTRC");
31025
+ const bTrc = table.get("bTRC");
31026
+ const rLin = evalTrc(profile, rTrc, rgb[0]);
31027
+ const gLin = evalTrc(profile, gTrc, rgb[1]);
31028
+ const bLin = evalTrc(profile, bTrc, rgb[2]);
31029
+ const rCol = readXyzTag(profile, table.get("rXYZ"));
31030
+ const gCol = readXyzTag(profile, table.get("gXYZ"));
31031
+ const bCol = readXyzTag(profile, table.get("bXYZ"));
31032
+ return [
31033
+ rCol[0] * rLin + gCol[0] * gLin + bCol[0] * bLin,
31034
+ rCol[1] * rLin + gCol[1] * gLin + bCol[1] * bLin,
31035
+ rCol[2] * rLin + gCol[2] * gLin + bCol[2] * bLin
31036
+ ];
31037
+ }
31038
+ /**
31039
+ * CIE L\*a\*b\* nonlinearity f(t) (CIE 15:2004 §8.2.1.1):
31040
+ *
31041
+ * ```
31042
+ * f(t) = t^(1/3) for t > δ³
31043
+ * f(t) = t / (3·δ²) + 4/29 for t <= δ³, δ = 6/29
31044
+ * ```
31045
+ */
31046
+ function labF$1(t) {
31047
+ return t > LAB_DELTA_CUBED$1 ? Math.cbrt(t) : t * LAB_LINEAR_SLOPE + LAB_LINEAR_INTERCEPT;
31048
+ }
31049
+ /**
31050
+ * Convert PCS XYZ to CIE L\*a\*b\* (CIE 15:2004 §8.2.1 / ICC PCS):
31051
+ *
31052
+ * ```
31053
+ * L* = 116·f(Y/Yn) − 16
31054
+ * a* = 500·(f(X/Xn) − f(Y/Yn))
31055
+ * b* = 200·(f(Y/Yn) − f(Z/Zn))
31056
+ * ```
31057
+ *
31058
+ * with f as in {@link labF}. The default reference white is **D50**
31059
+ * `[0.9642, 1.0000, 0.8249]`, matching the ICC PCS (ICC.1:2010 §6.3.4.3), so
31060
+ * XYZ produced by {@link deviceRgbToXyz} maps straight through.
31061
+ *
31062
+ * @param xyz - XYZ tristimulus, relative to `whitePoint`.
31063
+ * @param whitePoint - Reference white `[Xn, Yn, Zn]`. Defaults to D50.
31064
+ * @returns `[L*, a*, b*]`.
31065
+ *
31066
+ * @example
31067
+ * ```ts
31068
+ * import { xyzToLab } from 'modern-pdf-lib';
31069
+ *
31070
+ * xyzToLab([0.9642, 1.0, 0.8249]); // ~ [100, 0, 0] (D50 white)
31071
+ * ```
31072
+ */
31073
+ function xyzToLab(xyz, whitePoint = [
31074
+ D50_WHITE[0],
31075
+ D50_WHITE[1],
31076
+ D50_WHITE[2]
31077
+ ]) {
31078
+ const fx = labF$1(xyz[0] / whitePoint[0]);
31079
+ const fy = labF$1(xyz[1] / whitePoint[1]);
31080
+ const fz = labF$1(xyz[2] / whitePoint[2]);
31081
+ return [
31082
+ 116 * fy - 16,
31083
+ 500 * (fx - fy),
31084
+ 200 * (fy - fz)
31085
+ ];
31086
+ }
31087
+ //#endregion
31088
+ //#region src/color/colorConvert.ts
31089
+ /**
31090
+ * @module color/colorConvert
31091
+ *
31092
+ * Pure **device** colour-space conversions — no ICC, no chromatic adaptation
31093
+ * beyond what each standard formula already bakes in. These are the textbook
31094
+ * conversions used for previewing, picking and authoring colour; they are not
31095
+ * a substitute for ICC-based colour management.
31096
+ *
31097
+ * All channels are normalised to `0..1`, with two exceptions that follow the
31098
+ * natural ranges of their spaces:
31099
+ * - **Hue** is in degrees `[0, 360)`.
31100
+ * - **CIE L\*a\*b\*** uses its native ranges: `L ∈ [0, 100]`, `a`/`b`
31101
+ * unbounded (typically `[-128, 127]`).
31102
+ *
31103
+ * ## Verified reference constants
31104
+ *
31105
+ * **sRGB transfer function** — IEC 61966-2-1:1999 (sRGB). The companded↔linear
31106
+ * piecewise curve:
31107
+ * - expand (companded→linear): `c ≤ 0.04045 → c/12.92`,
31108
+ * else `((c + 0.055)/1.055)^2.4`.
31109
+ * - compress (linear→companded): `c ≤ 0.0031308 → 12.92·c`,
31110
+ * else `1.055·c^(1/2.4) − 0.055`.
31111
+ *
31112
+ * **sRGB ↔ XYZ (D65) matrices** — IEC 61966-2-1, as tabulated by Bruce
31113
+ * Lindbloom (sRGB, reference white D65). Forward (linear sRGB → XYZ):
31114
+ * ```
31115
+ * X = 0.4124564 R + 0.3575761 G + 0.1804375 B
31116
+ * Y = 0.2126729 R + 0.7151522 G + 0.0721750 B
31117
+ * Z = 0.0193339 R + 0.1191920 G + 0.9503041 B
31118
+ * ```
31119
+ * Inverse (XYZ → linear sRGB):
31120
+ * ```
31121
+ * R = 3.2404542 X − 1.5371385 Y − 0.4985314 Z
31122
+ * G = −0.9692660 X + 1.8760108 Y + 0.0415560 Z
31123
+ * B = 0.0556434 X − 0.2040259 Y + 1.0572252 Z
31124
+ * ```
31125
+ *
31126
+ * **D65 reference white** — CIE 1931 2° observer, normalised to `Y = 1`:
31127
+ * `Xn = 0.95047, Yn = 1.00000, Zn = 1.08883`.
31128
+ *
31129
+ * **CIE L\*a\*b\*** — CIE 15 colorimetry, using the rational `δ = 6/29`
31130
+ * formulation (numerically identical to the `0.008856 / 903.3` form but
31131
+ * continuous at the join):
31132
+ * ```
31133
+ * f(t) = t^(1/3) if t > δ³
31134
+ * = t/(3δ²) + 4/29 otherwise
31135
+ * L = 116·f(Y/Yn) − 16
31136
+ * a = 500·(f(X/Xn) − f(Y/Yn))
31137
+ * b = 200·(f(Y/Yn) − f(Z/Zn))
31138
+ * ```
31139
+ * with the inverse `f⁻¹(t) = t³` if `t > δ` else `3δ²·(t − 4/29)`.
31140
+ *
31141
+ * > **Note on Lab white point.** This module's `rgbToLab` / `labToRgb` use the
31142
+ * > **D65** PCS that matches the sRGB→XYZ pipeline, per this module's spec.
31143
+ * > That differs from {@link module:core/colorSpacesCIE}'s `labToRgb`, which
31144
+ * > targets the **D50** ICC profile-connection-space convention. The two are
31145
+ * > intentionally distinct and should not be confused.
31146
+ *
31147
+ * No `Buffer` — plain `number` arithmetic and tuples only.
31148
+ */
31149
+ /**
31150
+ * CIE 1931 2° D65 reference white, normalised so `Yn = 1`.
31151
+ * (IEC 61966-2-1 / CIE 15.)
31152
+ */
31153
+ const D65_WHITE = [
31154
+ .95047,
31155
+ 1,
31156
+ 1.08883
31157
+ ];
31158
+ /** CIE Lab constant `δ = 6/29`. */
31159
+ const LAB_DELTA = 6 / 29;
31160
+ /** `δ³` — the linear/cubic break point for the forward nonlinearity `f(t)`. */
31161
+ const LAB_DELTA_CUBED = LAB_DELTA * LAB_DELTA * LAB_DELTA;
31162
+ /** `3δ²` — slope of the linear branch. */
31163
+ const LAB_3_DELTA_SQUARED = 3 * LAB_DELTA * LAB_DELTA;
31164
+ /** Clamp `x` to the closed interval `[lo, hi]`. */
31165
+ function clamp(x, lo, hi) {
31166
+ return x < lo ? lo : x > hi ? hi : x;
31167
+ }
31168
+ /** Normalise a hue in degrees into `[0, 360)`. */
31169
+ function normalizeHue(h) {
31170
+ const m = h % 360;
31171
+ return m < 0 ? m + 360 : m;
31172
+ }
31173
+ /**
31174
+ * Convert device RGB to HSL.
31175
+ *
31176
+ * @param r - Red, 0..1.
31177
+ * @param g - Green, 0..1.
31178
+ * @param b - Blue, 0..1.
31179
+ * @returns `[h, s, l]` with `h` in `[0, 360)`, `s`/`l` in `0..1`.
31180
+ */
31181
+ function rgbToHsl(r, g, b) {
31182
+ const max = Math.max(r, g, b);
31183
+ const min = Math.min(r, g, b);
31184
+ const delta = max - min;
31185
+ const l = (max + min) / 2;
31186
+ if (delta === 0) return [
31187
+ 0,
31188
+ 0,
31189
+ l
31190
+ ];
31191
+ const s = delta / (1 - Math.abs(2 * l - 1));
31192
+ let h;
31193
+ if (max === r) h = (g - b) / delta % 6;
31194
+ else if (max === g) h = (b - r) / delta + 2;
31195
+ else h = (r - g) / delta + 4;
31196
+ h *= 60;
31197
+ return [
31198
+ normalizeHue(h),
31199
+ s,
31200
+ l
31201
+ ];
31202
+ }
31203
+ /**
31204
+ * Convert HSL to device RGB.
31205
+ *
31206
+ * @param h - Hue in degrees (any real; wrapped into `[0, 360)`).
31207
+ * @param s - Saturation, 0..1.
31208
+ * @param l - Lightness, 0..1.
31209
+ * @returns `[r, g, b]`, each 0..1.
31210
+ */
31211
+ function hslToRgb(h, s, l) {
31212
+ const hue = normalizeHue(h);
31213
+ const c = (1 - Math.abs(2 * l - 1)) * s;
31214
+ const x = c * (1 - Math.abs(hue / 60 % 2 - 1));
31215
+ const mAdd = l - c / 2;
31216
+ let r1 = 0;
31217
+ let g1 = 0;
31218
+ let b1 = 0;
31219
+ if (hue < 60) {
31220
+ r1 = c;
31221
+ g1 = x;
31222
+ } else if (hue < 120) {
31223
+ r1 = x;
31224
+ g1 = c;
31225
+ } else if (hue < 180) {
31226
+ g1 = c;
31227
+ b1 = x;
31228
+ } else if (hue < 240) {
31229
+ g1 = x;
31230
+ b1 = c;
31231
+ } else if (hue < 300) {
31232
+ r1 = x;
31233
+ b1 = c;
31234
+ } else {
31235
+ r1 = c;
31236
+ b1 = x;
31237
+ }
31238
+ return [
31239
+ r1 + mAdd,
31240
+ g1 + mAdd,
31241
+ b1 + mAdd
31242
+ ];
31243
+ }
31244
+ /**
31245
+ * Convert device RGB to HSV.
31246
+ *
31247
+ * @param r - Red, 0..1.
31248
+ * @param g - Green, 0..1.
31249
+ * @param b - Blue, 0..1.
31250
+ * @returns `[h, s, v]` with `h` in `[0, 360)`, `s`/`v` in `0..1`.
31251
+ */
31252
+ function rgbToHsv(r, g, b) {
31253
+ const max = Math.max(r, g, b);
31254
+ const delta = max - Math.min(r, g, b);
31255
+ const v = max;
31256
+ if (delta === 0) return [
31257
+ 0,
31258
+ 0,
31259
+ v
31260
+ ];
31261
+ const s = max === 0 ? 0 : delta / max;
31262
+ let h;
31263
+ if (max === r) h = (g - b) / delta % 6;
31264
+ else if (max === g) h = (b - r) / delta + 2;
31265
+ else h = (r - g) / delta + 4;
31266
+ h *= 60;
31267
+ return [
31268
+ normalizeHue(h),
31269
+ s,
31270
+ v
31271
+ ];
31272
+ }
31273
+ /**
31274
+ * Convert HSV to device RGB.
31275
+ *
31276
+ * @param h - Hue in degrees (any real; wrapped into `[0, 360)`).
31277
+ * @param s - Saturation, 0..1.
31278
+ * @param v - Value, 0..1.
31279
+ * @returns `[r, g, b]`, each 0..1.
31280
+ */
31281
+ function hsvToRgb(h, s, v) {
31282
+ const hue = normalizeHue(h);
31283
+ const c = v * s;
31284
+ const x = c * (1 - Math.abs(hue / 60 % 2 - 1));
31285
+ const mAdd = v - c;
31286
+ let r1 = 0;
31287
+ let g1 = 0;
31288
+ let b1 = 0;
31289
+ if (hue < 60) {
31290
+ r1 = c;
31291
+ g1 = x;
31292
+ } else if (hue < 120) {
31293
+ r1 = x;
31294
+ g1 = c;
31295
+ } else if (hue < 180) {
31296
+ g1 = c;
31297
+ b1 = x;
31298
+ } else if (hue < 240) {
31299
+ g1 = x;
31300
+ b1 = c;
31301
+ } else if (hue < 300) {
31302
+ r1 = x;
31303
+ b1 = c;
31304
+ } else {
31305
+ r1 = c;
31306
+ b1 = x;
31307
+ }
31308
+ return [
31309
+ r1 + mAdd,
31310
+ g1 + mAdd,
31311
+ b1 + mAdd
31312
+ ];
31313
+ }
31314
+ /** Gamma-expand a companded sRGB channel to linear (IEC 61966-2-1). */
31315
+ function srgbToLinear(c) {
31316
+ return c <= .04045 ? c / 12.92 : ((c + .055) / 1.055) ** 2.4;
31317
+ }
31318
+ /** Gamma-compress a linear channel to companded sRGB (IEC 61966-2-1). */
31319
+ function linearToSrgb(c) {
31320
+ return c <= .0031308 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - .055;
31321
+ }
31322
+ /**
31323
+ * Convert device (sRGB) RGB to CIE XYZ relative to the D65 white point.
31324
+ *
31325
+ * Gamma-expands each channel, then applies the IEC 61966-2-1 sRGB→XYZ D65
31326
+ * matrix. The returned `Y` is `1.0` for input white `(1, 1, 1)`.
31327
+ *
31328
+ * @param r - Red, 0..1.
31329
+ * @param g - Green, 0..1.
31330
+ * @param b - Blue, 0..1.
31331
+ * @returns `[X, Y, Z]` (D65, `Y = 1` for white).
31332
+ */
31333
+ function rgbToXyz(r, g, b) {
31334
+ const rl = srgbToLinear(r);
31335
+ const gl = srgbToLinear(g);
31336
+ const bl = srgbToLinear(b);
31337
+ return [
31338
+ .4124564 * rl + .3575761 * gl + .1804375 * bl,
31339
+ .2126729 * rl + .7151522 * gl + .072175 * bl,
31340
+ .0193339 * rl + .119192 * gl + .9503041 * bl
31341
+ ];
31342
+ }
31343
+ /**
31344
+ * Convert CIE XYZ (D65) to device (sRGB) RGB.
31345
+ *
31346
+ * Applies the inverse sRGB matrix, then gamma-companding. Results are clamped
31347
+ * to `0..1` to keep them in the displayable device gamut.
31348
+ *
31349
+ * @param x - CIE X (D65).
31350
+ * @param y - CIE Y (D65).
31351
+ * @param z - CIE Z (D65).
31352
+ * @returns `[r, g, b]`, each clamped to 0..1.
31353
+ */
31354
+ function xyzToRgb(x, y, z) {
31355
+ const rl = 3.2404542 * x - 1.5371385 * y - .4985314 * z;
31356
+ const gl = -.969266 * x + 1.8760108 * y + .041556 * z;
31357
+ const bl = .0556434 * x - .2040259 * y + 1.0572252 * z;
31358
+ return [
31359
+ clamp(linearToSrgb(rl), 0, 1),
31360
+ clamp(linearToSrgb(gl), 0, 1),
31361
+ clamp(linearToSrgb(bl), 0, 1)
31362
+ ];
31363
+ }
31364
+ /** Forward CIE Lab nonlinearity `f(t)`. */
31365
+ function labF(t) {
31366
+ return t > LAB_DELTA_CUBED ? Math.cbrt(t) : t / LAB_3_DELTA_SQUARED + 4 / 29;
31367
+ }
31368
+ /**
31369
+ * Convert device (sRGB) RGB to CIE L\*a\*b\* via XYZ, using the D65 white
31370
+ * point.
31371
+ *
31372
+ * @param r - Red, 0..1.
31373
+ * @param g - Green, 0..1.
31374
+ * @param b - Blue, 0..1.
31375
+ * @returns `[L, a, b]` with `L ∈ [0, 100]`, `a`/`b` in their natural ranges.
31376
+ */
31377
+ function rgbToLab(r, g, b) {
31378
+ const [x, y, z] = rgbToXyz(r, g, b);
31379
+ const fx = labF(x / D65_WHITE[0]);
31380
+ const fy = labF(y / D65_WHITE[1]);
31381
+ const fz = labF(z / D65_WHITE[2]);
31382
+ return [
31383
+ 116 * fy - 16,
31384
+ 500 * (fx - fy),
31385
+ 200 * (fy - fz)
31386
+ ];
31387
+ }
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
30530
32170
  //#region src/render/matrix.ts
30531
32171
  /** The identity transform. */
30532
32172
  function identity() {
@@ -34354,6 +35994,6 @@ async function initWasm(options) {
34354
35994
  wasmInitialized = true;
34355
35995
  }
34356
35996
  //#endregion
34357
- export { getColorGlyphLayers as $, requestTimestamp as $a, applyRedaction as $i, PDF2_NAMESPACE as $n, shrinkFontSize as $r, parseAcrobatDate as $t, buildSoftMaskNone as A, optimizeIncrementalSave as Aa, computeCode39CheckDigit as Ai, STANDARD_SPOT_FUNCTIONS as An, parseXmpMetadata$1 as Ao, FieldAlreadyExistsError as Ar, summarizeBitDepth as At, redactRegions as B, detectModifications as Ba, recompressWebP as Bi, reconstructLines as Bn, RemovePageFromEmptyDocumentError as Br, isCertificateRevoked as Bt, tagTableHeaderCell as C, validatePdfA as Ca, ean13ToOperators as Ci, levenshtein as Cn, generateSquigglyAppearance as Co, flattenField as Cr, buildPdfXOutputIntent as Ct, buildImageSoftMask as D, linearizePdf as Da, encodeItf as Di, buildGtsPdfxVersion as Dn, PdfTextAnnotation as Do, CombedTextLayoutError as Dr, getComponentDepths as Dt, buildColorKeyMask as E, isLinearized as Ea, encodeEan8 as Ei, buildBoxDict as En, PdfLinkAnnotation as Eo, BatchProcessingError as Er, downscale16To8 as Et, attachAssociatedFiles as F, getCounterSignatures as Fa, valuesToModules as Fi, identityTransferFunction as Fn, saveDocumentIncremental as Fo, InvalidFieldNamePartError as Fr, parseTileInfo as Ft, extractImages as G, validateSignatureChain as Ga, isCmykTiff as Gi, buildCalRGB as Gn, applyHeaderFooterToPage as Gr, resolveFieldReference as Gt, compareImages as H, buildDocMdpReference as Ha, webpToPng as Hi, DEFAULT_DOC_TIMESTAMP_CONTENTS_SIZE as Hn, StreamingParseError as Hr, extractOcspUrl as Ht, registerEmbeddedFile as I, diffSignedContent as Ia, PdfWorker as Ii, nameHalftone as In, saveIncremental as Io, InvalidPageSizeError as Ir, verifySignatureDetailed as It, renderPageToCanvas as J, parseExistingTrailer as Ja, analyzeJpegMarkers as Ji, DEFAULT_SARIF_TOOL_NAME as Jn, toAlpha as Jr, setFieldVisibility as Jt, generateThumbnail as K, appendIncrementalUpdate as Ka, extractJpegMetadata as Ki, buildLab as Kn, formatDate$1 as Kr, setFieldValue as Kt, RenderCache as L, addFieldLock as La, canDirectEmbed as Li, evaluateFunction as Ln, MissingOnValueCheckError as Lr, TrustStore as Lt, buildUnencryptedWrapper as M, embedLtvData as Ma, code128ToOperators as Mi, buildThresholdHalftone as Mn, buildDeviceNColorSpace as Mo, FontNotEmbeddedError as Mr, assembleTiles as Mt, attachOutputIntents as N, hasLtvData as Na, encodeCode128 as Ni, buildType1Halftone as Nn, buildSeparationColorSpace as No, ForeignPageError as Nr, decodeTile as Nt, buildStencilMask as O, computeObjectHash as Oa, itfToOperators as Oi, buildPdfX6OutputIntent as On, buildXmpMetadata as Oo, EncryptedPdfError as Or, normalizeComponentDepth as Ot, buildPageOutputIntent as P, addCounterSignature as Pa, encodeCode128Values as Pi, buildType5Halftone as Pn, ChangeTracker as Po, InvalidColorError as Pr, decodeTileRegion as Pt, interpretPage as Q, parseTimestampResponse as Qa, recompressImage as Qi, MATHML_NAMESPACE as Qn, estimateTextWidth as Qr, formatDate as Qt, computeTileGrid as R, buildFieldLockDict as Ra, embedTiffDirect as Ri, markdownToPdf as Rn, NoSuchFieldError as Rr, downloadCrl as Rt, tagTableDataCell as S, enforcePdfA as Sa, calculateEanCheckDigit as Si, didYouMean as Sn, generateSquareAppearance as So, removeBookmark as Sr, layoutTextFlow as St, buildBlackPointCompensationExtGState as T, getLinearizationInfo as Ta, encodeEan13 as Ti, generateCiiXml as Tn, generateUnderlineAppearance as To, flattenForm as Tr, validatePdfX as Tt, comparePages as U, getCertificationLevel as Ua, convertTiffCmykToRgb as Ui, buildDocTimeStampDict as Un, UnexpectedFieldTypeError as Ur, createSandbox as Ut, applyOcr as V, MdpPermission as Va, webpToJpeg as Vi, reconstructParagraphs as Vn, RichTextFieldReadError as Vr, checkCertificateStatus as Vt, extractFonts as W, setCertificationLevel as Wa, embedTiffCmyk as Wi, buildCalGray as Wn, applyHeaderFooter as Wr, getFieldValue as Wt, renderPageToImage as X, validateByteRangeIntegrity as Xa, estimateJpegQuality as Xi, toJsonReport as Xn, applyOverflow as Xr, AFSpecial_Format as Xt, rasterize as Y, saveIncrementalWithSignaturePreservation as Ya, downscaleImage as Yi, SARIF_SCHEMA_URI as Yn, toRoman as Yr, validateFieldValue as Yt, interpretContentStream as Z, buildTimestampRequest as Za, optimizeImage as Zi, toSarif as Zn, ellipsisText as Zr, AFDate_FormatEx as Zt, tagLink as _, buildOutputIntent as _a, dataMatrixToOperators as _i, generateXRechnungCii as _n, generateCircleAppearance as _o, batchMerge as _r, buildCertificateChain as _t, assembleFacturX as a, buildAfArray as aa, minimalPreset as ai, readWoffHeader as an, PdfInkAnnotation as ao, buildDPartRoot as ar, resolveBidi as at, tagParagraph as b, detectTransparency as ba, encodeUpcA as bi, buildFunctionShading as bn, generateInkAppearance as bo, getBookmarks as br, layoutColumns as bt, buildWtpdfIdentificationXmp as c, parseXmpMetadata as ca, readBarcode as ci, buildPdfVtDParts as cn, PdfLineAnnotation as co, tableToJson as cr, sanitizePdf as ct, autoTagPage as d, getSupportedLevels as da, readEan13 as di, h as dn, PdfSquareAnnotation as do, timestampPlugin as dr, extractEmbeddedRevocationData as dt, enforcePdfAFull as ea, truncateText as ei, AFNumber_Format as en, searchTextItems as eo, buildNamespace as er, parseColorFont as et, buildPdfUa2Xmp as f, isValidLevel as fa, readEan8 as fi, renderToPdf as fn, PdfHighlightAnnotation as fo, StreamingPdfParser as fr, verifyOfflineRevocation as ft, tagHeading as g, getToUnicodeCmap as ga, pdf417ToOperators as gi, generateOrderX as gn, PdfFreeTextAnnotation as go, batchFlatten as gr, validateKeyUsage as gt, tagFigure as h, generateZapfDingbatsToUnicodeCmap as ha, encodePdf417 as hi, splitByScript as hn, PdfUnderlineAnnotation as ho, validatePdfUa as hr, validateExtendedKeyUsage as ht, validateEn16931 as i, stripProhibitedFeatures as ia, borderedPreset as ii, isWoff2 as in, PdfRedactAnnotation as io, buildRequirements as ir, reorderVisual as it, buildEncryptedPayload as j, buildDssDictionary as ja, encodeCode39 as ji, buildSampledTransferFunction as jn, PDFOperator as jo, FieldExistsAsNonTerminalError as jr, upscale8To16 as jt, buildSoftMaskGroupExtGState as k, findChangedObjects as ka, code39ToOperators as ki, validateBoxGeometry as kn, createXmpStream as ko, ExceededMaxLengthError as kr, offsetSignedToUnsigned as kt, convertPdfAConformanceXmp as l, validateXmpMetadata as la, readCode128 as li, buildVtDpm as ln, PdfPolyLineAnnotation as lo, accessibilityPlugin as lr, scanPdfThreats as lt, LIST_NUMBERING_KEY as m, generateWinAnsiToUnicodeCmap as ma, renderStyledBarcode as mi, resolveFallback as mn, PdfStrikeOutAnnotation as mo, enforcePdfUa as mr, validateCertificatePolicy as mt, detectFacturXProfile as n, generatePdfAXmpBytes as na, applyPreset as ni, decodeWoff as nn, PdfCaretAnnotation as no, buildPieceInfo as nr, parseVariableFont as nt, buildFacturXXmp as o, createAssociatedFile as oa, professionalPreset as oi, signDeferred as on, PdfStampAnnotation as oo, extractTables as or, inspectEncryption as ot, validatePdfUa2 as p, generateSymbolToUnicodeCmap as pa, calculateBarcodeDimensions as pi, createRangeFetcher as pn, PdfSquigglyAnnotation as po, PdfDocumentBuilder as pr, EKU_OIDS as pt, renderDisplayListToCanvas as q, findExistingSignatures as qa, injectJpegMetadata as qi, labToRgb as qn, replaceTemplateVariables as qr, addVisibilityAction as qt, parseCiiXml as r, countOccurrences as ra, applyTablePreset as ri, isWoff as rn, PdfPopupAnnotation as ro, buildRequirement as rr, resolveInstanceCoordinates as rt, buildPdfRIdentificationXmp as s, extractXmpMetadata as sa, stripedPreset as si, createWorkerPool as sn, PdfCircleAnnotation as so, tableToCsv as sr, verifyRedactions as st, initWasm as t, generatePdfAXmp as ta, wrapText$2 as ti, formatNumber$1 as tn, PdfFileAttachmentAnnotation as to, buildNamespacesArray as tr, normalizeAxisCoordinate as tt, preflightPdfA as u, getProfile as ua, readCode39 as ui, gtsPdfVtVersion as un, PdfPolygonAnnotation as uo, metadataPlugin as ur, buildCertPath as ut, tagList as v, SRGB_ICC_PROFILE as va, encodeDataMatrix as vi, buildPdfA4Xmp as vn, generateFreeTextAppearance as vo, processBatch as vr, validateCertificateChain as vt, tagTableRow as w, delinearizePdf as wa, ean8ToOperators as wi, renderCodeFrame as wn, generateStrikeOutAppearance as wo, flattenFields as wr, enforcePdfX as wt, tagTable as x, flattenTransparency as xa, upcAToOperators as xi, sampleShadingColor as xn, generateLineAppearance as xo, removeAllBookmarks as xr, layoutParagraph as xt, tagListItem as y, generateSrgbIccProfile as ya, calculateUpcCheckDigit as yi, pdfA4Rules as yn, generateHighlightAppearance as yo, addBookmark as yr, findHyphenationPoints as yt, renderPageTile as z, getFieldLocks as za, encodePngFromPixels as zi, buildCollection as zn, PluginError as zr, extractCrlUrls as zt };
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 };
34358
35998
 
34359
- //# sourceMappingURL=src-4wfgzZvz.mjs.map
35999
+ //# sourceMappingURL=src-DlRTrvWg.mjs.map