modern-pdf-lib 0.12.1 → 0.14.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.
@@ -1,5 +1,5 @@
1
1
  const require_rolldown_runtime = require('./rolldown-runtime-CKhH4XqG.cjs');
2
- const require_pdfCatalog = require('./pdfCatalog-y_XG8Hq1.cjs');
2
+ const require_pdfCatalog = require('./pdfCatalog-COKoYQ8C.cjs');
3
3
 
4
4
  //#region src/core/operators/text.ts
5
5
  /**
@@ -1551,29 +1551,45 @@ const NAMED_COLORS = {
1551
1551
  *
1552
1552
  * @returns RGB values (0-255) or `undefined` if not parseable.
1553
1553
  */
1554
+ /** Cache for parsed SVG colors — high hit rate since SVGs reuse colors. */
1555
+ const colorCache = /* @__PURE__ */ new Map();
1554
1556
  function parseSvgColor(colorStr) {
1555
1557
  if (!colorStr) return void 0;
1558
+ const cached = colorCache.get(colorStr);
1559
+ if (cached !== void 0) return cached;
1560
+ if (colorCache.has(colorStr)) return void 0;
1556
1561
  const s = colorStr.trim().toLowerCase();
1557
- if (s === "none" || s === "transparent") return;
1562
+ if (s === "none" || s === "transparent") {
1563
+ colorCache.set(colorStr, void 0);
1564
+ return;
1565
+ }
1558
1566
  if (s.length === 7 && s[0] === "#") {
1559
1567
  const r = parseInt(s.slice(1, 3), 16);
1560
1568
  const g = parseInt(s.slice(3, 5), 16);
1561
1569
  const b = parseInt(s.slice(5, 7), 16);
1562
- if (!isNaN(r) && !isNaN(g) && !isNaN(b)) return {
1563
- r,
1564
- g,
1565
- b
1566
- };
1570
+ if (!isNaN(r) && !isNaN(g) && !isNaN(b)) {
1571
+ const result = {
1572
+ r,
1573
+ g,
1574
+ b
1575
+ };
1576
+ colorCache.set(colorStr, result);
1577
+ return result;
1578
+ }
1567
1579
  }
1568
1580
  if (s.length === 4 && s[0] === "#") {
1569
1581
  const r = parseInt(s[1] + s[1], 16);
1570
1582
  const g = parseInt(s[2] + s[2], 16);
1571
1583
  const b = parseInt(s[3] + s[3], 16);
1572
- if (!isNaN(r) && !isNaN(g) && !isNaN(b)) return {
1573
- r,
1574
- g,
1575
- b
1576
- };
1584
+ if (!isNaN(r) && !isNaN(g) && !isNaN(b)) {
1585
+ const result = {
1586
+ r,
1587
+ g,
1588
+ b
1589
+ };
1590
+ colorCache.set(colorStr, result);
1591
+ return result;
1592
+ }
1577
1593
  }
1578
1594
  const rgbaMatch = /^rgba?\(\s*([\d.]+)\s*[,\s]\s*([\d.]+)\s*[,\s]\s*([\d.]+)(?:\s*[,/\s]\s*([\d.]+))?\s*\)$/.exec(s);
1579
1595
  if (rgbaMatch) {
@@ -1581,19 +1597,26 @@ function parseSvgColor(colorStr) {
1581
1597
  const g = Math.round(parseFloat(rgbaMatch[2]));
1582
1598
  const b = Math.round(parseFloat(rgbaMatch[3]));
1583
1599
  const a = rgbaMatch[4] !== void 0 ? parseFloat(rgbaMatch[4]) : void 0;
1584
- return {
1600
+ const result = {
1585
1601
  r,
1586
1602
  g,
1587
1603
  b,
1588
1604
  ...a !== void 0 ? { a } : {}
1589
1605
  };
1606
+ colorCache.set(colorStr, result);
1607
+ return result;
1590
1608
  }
1591
1609
  const named = NAMED_COLORS[s];
1592
- if (named) return {
1593
- r: named[0],
1594
- g: named[1],
1595
- b: named[2]
1596
- };
1610
+ if (named) {
1611
+ const result = {
1612
+ r: named[0],
1613
+ g: named[1],
1614
+ b: named[2]
1615
+ };
1616
+ colorCache.set(colorStr, result);
1617
+ return result;
1618
+ }
1619
+ colorCache.set(colorStr, void 0);
1597
1620
  }
1598
1621
  /**
1599
1622
  * Parse an SVG `transform` attribute into a 2D affine matrix.
@@ -2705,6 +2728,162 @@ function drawSvgOnPage(page, svgString, options) {
2705
2728
  page.pushOperators(ops);
2706
2729
  }
2707
2730
 
2731
+ //#endregion
2732
+ //#region src/core/pdfPageSvg.ts
2733
+ /** Format a number for PDF output. */
2734
+ function fmtN(value) {
2735
+ if (Number.isInteger(value)) return value.toString();
2736
+ const s = value.toFixed(6).replace(/\.?0+$/, "");
2737
+ return s === "-0" ? "0" : s;
2738
+ }
2739
+ /** Magic constant for circular arc approximation: 4*(sqrt(2)-1)/3. */
2740
+ const KAPPA = .5522847498;
2741
+ /**
2742
+ * Approximate an SVG arc command as cubic Bezier curve(s) (PDF operators).
2743
+ *
2744
+ * SVG arcs use endpoint parameterization; PDF has no native arc command.
2745
+ */
2746
+ function svgArcToPdfOps(fromX, fromY, rx0, ry0, rotationDeg, largeArcFlag, sweepFlag, toX, toY) {
2747
+ let rx = Math.abs(rx0);
2748
+ let ry = Math.abs(ry0);
2749
+ if (rx === 0 || ry === 0) return `${fmtN(toX)} ${fmtN(toY)} l\n`;
2750
+ const phi = rotationDeg * Math.PI / 180;
2751
+ const cosPhi = Math.cos(phi);
2752
+ const sinPhi = Math.sin(phi);
2753
+ const dx2 = (fromX - toX) / 2;
2754
+ const dy2 = (fromY - toY) / 2;
2755
+ const x1p = cosPhi * dx2 + sinPhi * dy2;
2756
+ const y1p = -sinPhi * dx2 + cosPhi * dy2;
2757
+ let rxSq = rx * rx;
2758
+ let rySq = ry * ry;
2759
+ const x1pSq = x1p * x1p;
2760
+ const y1pSq = y1p * y1p;
2761
+ const lambda = x1pSq / rxSq + y1pSq / rySq;
2762
+ if (lambda > 1) {
2763
+ const s = Math.sqrt(lambda);
2764
+ rx *= s;
2765
+ ry *= s;
2766
+ rxSq = rx * rx;
2767
+ rySq = ry * ry;
2768
+ }
2769
+ let sq = (rxSq * rySq - rxSq * y1pSq - rySq * x1pSq) / (rxSq * y1pSq + rySq * x1pSq);
2770
+ if (sq < 0) sq = 0;
2771
+ sq = Math.sqrt(sq);
2772
+ if (largeArcFlag === sweepFlag) sq = -sq;
2773
+ const cxp = sq * rx * y1p / ry;
2774
+ const cyp = -sq * ry * x1p / rx;
2775
+ const cx = cosPhi * cxp - sinPhi * cyp + (fromX + toX) / 2;
2776
+ const cy = sinPhi * cxp + cosPhi * cyp + (fromY + toY) / 2;
2777
+ function vecAngle(ux, uy, vx, vy) {
2778
+ const sign = ux * vy - uy * vx < 0 ? -1 : 1;
2779
+ let r = (ux * vx + uy * vy) / (Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy));
2780
+ if (r < -1) r = -1;
2781
+ if (r > 1) r = 1;
2782
+ return sign * Math.acos(r);
2783
+ }
2784
+ const theta1 = vecAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
2785
+ let dTheta = vecAngle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);
2786
+ if (sweepFlag === 0 && dTheta > 0) dTheta -= 2 * Math.PI;
2787
+ if (sweepFlag === 1 && dTheta < 0) dTheta += 2 * Math.PI;
2788
+ const segs = Math.ceil(Math.abs(dTheta) / (Math.PI / 2));
2789
+ const segAngle = dTheta / segs;
2790
+ let ops = "";
2791
+ let angle = theta1;
2792
+ for (let i = 0; i < segs; i++) {
2793
+ const a1 = angle;
2794
+ const a2 = angle + segAngle;
2795
+ const alpha = 4 / 3 * Math.tan((a2 - a1) / 4);
2796
+ const cos1 = Math.cos(a1), sin1 = Math.sin(a1);
2797
+ const cos2 = Math.cos(a2), sin2 = Math.sin(a2);
2798
+ const ep1x = cosPhi * rx * cos1 - sinPhi * ry * sin1 + cx;
2799
+ const ep1y = sinPhi * rx * cos1 + cosPhi * ry * sin1 + cy;
2800
+ const cp1x = ep1x + alpha * (-cosPhi * rx * sin1 - sinPhi * ry * cos1);
2801
+ const cp1y = ep1y + alpha * (-sinPhi * rx * sin1 + cosPhi * ry * cos1);
2802
+ const ep2x = cosPhi * rx * cos2 - sinPhi * ry * sin2 + cx;
2803
+ const ep2y = sinPhi * rx * cos2 + cosPhi * ry * sin2 + cy;
2804
+ const cp2x = ep2x - alpha * (-cosPhi * rx * sin2 - sinPhi * ry * cos2);
2805
+ const cp2y = ep2y - alpha * (-sinPhi * rx * sin2 + cosPhi * ry * cos2);
2806
+ ops += `${fmtN(cp1x)} ${fmtN(cp1y)} ${fmtN(cp2x)} ${fmtN(cp2y)} ${fmtN(ep2x)} ${fmtN(ep2y)} c\n`;
2807
+ angle = a2;
2808
+ }
2809
+ return ops;
2810
+ }
2811
+ /**
2812
+ * Convert parsed SVG draw commands into PDF path construction operators.
2813
+ *
2814
+ * Does **not** emit painting operators (fill / stroke) -- the caller
2815
+ * is responsible for that.
2816
+ */
2817
+ function svgCommandsToPdfOps(commands) {
2818
+ let ops = "";
2819
+ let curX = 0;
2820
+ let curY = 0;
2821
+ for (const cmd of commands) switch (cmd.type) {
2822
+ case "moveTo":
2823
+ curX = cmd.params[0];
2824
+ curY = cmd.params[1];
2825
+ ops += `${fmtN(curX)} ${fmtN(curY)} m\n`;
2826
+ break;
2827
+ case "lineTo":
2828
+ curX = cmd.params[0];
2829
+ curY = cmd.params[1];
2830
+ ops += `${fmtN(curX)} ${fmtN(curY)} l\n`;
2831
+ break;
2832
+ case "curveTo":
2833
+ ops += `${fmtN(cmd.params[0])} ${fmtN(cmd.params[1])} ${fmtN(cmd.params[2])} ${fmtN(cmd.params[3])} ${fmtN(cmd.params[4])} ${fmtN(cmd.params[5])} c\n`;
2834
+ curX = cmd.params[4];
2835
+ curY = cmd.params[5];
2836
+ break;
2837
+ case "quadCurveTo": {
2838
+ const cpx = cmd.params[0];
2839
+ const cpy = cmd.params[1];
2840
+ const toX = cmd.params[2];
2841
+ const toY = cmd.params[3];
2842
+ const cp1x = curX + 2 / 3 * (cpx - curX);
2843
+ const cp1y = curY + 2 / 3 * (cpy - curY);
2844
+ const cp2x = toX + 2 / 3 * (cpx - toX);
2845
+ const cp2y = toY + 2 / 3 * (cpy - toY);
2846
+ ops += `${fmtN(cp1x)} ${fmtN(cp1y)} ${fmtN(cp2x)} ${fmtN(cp2y)} ${fmtN(toX)} ${fmtN(toY)} c\n`;
2847
+ curX = toX;
2848
+ curY = toY;
2849
+ break;
2850
+ }
2851
+ case "closePath":
2852
+ ops += "h\n";
2853
+ break;
2854
+ case "rect":
2855
+ ops += `${fmtN(cmd.params[0])} ${fmtN(cmd.params[1])} ${fmtN(cmd.params[2])} ${fmtN(cmd.params[3])} re\n`;
2856
+ break;
2857
+ case "circle": {
2858
+ const ccx = cmd.params[0], ccy = cmd.params[1], r = cmd.params[2];
2859
+ const ox = r * KAPPA, oy = r * KAPPA;
2860
+ ops += `${fmtN(ccx)} ${fmtN(ccy + r)} m\n`;
2861
+ ops += `${fmtN(ccx + ox)} ${fmtN(ccy + r)} ${fmtN(ccx + r)} ${fmtN(ccy + oy)} ${fmtN(ccx + r)} ${fmtN(ccy)} c\n`;
2862
+ ops += `${fmtN(ccx + r)} ${fmtN(ccy - oy)} ${fmtN(ccx + ox)} ${fmtN(ccy - r)} ${fmtN(ccx)} ${fmtN(ccy - r)} c\n`;
2863
+ ops += `${fmtN(ccx - ox)} ${fmtN(ccy - r)} ${fmtN(ccx - r)} ${fmtN(ccy - oy)} ${fmtN(ccx - r)} ${fmtN(ccy)} c\n`;
2864
+ ops += `${fmtN(ccx - r)} ${fmtN(ccy + oy)} ${fmtN(ccx - ox)} ${fmtN(ccy + r)} ${fmtN(ccx)} ${fmtN(ccy + r)} c\n`;
2865
+ break;
2866
+ }
2867
+ case "ellipse": {
2868
+ const ecx = cmd.params[0], ecy = cmd.params[1];
2869
+ const erx = cmd.params[2], ery = cmd.params[3];
2870
+ const eox = erx * KAPPA, eoy = ery * KAPPA;
2871
+ ops += `${fmtN(ecx)} ${fmtN(ecy + ery)} m\n`;
2872
+ ops += `${fmtN(ecx + eox)} ${fmtN(ecy + ery)} ${fmtN(ecx + erx)} ${fmtN(ecy + eoy)} ${fmtN(ecx + erx)} ${fmtN(ecy)} c\n`;
2873
+ ops += `${fmtN(ecx + erx)} ${fmtN(ecy - eoy)} ${fmtN(ecx + eox)} ${fmtN(ecy - ery)} ${fmtN(ecx)} ${fmtN(ecy - ery)} c\n`;
2874
+ ops += `${fmtN(ecx - eox)} ${fmtN(ecy - ery)} ${fmtN(ecx - erx)} ${fmtN(ecy - eoy)} ${fmtN(ecx - erx)} ${fmtN(ecy)} c\n`;
2875
+ ops += `${fmtN(ecx - erx)} ${fmtN(ecy + eoy)} ${fmtN(ecx - eox)} ${fmtN(ecy + ery)} ${fmtN(ecx)} ${fmtN(ecy + ery)} c\n`;
2876
+ break;
2877
+ }
2878
+ case "arc":
2879
+ ops += svgArcToPdfOps(curX, curY, cmd.params[0], cmd.params[1], cmd.params[2], cmd.params[3], cmd.params[4], cmd.params[5], cmd.params[6]);
2880
+ curX = cmd.params[5];
2881
+ curY = cmd.params[6];
2882
+ break;
2883
+ }
2884
+ return ops;
2885
+ }
2886
+
2708
2887
  //#endregion
2709
2888
  //#region src/layers/optionalContent.ts
2710
2889
  /**
@@ -3009,66 +3188,238 @@ function getRedactionMarks(page) {
3009
3188
  }
3010
3189
 
3011
3190
  //#endregion
3012
- //#region src/core/pdfPage.ts
3013
- var pdfPage_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
3014
- PageSizes: () => PageSizes,
3015
- PdfPage: () => PdfPage,
3016
- wrapText: () => wrapText
3017
- });
3018
- /** Pre-defined page sizes as `[width, height]` tuples in PDF points. */
3019
- const PageSizes = {
3020
- "4A0": [4767.87, 6740.79],
3021
- "2A0": [3370.39, 4767.87],
3022
- A0: [2383.94, 3370.39],
3023
- A1: [1683.78, 2383.94],
3024
- A2: [1190.55, 1683.78],
3025
- A3: [841.89, 1190.55],
3026
- A4: [595.28, 841.89],
3027
- A5: [419.53, 595.28],
3028
- A6: [297.64, 419.53],
3029
- A7: [209.76, 297.64],
3030
- A8: [147.4, 209.76],
3031
- A9: [104.88, 147.4],
3032
- A10: [73.7, 104.88],
3033
- B0: [2834.65, 4008.19],
3034
- B1: [2004.09, 2834.65],
3035
- B2: [1417.32, 2004.09],
3036
- B3: [1000.63, 1417.32],
3037
- B4: [708.66, 1000.63],
3038
- B5: [498.9, 708.66],
3039
- B6: [354.33, 498.9],
3040
- B7: [249.45, 354.33],
3041
- B8: [175.75, 249.45],
3042
- B9: [124.72, 175.75],
3043
- B10: [87.87, 124.72],
3044
- Letter: [612, 792],
3045
- Legal: [612, 1008],
3046
- Tabloid: [792, 1224],
3047
- Ledger: [1224, 792],
3048
- Executive: [521.86, 756],
3049
- Folio: [612, 936],
3050
- C0: [2599.37, 3676.54],
3051
- C1: [1836.85, 2599.37],
3052
- C2: [1298.27, 1836.85],
3053
- C3: [918.43, 1298.27],
3054
- C4: [649.13, 918.43],
3055
- C5: [459.21, 649.13],
3056
- C6: [323.15, 459.21],
3057
- C7: [229.61, 323.15],
3058
- C8: [161.57, 229.61],
3059
- C9: [113.39, 161.57],
3060
- C10: [79.37, 113.39],
3061
- RA0: [2437.8, 3458.27],
3062
- RA1: [1729.13, 2437.8],
3063
- RA2: [1218.9, 1729.13],
3064
- RA3: [864.57, 1218.9],
3065
- RA4: [609.45, 864.57],
3066
- SRA0: [2551.18, 3628.35],
3067
- SRA1: [1814.17, 2551.18],
3068
- SRA2: [1275.59, 1814.17],
3069
- SRA3: [907.09, 1275.59],
3070
- SRA4: [637.8, 907.09]
3071
- };
3191
+ //#region src/core/patterns.ts
3192
+ /** Convert a Color to RGB components (0..1). CMYK/gray are converted. */
3193
+ function colorToRgb(c) {
3194
+ switch (c.type) {
3195
+ case "rgb": return {
3196
+ r: c.r,
3197
+ g: c.g,
3198
+ b: c.b
3199
+ };
3200
+ case "grayscale": return {
3201
+ r: c.gray,
3202
+ g: c.gray,
3203
+ b: c.gray
3204
+ };
3205
+ case "cmyk": return {
3206
+ r: (1 - c.c) * (1 - c.k),
3207
+ g: (1 - c.m) * (1 - c.k),
3208
+ b: (1 - c.y) * (1 - c.k)
3209
+ };
3210
+ }
3211
+ }
3212
+ /** Check if a stop is a ColorStop (has `offset` property). */
3213
+ function isColorStop(stop) {
3214
+ return "offset" in stop && "color" in stop;
3215
+ }
3216
+ /**
3217
+ * Normalise an array of stops into sorted, explicit-offset RGB stops.
3218
+ * Bare Color values get evenly-distributed offsets.
3219
+ */
3220
+ function normalizeStops(stops) {
3221
+ if (stops.length < 2) throw new Error("Gradient requires at least 2 colour stops");
3222
+ const result = [];
3223
+ for (let i = 0; i < stops.length; i++) {
3224
+ const stop = stops[i];
3225
+ let offset;
3226
+ let color;
3227
+ if (isColorStop(stop)) {
3228
+ offset = stop.offset;
3229
+ color = stop.color;
3230
+ } else {
3231
+ offset = i / (stops.length - 1);
3232
+ color = stop;
3233
+ }
3234
+ const { r, g, b } = colorToRgb(color);
3235
+ result.push({
3236
+ offset,
3237
+ r,
3238
+ g,
3239
+ b
3240
+ });
3241
+ }
3242
+ result.sort((a, b) => a.offset - b.offset);
3243
+ return result;
3244
+ }
3245
+ /**
3246
+ * Create a linear (axial) gradient descriptor.
3247
+ *
3248
+ * The gradient runs from `(x1, y1)` to `(x2, y2)` through the given
3249
+ * colour stops. By default the gradient extends beyond its endpoints.
3250
+ *
3251
+ * @param options Gradient parameters.
3252
+ * @returns A {@link GradientFill} descriptor.
3253
+ */
3254
+ function linearGradient(options) {
3255
+ const normalizedStops = normalizeStops(options.stops);
3256
+ return {
3257
+ kind: "gradient",
3258
+ shadingType: 2,
3259
+ coords: [
3260
+ options.x1,
3261
+ options.y1,
3262
+ options.x2,
3263
+ options.y2
3264
+ ],
3265
+ normalizedStops,
3266
+ extend: options.extend ?? true
3267
+ };
3268
+ }
3269
+ /**
3270
+ * Create a radial gradient descriptor.
3271
+ *
3272
+ * The gradient interpolates between two circles: the start circle at
3273
+ * `(x0, y0)` with radius `r0` and the end circle at `(x1, y1)` with
3274
+ * radius `r1`.
3275
+ *
3276
+ * @param options Gradient parameters.
3277
+ * @returns A {@link GradientFill} descriptor (with `shadingType: 3`).
3278
+ */
3279
+ function radialGradient(options) {
3280
+ const normalizedStops = normalizeStops(options.stops);
3281
+ return {
3282
+ kind: "gradient",
3283
+ shadingType: 3,
3284
+ coords: [
3285
+ options.x0,
3286
+ options.y0,
3287
+ options.r0,
3288
+ options.x1,
3289
+ options.y1,
3290
+ options.r1
3291
+ ],
3292
+ normalizedStops,
3293
+ extend: options.extend ?? true
3294
+ };
3295
+ }
3296
+ /**
3297
+ * Create a tiling pattern descriptor.
3298
+ *
3299
+ * @param options Pattern parameters including the tile content stream.
3300
+ * @returns A {@link PatternFill} descriptor.
3301
+ */
3302
+ function tilingPattern(options) {
3303
+ return {
3304
+ kind: "pattern",
3305
+ width: options.width,
3306
+ height: options.height,
3307
+ paintType: options.paintType ?? 1,
3308
+ tilingType: options.tilingType ?? 1,
3309
+ ops: options.ops
3310
+ };
3311
+ }
3312
+ /**
3313
+ * Build a Type 2 (exponential interpolation) function for a single
3314
+ * colour-transition segment between two RGB stops.
3315
+ */
3316
+ function buildType2Function(c0, c1) {
3317
+ const fn = new require_pdfCatalog.PdfDict();
3318
+ fn.set("/FunctionType", require_pdfCatalog.PdfNumber.of(2));
3319
+ fn.set("/Domain", require_pdfCatalog.PdfArray.fromNumbers([0, 1]));
3320
+ fn.set("/C0", require_pdfCatalog.PdfArray.fromNumbers([
3321
+ c0.r,
3322
+ c0.g,
3323
+ c0.b
3324
+ ]));
3325
+ fn.set("/C1", require_pdfCatalog.PdfArray.fromNumbers([
3326
+ c1.r,
3327
+ c1.g,
3328
+ c1.b
3329
+ ]));
3330
+ fn.set("/N", require_pdfCatalog.PdfNumber.of(1));
3331
+ return fn;
3332
+ }
3333
+ /**
3334
+ * Build the shading function for a gradient.
3335
+ *
3336
+ * - 2 stops → single Type 2 (exponential interpolation) function.
3337
+ * - 3+ stops → Type 3 (stitching) function wrapping one Type 2 per segment.
3338
+ */
3339
+ function buildShadingFunction(stops, registry) {
3340
+ if (stops.length === 2) {
3341
+ const fn = buildType2Function(stops[0], stops[1]);
3342
+ return registry.register(fn);
3343
+ }
3344
+ const stitchDict = new require_pdfCatalog.PdfDict();
3345
+ stitchDict.set("/FunctionType", require_pdfCatalog.PdfNumber.of(3));
3346
+ stitchDict.set("/Domain", require_pdfCatalog.PdfArray.fromNumbers([0, 1]));
3347
+ const subFunctions = [];
3348
+ const bounds = [];
3349
+ const encode = [];
3350
+ for (let i = 0; i < stops.length - 1; i++) {
3351
+ const fn = buildType2Function(stops[i], stops[i + 1]);
3352
+ subFunctions.push(registry.register(fn));
3353
+ if (i > 0) bounds.push(stops[i].offset);
3354
+ encode.push(0, 1);
3355
+ }
3356
+ stitchDict.set("/Functions", require_pdfCatalog.PdfArray.of(subFunctions));
3357
+ stitchDict.set("/Bounds", require_pdfCatalog.PdfArray.fromNumbers(bounds));
3358
+ stitchDict.set("/Encode", require_pdfCatalog.PdfArray.fromNumbers(encode));
3359
+ return registry.register(stitchDict);
3360
+ }
3361
+ /**
3362
+ * Materialise a {@link GradientFill} descriptor into actual PDF objects
3363
+ * in the given registry.
3364
+ *
3365
+ * @param gradient The gradient descriptor.
3366
+ * @param registry The document's object registry.
3367
+ * @returns An object with the pattern's indirect reference and a unique
3368
+ * resource name.
3369
+ */
3370
+ function buildGradientObjects(gradient, registry) {
3371
+ const fnRef = buildShadingFunction(gradient.normalizedStops, registry);
3372
+ const shadingDict = new require_pdfCatalog.PdfDict();
3373
+ shadingDict.set("/ShadingType", require_pdfCatalog.PdfNumber.of(gradient.shadingType));
3374
+ shadingDict.set("/ColorSpace", require_pdfCatalog.PdfName.of("DeviceRGB"));
3375
+ shadingDict.set("/Coords", require_pdfCatalog.PdfArray.fromNumbers([...gradient.coords]));
3376
+ shadingDict.set("/Function", fnRef);
3377
+ shadingDict.set("/Extend", require_pdfCatalog.PdfArray.of([require_pdfCatalog.PdfBool.of(gradient.extend), require_pdfCatalog.PdfBool.of(gradient.extend)]));
3378
+ const shadingRef = registry.register(shadingDict);
3379
+ const patternDict = new require_pdfCatalog.PdfDict();
3380
+ patternDict.set("/Type", require_pdfCatalog.PdfName.of("Pattern"));
3381
+ patternDict.set("/PatternType", require_pdfCatalog.PdfNumber.of(2));
3382
+ patternDict.set("/Shading", shadingRef);
3383
+ const patternRef = registry.register(patternDict);
3384
+ return {
3385
+ patternRef,
3386
+ patternName: `Pat${patternRef.objectNumber}`
3387
+ };
3388
+ }
3389
+ /**
3390
+ * Materialise a {@link PatternFill} descriptor into actual PDF objects
3391
+ * in the given registry.
3392
+ *
3393
+ * @param pattern The tiling pattern descriptor.
3394
+ * @param registry The document's object registry.
3395
+ * @returns An object with the pattern's indirect reference and a unique
3396
+ * resource name.
3397
+ */
3398
+ function buildPatternObjects(pattern, registry) {
3399
+ const dict = new require_pdfCatalog.PdfDict();
3400
+ dict.set("/Type", require_pdfCatalog.PdfName.of("Pattern"));
3401
+ dict.set("/PatternType", require_pdfCatalog.PdfNumber.of(1));
3402
+ dict.set("/PaintType", require_pdfCatalog.PdfNumber.of(pattern.paintType));
3403
+ dict.set("/TilingType", require_pdfCatalog.PdfNumber.of(pattern.tilingType));
3404
+ dict.set("/BBox", require_pdfCatalog.PdfArray.fromNumbers([
3405
+ 0,
3406
+ 0,
3407
+ pattern.width,
3408
+ pattern.height
3409
+ ]));
3410
+ dict.set("/XStep", require_pdfCatalog.PdfNumber.of(pattern.width));
3411
+ dict.set("/YStep", require_pdfCatalog.PdfNumber.of(pattern.height));
3412
+ dict.set("/Resources", new require_pdfCatalog.PdfDict());
3413
+ const stream = require_pdfCatalog.PdfStream.fromString(pattern.ops, dict);
3414
+ const patternRef = registry.register(stream);
3415
+ return {
3416
+ patternRef,
3417
+ patternName: `Pat${patternRef.objectNumber}`
3418
+ };
3419
+ }
3420
+
3421
+ //#endregion
3422
+ //#region src/core/pdfPageText.ts
3072
3423
  /**
3073
3424
  * Break a single line of text into multiple lines that fit within `maxWidth`.
3074
3425
  *
@@ -3153,6 +3504,67 @@ function breakWord(word, maxWidth, font, size) {
3153
3504
  if (current !== "") fragments.push(current);
3154
3505
  return fragments;
3155
3506
  }
3507
+
3508
+ //#endregion
3509
+ //#region src/core/pdfPage.ts
3510
+ var pdfPage_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
3511
+ PageSizes: () => PageSizes,
3512
+ PdfPage: () => PdfPage
3513
+ });
3514
+ /** Pre-defined page sizes as `[width, height]` tuples in PDF points. */
3515
+ const PageSizes = {
3516
+ "4A0": [4767.87, 6740.79],
3517
+ "2A0": [3370.39, 4767.87],
3518
+ A0: [2383.94, 3370.39],
3519
+ A1: [1683.78, 2383.94],
3520
+ A2: [1190.55, 1683.78],
3521
+ A3: [841.89, 1190.55],
3522
+ A4: [595.28, 841.89],
3523
+ A5: [419.53, 595.28],
3524
+ A6: [297.64, 419.53],
3525
+ A7: [209.76, 297.64],
3526
+ A8: [147.4, 209.76],
3527
+ A9: [104.88, 147.4],
3528
+ A10: [73.7, 104.88],
3529
+ B0: [2834.65, 4008.19],
3530
+ B1: [2004.09, 2834.65],
3531
+ B2: [1417.32, 2004.09],
3532
+ B3: [1000.63, 1417.32],
3533
+ B4: [708.66, 1000.63],
3534
+ B5: [498.9, 708.66],
3535
+ B6: [354.33, 498.9],
3536
+ B7: [249.45, 354.33],
3537
+ B8: [175.75, 249.45],
3538
+ B9: [124.72, 175.75],
3539
+ B10: [87.87, 124.72],
3540
+ Letter: [612, 792],
3541
+ Legal: [612, 1008],
3542
+ Tabloid: [792, 1224],
3543
+ Ledger: [1224, 792],
3544
+ Executive: [521.86, 756],
3545
+ Folio: [612, 936],
3546
+ C0: [2599.37, 3676.54],
3547
+ C1: [1836.85, 2599.37],
3548
+ C2: [1298.27, 1836.85],
3549
+ C3: [918.43, 1298.27],
3550
+ C4: [649.13, 918.43],
3551
+ C5: [459.21, 649.13],
3552
+ C6: [323.15, 459.21],
3553
+ C7: [229.61, 323.15],
3554
+ C8: [161.57, 229.61],
3555
+ C9: [113.39, 161.57],
3556
+ C10: [79.37, 113.39],
3557
+ RA0: [2437.8, 3458.27],
3558
+ RA1: [1729.13, 2437.8],
3559
+ RA2: [1218.9, 1729.13],
3560
+ RA3: [864.57, 1218.9],
3561
+ RA4: [609.45, 864.57],
3562
+ SRA0: [2551.18, 3628.35],
3563
+ SRA1: [1814.17, 2551.18],
3564
+ SRA2: [1275.59, 1814.17],
3565
+ SRA3: [907.09, 1275.59],
3566
+ SRA4: [637.8, 907.09]
3567
+ };
3156
3568
  /**
3157
3569
  * A single page in a PDF document.
3158
3570
  *
@@ -3180,10 +3592,25 @@ var PdfPage = class PdfPage {
3180
3592
  */
3181
3593
  extGStates = /* @__PURE__ */ new Map();
3182
3594
  /**
3595
+ * Pattern resources referenced by this page.
3596
+ * Maps a resource name (e.g. `Pat5`) to its indirect reference.
3597
+ * Used for gradient fills and tiling patterns.
3598
+ */
3599
+ patterns = /* @__PURE__ */ new Map();
3600
+ /**
3183
3601
  * Counter for ExtGState resource names (`GS1`, `GS2`, ...).
3184
3602
  */
3185
3603
  extGStateCounter = 0;
3186
3604
  /**
3605
+ * Counter for transparency group XObject resource names (`TG1`, `TG2`, ...).
3606
+ */
3607
+ transparencyGroupCounter = 0;
3608
+ /**
3609
+ * Stack of transparency group state. Each entry records the ops length
3610
+ * at the time `beginTransparencyGroup()` was called, plus the options.
3611
+ */
3612
+ transparencyGroupStack = [];
3613
+ /**
3187
3614
  * Cache mapping composite keys (opacity + blend mode) to their ExtGState
3188
3615
  * resource names, so the same combination reuses the same graphics state
3189
3616
  * dictionary.
@@ -3323,6 +3750,10 @@ var PdfPage = class PdfPage {
3323
3750
  registerExtGState(name, ref) {
3324
3751
  this.extGStates.set(name, ref);
3325
3752
  }
3753
+ /** @internal Register a Pattern resource on this page. */
3754
+ registerPattern(name, ref) {
3755
+ this.patterns.set(name, ref);
3756
+ }
3326
3757
  /**
3327
3758
  * Set the default font used by {@link drawText} when the `font` option
3328
3759
  * is not provided.
@@ -4224,6 +4655,51 @@ var PdfPage = class PdfPage {
4224
4655
  this.ops += restoreState();
4225
4656
  }
4226
4657
  /**
4658
+ * Draw a gradient fill (linear or radial) clipped to a rectangle.
4659
+ *
4660
+ * The gradient is registered as a `/Pattern` resource on this page
4661
+ * and painted within the specified rectangular region.
4662
+ *
4663
+ * @param gradient A gradient descriptor from {@link linearGradient}
4664
+ * or {@link radialGradient}.
4665
+ * @param rect The rectangle to fill.
4666
+ */
4667
+ drawGradient(gradient, rect) {
4668
+ const { patternRef, patternName } = buildGradientObjects(gradient, this.registry);
4669
+ this.patterns.set(patternName, patternRef);
4670
+ this.ops += saveState();
4671
+ this.ops += rectangle(rect.x, rect.y, rect.width, rect.height);
4672
+ this.ops += clip();
4673
+ this.ops += endPath();
4674
+ this.ops += setColorSpace("Pattern");
4675
+ this.ops += `/${patternName} scn\n`;
4676
+ this.ops += rectangle(rect.x, rect.y, rect.width, rect.height);
4677
+ this.ops += fill();
4678
+ this.ops += restoreState();
4679
+ }
4680
+ /**
4681
+ * Draw a tiling pattern fill clipped to a rectangle.
4682
+ *
4683
+ * The pattern is registered as a `/Pattern` resource on this page
4684
+ * and painted within the specified rectangular region.
4685
+ *
4686
+ * @param pattern A pattern descriptor from {@link tilingPattern}.
4687
+ * @param rect The rectangle to fill.
4688
+ */
4689
+ drawPattern(pattern, rect) {
4690
+ const { patternRef, patternName } = buildPatternObjects(pattern, this.registry);
4691
+ this.patterns.set(patternName, patternRef);
4692
+ this.ops += saveState();
4693
+ this.ops += rectangle(rect.x, rect.y, rect.width, rect.height);
4694
+ this.ops += clip();
4695
+ this.ops += endPath();
4696
+ this.ops += setColorSpace("Pattern");
4697
+ this.ops += `/${patternName} scn\n`;
4698
+ this.ops += rectangle(rect.x, rect.y, rect.width, rect.height);
4699
+ this.ops += fill();
4700
+ this.ops += restoreState();
4701
+ }
4702
+ /**
4227
4703
  * Begin layer-specific content.
4228
4704
  *
4229
4705
  * Content drawn after this call and before {@link endLayer} will be
@@ -4244,6 +4720,120 @@ var PdfPage = class PdfPage {
4244
4720
  this.ops += endLayerContent();
4245
4721
  }
4246
4722
  /**
4723
+ * Begin a transparency group. All drawing operations until
4724
+ * {@link endTransparencyGroup} will be captured and composited as a
4725
+ * single Form XObject with a `/Group` transparency dictionary.
4726
+ *
4727
+ * Transparency groups enable isolated and knockout compositing effects
4728
+ * that are not possible with simple opacity settings.
4729
+ *
4730
+ * Groups can be nested — each call must be paired with a matching
4731
+ * {@link endTransparencyGroup}.
4732
+ *
4733
+ * @param options Isolation, knockout, and color-space settings.
4734
+ *
4735
+ * @example
4736
+ * ```ts
4737
+ * page.beginTransparencyGroup({ isolated: true });
4738
+ * page.drawRectangle({ x: 50, y: 50, width: 100, height: 100, opacity: 0.5 });
4739
+ * page.drawCircle({ x: 100, y: 100, size: 60, opacity: 0.5 });
4740
+ * page.endTransparencyGroup();
4741
+ * ```
4742
+ */
4743
+ beginTransparencyGroup(options) {
4744
+ this.transparencyGroupStack.push({
4745
+ opsStart: this.ops.length,
4746
+ options: options ?? {}
4747
+ });
4748
+ }
4749
+ /**
4750
+ * End the current transparency group and composite it onto the page
4751
+ * as a Form XObject.
4752
+ *
4753
+ * @throws {Error} If there is no matching {@link beginTransparencyGroup}.
4754
+ */
4755
+ endTransparencyGroup() {
4756
+ const group = this.transparencyGroupStack.pop();
4757
+ if (!group) throw new Error("No transparency group to end — call beginTransparencyGroup() first");
4758
+ const groupOps = this.ops.slice(group.opsStart);
4759
+ this.ops = this.ops.slice(0, group.opsStart);
4760
+ const colorSpace = group.options.colorSpace ?? "DeviceRGB";
4761
+ const groupDict = new require_pdfCatalog.PdfDict();
4762
+ groupDict.set("/S", require_pdfCatalog.PdfName.of("Transparency"));
4763
+ groupDict.set("/I", require_pdfCatalog.PdfBool.of(group.options.isolated ?? true));
4764
+ groupDict.set("/K", require_pdfCatalog.PdfBool.of(group.options.knockout ?? false));
4765
+ groupDict.set("/CS", require_pdfCatalog.PdfName.of(colorSpace));
4766
+ const bbox = require_pdfCatalog.PdfArray.fromNumbers([
4767
+ this.mediaX,
4768
+ this.mediaY,
4769
+ this.mediaX + this.mediaWidth,
4770
+ this.mediaY + this.mediaHeight
4771
+ ]);
4772
+ const formDict = new require_pdfCatalog.PdfDict();
4773
+ formDict.set("/Type", require_pdfCatalog.PdfName.of("XObject"));
4774
+ formDict.set("/Subtype", require_pdfCatalog.PdfName.of("Form"));
4775
+ formDict.set("/BBox", bbox);
4776
+ formDict.set("/Group", groupDict);
4777
+ const formStream = require_pdfCatalog.PdfStream.fromString(groupOps, formDict);
4778
+ const formRef = this.registry.register(formStream);
4779
+ this.transparencyGroupCounter++;
4780
+ const name = `TG${this.transparencyGroupCounter}`;
4781
+ this.registerXObject(name, formRef);
4782
+ this.ops += saveState();
4783
+ this.ops += drawXObject(name);
4784
+ this.ops += restoreState();
4785
+ }
4786
+ /**
4787
+ * Apply a soft mask (luminosity-based) for subsequent drawing operations.
4788
+ *
4789
+ * White regions in the mask are fully opaque; black regions are fully
4790
+ * transparent. The mask stays active until {@link clearSoftMask} is
4791
+ * called or the graphics state is restored.
4792
+ *
4793
+ * @param mask A soft mask reference created by
4794
+ * {@link PdfDocument.createSoftMask}.
4795
+ *
4796
+ * @example
4797
+ * ```ts
4798
+ * const mask = doc.createSoftMask(200, 200, (b) => {
4799
+ * b.drawRectangle(0, 0, 200, 200, 1); // white = opaque
4800
+ * b.drawCircle(100, 100, 80, 0); // black = transparent
4801
+ * });
4802
+ * page.applySoftMask(mask);
4803
+ * page.drawImage(image, { x: 50, y: 50, width: 200, height: 200 });
4804
+ * page.clearSoftMask();
4805
+ * ```
4806
+ */
4807
+ applySoftMask(mask) {
4808
+ const smaskDict = new require_pdfCatalog.PdfDict();
4809
+ smaskDict.set("/S", require_pdfCatalog.PdfName.of("Luminosity"));
4810
+ smaskDict.set("/G", mask.ref);
4811
+ const gsDict = new require_pdfCatalog.PdfDict();
4812
+ gsDict.set("/Type", require_pdfCatalog.PdfName.of("ExtGState"));
4813
+ gsDict.set("/SMask", smaskDict);
4814
+ const gsRef = this.registry.register(gsDict);
4815
+ this.extGStateCounter++;
4816
+ const gsName = `GS${this.extGStateCounter}`;
4817
+ this.extGStates.set(gsName, gsRef);
4818
+ this.ops += setGraphicsState(gsName);
4819
+ }
4820
+ /**
4821
+ * Clear the current soft mask, resetting to no masking.
4822
+ *
4823
+ * This emits an ExtGState with `/SMask /None`, which removes any
4824
+ * previously applied soft mask for subsequent drawing operations.
4825
+ */
4826
+ clearSoftMask() {
4827
+ const gsDict = new require_pdfCatalog.PdfDict();
4828
+ gsDict.set("/Type", require_pdfCatalog.PdfName.of("ExtGState"));
4829
+ gsDict.set("/SMask", require_pdfCatalog.PdfName.of("None"));
4830
+ const gsRef = this.registry.register(gsDict);
4831
+ this.extGStateCounter++;
4832
+ const gsName = `GS${this.extGStateCounter}`;
4833
+ this.extGStates.set(gsName, gsRef);
4834
+ this.ops += setGraphicsState(gsName);
4835
+ }
4836
+ /**
4247
4837
  * Mark a rectangular region on this page for redaction.
4248
4838
  *
4249
4839
  * The mark is stored but not applied until `doc.applyRedactions()`
@@ -4296,6 +4886,11 @@ var PdfPage = class PdfPage {
4296
4886
  for (const [name, ref] of this.extGStates) gsDict.set(name, ref);
4297
4887
  resources.set("/ExtGState", gsDict);
4298
4888
  }
4889
+ if (this.patterns.size > 0) {
4890
+ const patDict = new require_pdfCatalog.PdfDict();
4891
+ for (const [name, ref] of this.patterns) patDict.set(name, ref);
4892
+ resources.set("/Pattern", patDict);
4893
+ }
4299
4894
  resources.set("/ProcSet", require_pdfCatalog.PdfArray.of([
4300
4895
  require_pdfCatalog.PdfName.of("PDF"),
4301
4896
  require_pdfCatalog.PdfName.of("Text"),
@@ -4341,6 +4936,15 @@ var PdfPage = class PdfPage {
4341
4936
  const gsDict = gsObj;
4342
4937
  for (const [name, ref] of this.extGStates) gsDict.set(name, ref);
4343
4938
  }
4939
+ if (this.patterns.size > 0) {
4940
+ let patObj = resources.get("/Pattern");
4941
+ if (patObj === void 0 || patObj.kind !== "dict") {
4942
+ patObj = new require_pdfCatalog.PdfDict();
4943
+ resources.set("/Pattern", patObj);
4944
+ }
4945
+ const patDict = patObj;
4946
+ for (const [name, ref] of this.patterns) patDict.set(name, ref);
4947
+ }
4344
4948
  return resources;
4345
4949
  }
4346
4950
  /**
@@ -4385,159 +4989,6 @@ var PdfPage = class PdfPage {
4385
4989
  };
4386
4990
  }
4387
4991
  };
4388
- /** Format a number for PDF output. */
4389
- function fmtN(value) {
4390
- if (Number.isInteger(value)) return value.toString();
4391
- const s = value.toFixed(6).replace(/\.?0+$/, "");
4392
- return s === "-0" ? "0" : s;
4393
- }
4394
- /** Magic constant for circular arc approximation: 4*(sqrt(2)-1)/3. */
4395
- const KAPPA = .5522847498;
4396
- /**
4397
- * Approximate an SVG arc command as cubic Bezier curve(s) (PDF operators).
4398
- *
4399
- * SVG arcs use endpoint parameterization; PDF has no native arc command.
4400
- */
4401
- function svgArcToPdfOps(fromX, fromY, rx0, ry0, rotationDeg, largeArcFlag, sweepFlag, toX, toY) {
4402
- let rx = Math.abs(rx0);
4403
- let ry = Math.abs(ry0);
4404
- if (rx === 0 || ry === 0) return `${fmtN(toX)} ${fmtN(toY)} l\n`;
4405
- const phi = rotationDeg * Math.PI / 180;
4406
- const cosPhi = Math.cos(phi);
4407
- const sinPhi = Math.sin(phi);
4408
- const dx2 = (fromX - toX) / 2;
4409
- const dy2 = (fromY - toY) / 2;
4410
- const x1p = cosPhi * dx2 + sinPhi * dy2;
4411
- const y1p = -sinPhi * dx2 + cosPhi * dy2;
4412
- let rxSq = rx * rx;
4413
- let rySq = ry * ry;
4414
- const x1pSq = x1p * x1p;
4415
- const y1pSq = y1p * y1p;
4416
- const lambda = x1pSq / rxSq + y1pSq / rySq;
4417
- if (lambda > 1) {
4418
- const s = Math.sqrt(lambda);
4419
- rx *= s;
4420
- ry *= s;
4421
- rxSq = rx * rx;
4422
- rySq = ry * ry;
4423
- }
4424
- let sq = (rxSq * rySq - rxSq * y1pSq - rySq * x1pSq) / (rxSq * y1pSq + rySq * x1pSq);
4425
- if (sq < 0) sq = 0;
4426
- sq = Math.sqrt(sq);
4427
- if (largeArcFlag === sweepFlag) sq = -sq;
4428
- const cxp = sq * rx * y1p / ry;
4429
- const cyp = -sq * ry * x1p / rx;
4430
- const cx = cosPhi * cxp - sinPhi * cyp + (fromX + toX) / 2;
4431
- const cy = sinPhi * cxp + cosPhi * cyp + (fromY + toY) / 2;
4432
- function vecAngle(ux, uy, vx, vy) {
4433
- const sign = ux * vy - uy * vx < 0 ? -1 : 1;
4434
- let r = (ux * vx + uy * vy) / (Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy));
4435
- if (r < -1) r = -1;
4436
- if (r > 1) r = 1;
4437
- return sign * Math.acos(r);
4438
- }
4439
- const theta1 = vecAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
4440
- let dTheta = vecAngle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);
4441
- if (sweepFlag === 0 && dTheta > 0) dTheta -= 2 * Math.PI;
4442
- if (sweepFlag === 1 && dTheta < 0) dTheta += 2 * Math.PI;
4443
- const segs = Math.ceil(Math.abs(dTheta) / (Math.PI / 2));
4444
- const segAngle = dTheta / segs;
4445
- let ops = "";
4446
- let angle = theta1;
4447
- for (let i = 0; i < segs; i++) {
4448
- const a1 = angle;
4449
- const a2 = angle + segAngle;
4450
- const alpha = 4 / 3 * Math.tan((a2 - a1) / 4);
4451
- const cos1 = Math.cos(a1), sin1 = Math.sin(a1);
4452
- const cos2 = Math.cos(a2), sin2 = Math.sin(a2);
4453
- const ep1x = cosPhi * rx * cos1 - sinPhi * ry * sin1 + cx;
4454
- const ep1y = sinPhi * rx * cos1 + cosPhi * ry * sin1 + cy;
4455
- const cp1x = ep1x + alpha * (-cosPhi * rx * sin1 - sinPhi * ry * cos1);
4456
- const cp1y = ep1y + alpha * (-sinPhi * rx * sin1 + cosPhi * ry * cos1);
4457
- const ep2x = cosPhi * rx * cos2 - sinPhi * ry * sin2 + cx;
4458
- const ep2y = sinPhi * rx * cos2 + cosPhi * ry * sin2 + cy;
4459
- const cp2x = ep2x - alpha * (-cosPhi * rx * sin2 - sinPhi * ry * cos2);
4460
- const cp2y = ep2y - alpha * (-sinPhi * rx * sin2 + cosPhi * ry * cos2);
4461
- ops += `${fmtN(cp1x)} ${fmtN(cp1y)} ${fmtN(cp2x)} ${fmtN(cp2y)} ${fmtN(ep2x)} ${fmtN(ep2y)} c\n`;
4462
- angle = a2;
4463
- }
4464
- return ops;
4465
- }
4466
- /**
4467
- * Convert parsed SVG draw commands into PDF path construction operators.
4468
- *
4469
- * Does **not** emit painting operators (fill / stroke) -- the caller
4470
- * is responsible for that.
4471
- */
4472
- function svgCommandsToPdfOps(commands) {
4473
- let ops = "";
4474
- let curX = 0;
4475
- let curY = 0;
4476
- for (const cmd of commands) switch (cmd.type) {
4477
- case "moveTo":
4478
- curX = cmd.params[0];
4479
- curY = cmd.params[1];
4480
- ops += `${fmtN(curX)} ${fmtN(curY)} m\n`;
4481
- break;
4482
- case "lineTo":
4483
- curX = cmd.params[0];
4484
- curY = cmd.params[1];
4485
- ops += `${fmtN(curX)} ${fmtN(curY)} l\n`;
4486
- break;
4487
- case "curveTo":
4488
- ops += `${fmtN(cmd.params[0])} ${fmtN(cmd.params[1])} ${fmtN(cmd.params[2])} ${fmtN(cmd.params[3])} ${fmtN(cmd.params[4])} ${fmtN(cmd.params[5])} c\n`;
4489
- curX = cmd.params[4];
4490
- curY = cmd.params[5];
4491
- break;
4492
- case "quadCurveTo": {
4493
- const cpx = cmd.params[0];
4494
- const cpy = cmd.params[1];
4495
- const toX = cmd.params[2];
4496
- const toY = cmd.params[3];
4497
- const cp1x = curX + 2 / 3 * (cpx - curX);
4498
- const cp1y = curY + 2 / 3 * (cpy - curY);
4499
- const cp2x = toX + 2 / 3 * (cpx - toX);
4500
- const cp2y = toY + 2 / 3 * (cpy - toY);
4501
- ops += `${fmtN(cp1x)} ${fmtN(cp1y)} ${fmtN(cp2x)} ${fmtN(cp2y)} ${fmtN(toX)} ${fmtN(toY)} c\n`;
4502
- curX = toX;
4503
- curY = toY;
4504
- break;
4505
- }
4506
- case "closePath":
4507
- ops += "h\n";
4508
- break;
4509
- case "rect":
4510
- ops += `${fmtN(cmd.params[0])} ${fmtN(cmd.params[1])} ${fmtN(cmd.params[2])} ${fmtN(cmd.params[3])} re\n`;
4511
- break;
4512
- case "circle": {
4513
- const ccx = cmd.params[0], ccy = cmd.params[1], r = cmd.params[2];
4514
- const ox = r * KAPPA, oy = r * KAPPA;
4515
- ops += `${fmtN(ccx)} ${fmtN(ccy + r)} m\n`;
4516
- ops += `${fmtN(ccx + ox)} ${fmtN(ccy + r)} ${fmtN(ccx + r)} ${fmtN(ccy + oy)} ${fmtN(ccx + r)} ${fmtN(ccy)} c\n`;
4517
- ops += `${fmtN(ccx + r)} ${fmtN(ccy - oy)} ${fmtN(ccx + ox)} ${fmtN(ccy - r)} ${fmtN(ccx)} ${fmtN(ccy - r)} c\n`;
4518
- ops += `${fmtN(ccx - ox)} ${fmtN(ccy - r)} ${fmtN(ccx - r)} ${fmtN(ccy - oy)} ${fmtN(ccx - r)} ${fmtN(ccy)} c\n`;
4519
- ops += `${fmtN(ccx - r)} ${fmtN(ccy + oy)} ${fmtN(ccx - ox)} ${fmtN(ccy + r)} ${fmtN(ccx)} ${fmtN(ccy + r)} c\n`;
4520
- break;
4521
- }
4522
- case "ellipse": {
4523
- const ecx = cmd.params[0], ecy = cmd.params[1];
4524
- const erx = cmd.params[2], ery = cmd.params[3];
4525
- const eox = erx * KAPPA, eoy = ery * KAPPA;
4526
- ops += `${fmtN(ecx)} ${fmtN(ecy + ery)} m\n`;
4527
- ops += `${fmtN(ecx + eox)} ${fmtN(ecy + ery)} ${fmtN(ecx + erx)} ${fmtN(ecy + eoy)} ${fmtN(ecx + erx)} ${fmtN(ecy)} c\n`;
4528
- ops += `${fmtN(ecx + erx)} ${fmtN(ecy - eoy)} ${fmtN(ecx + eox)} ${fmtN(ecy - ery)} ${fmtN(ecx)} ${fmtN(ecy - ery)} c\n`;
4529
- ops += `${fmtN(ecx - eox)} ${fmtN(ecy - ery)} ${fmtN(ecx - erx)} ${fmtN(ecy - eoy)} ${fmtN(ecx - erx)} ${fmtN(ecy)} c\n`;
4530
- ops += `${fmtN(ecx - erx)} ${fmtN(ecy + eoy)} ${fmtN(ecx - eox)} ${fmtN(ecy + ery)} ${fmtN(ecx)} ${fmtN(ecy + ery)} c\n`;
4531
- break;
4532
- }
4533
- case "arc":
4534
- ops += svgArcToPdfOps(curX, curY, cmd.params[0], cmd.params[1], cmd.params[2], cmd.params[3], cmd.params[4], cmd.params[5], cmd.params[6]);
4535
- curX = cmd.params[5];
4536
- curY = cmd.params[6];
4537
- break;
4538
- }
4539
- return ops;
4540
- }
4541
4992
 
4542
4993
  //#endregion
4543
4994
  Object.defineProperty(exports, 'AnnotationFlags', {
@@ -4648,6 +5099,18 @@ Object.defineProperty(exports, 'buildAnnotationDict', {
4648
5099
  return buildAnnotationDict;
4649
5100
  }
4650
5101
  });
5102
+ Object.defineProperty(exports, 'buildGradientObjects', {
5103
+ enumerable: true,
5104
+ get: function () {
5105
+ return buildGradientObjects;
5106
+ }
5107
+ });
5108
+ Object.defineProperty(exports, 'buildPatternObjects', {
5109
+ enumerable: true,
5110
+ get: function () {
5111
+ return buildPatternObjects;
5112
+ }
5113
+ });
4651
5114
  Object.defineProperty(exports, 'circlePath', {
4652
5115
  enumerable: true,
4653
5116
  get: function () {
@@ -4858,6 +5321,12 @@ Object.defineProperty(exports, 'lineTo', {
4858
5321
  return lineTo;
4859
5322
  }
4860
5323
  });
5324
+ Object.defineProperty(exports, 'linearGradient', {
5325
+ enumerable: true,
5326
+ get: function () {
5327
+ return linearGradient;
5328
+ }
5329
+ });
4861
5330
  Object.defineProperty(exports, 'markForRedaction', {
4862
5331
  enumerable: true,
4863
5332
  get: function () {
@@ -4918,6 +5387,12 @@ Object.defineProperty(exports, 'pdfPage_exports', {
4918
5387
  return pdfPage_exports;
4919
5388
  }
4920
5389
  });
5390
+ Object.defineProperty(exports, 'radialGradient', {
5391
+ enumerable: true,
5392
+ get: function () {
5393
+ return radialGradient;
5394
+ }
5395
+ });
4921
5396
  Object.defineProperty(exports, 'radians', {
4922
5397
  enumerable: true,
4923
5398
  get: function () {
@@ -5182,6 +5657,12 @@ Object.defineProperty(exports, 'svgToPdfOperators', {
5182
5657
  return svgToPdfOperators;
5183
5658
  }
5184
5659
  });
5660
+ Object.defineProperty(exports, 'tilingPattern', {
5661
+ enumerable: true,
5662
+ get: function () {
5663
+ return tilingPattern;
5664
+ }
5665
+ });
5185
5666
  Object.defineProperty(exports, 'translate', {
5186
5667
  enumerable: true,
5187
5668
  get: function () {
@@ -5200,4 +5681,4 @@ Object.defineProperty(exports, 'wrapText', {
5200
5681
  return wrapText;
5201
5682
  }
5202
5683
  });
5203
- //# sourceMappingURL=pdfPage-BMGFx7Xd.cjs.map
5684
+ //# sourceMappingURL=pdfPage-DBfdinTR.cjs.map