@poe-platform/safe-bash 0.1.771 → 0.1.773

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.
Files changed (42) hide show
  1. package/dist/image-ast/index.browser.js +2801 -556
  2. package/dist/image-ast/index.js +2801 -556
  3. package/dist/pdf-ast/ast.d.ts +7 -0
  4. package/dist/pdf-ast/content/evaluator.d.ts +1 -0
  5. package/dist/pdf-ast/index.js +2845 -568
  6. package/dist/pdf-ast/render/raster.d.ts +1 -0
  7. package/dist/pdf-ast/vendor/pdfjs-fonts.d.mts +24 -0
  8. package/dist/pdf-ast/vendor/pdfjs-fonts.mjs +2621 -0
  9. package/dist/safe-bash/chunks/{chunk-FSH7QRIC.js → chunk-Z3HX3ZBA.js} +10 -4
  10. package/dist/safe-bash/command-chunks/{chunk-M2XU2YCK.js → chunk-5VXZSNM2.js} +2 -2
  11. package/dist/safe-bash/command-chunks/{chunk-C4AAJTXF.js → chunk-B2MM5DIT.js} +2804 -556
  12. package/dist/safe-bash/command-chunks/{chunk-NBENXODJ.js → chunk-G3NVK25P.js} +1 -1
  13. package/dist/safe-bash/commands/python/host-capabilities.js +15 -6
  14. package/dist/safe-bash/commands/python/index.browser.js +1 -1
  15. package/dist/safe-bash/core.browser.js +39 -39
  16. package/dist/safe-bash/core.d.ts +1 -1
  17. package/dist/safe-bash/plugins/composition.d.ts +2 -0
  18. package/dist/safe-bash/plugins/composition.js +2 -1
  19. package/dist/safe-bash-command-ffmpeg/index.js +10968 -9719
  20. package/dist/safe-bash-command-gh/index.d.ts +1 -0
  21. package/dist/safe-bash-command-gh/index.js +43 -13
  22. package/dist/safe-bash-command-gh/types.d.ts +1 -0
  23. package/dist/safe-bash-command-git/git_rust.wasm +0 -0
  24. package/dist/safe-bash-command-git/index.js +22 -15
  25. package/dist/safe-bash-command-git/wasm.generated.js +1 -1
  26. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  27. package/dist/safe-bash-command-pandoc/command.js +3 -3
  28. package/dist/safe-bash-command-pandoc/index.js +3 -3
  29. package/dist/safe-bash-command-pdfimages/index.js +2800 -510
  30. package/dist/safe-bash-command-pdfinfo/index.js +2842 -568
  31. package/dist/safe-bash-command-pdftk/index.js +2800 -510
  32. package/dist/safe-bash-command-pdftoppm/index.js +2847 -637
  33. package/dist/safe-bash-command-pdftotext/index.js +2800 -510
  34. package/dist/safe-bash-command-qpdf/index.js +2800 -510
  35. package/dist/safe-bash-command-sips/index.js +2 -2
  36. package/dist/safe-bash-command-soffice/index.js +1 -1
  37. package/dist/safe-bash-command-ssconvert/index.js +2811 -566
  38. package/dist/safe-bash-command-wkhtmltopdf/index.js +2833 -510
  39. package/dist/safe-bash-mcp/index.d.ts +8 -2
  40. package/dist/safe-bash-mcp/index.js +13 -6
  41. package/package.json +7 -7
  42. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +62 -1
@@ -2595,6 +2595,198 @@ function utf8PasswordToBytes(password) {
2595
2595
  }
2596
2596
  return stringToBytes(password);
2597
2597
  }
2598
+ function resizeRgbImage(src, dest, w1, h1, w2, h2, alpha01) {
2599
+ const COMPONENTS = 3;
2600
+ alpha01 = alpha01 !== 1 ? 0 : alpha01;
2601
+ const xRatio = w1 / w2;
2602
+ const yRatio = h1 / h2;
2603
+ let newIndex = 0, oldIndex;
2604
+ const xScaled = new Uint16Array(w2);
2605
+ const w1Scanline = w1 * COMPONENTS;
2606
+ for (let i = 0; i < w2; i++) {
2607
+ xScaled[i] = Math.floor(i * xRatio) * COMPONENTS;
2608
+ }
2609
+ for (let i = 0; i < h2; i++) {
2610
+ const py = Math.floor(i * yRatio) * w1Scanline;
2611
+ for (let j = 0; j < w2; j++) {
2612
+ oldIndex = py + xScaled[j];
2613
+ dest[newIndex++] = src[oldIndex++];
2614
+ dest[newIndex++] = src[oldIndex++];
2615
+ dest[newIndex++] = src[oldIndex++];
2616
+ newIndex += alpha01;
2617
+ }
2618
+ }
2619
+ }
2620
+ function isDefaultDecodeHelper(decode, expectedLen) {
2621
+ if (!Array.isArray(decode)) {
2622
+ return true;
2623
+ }
2624
+ const decodeLen = decode.length;
2625
+ if (decodeLen < expectedLen) {
2626
+ warn2("Decode map length is too short.");
2627
+ return true;
2628
+ }
2629
+ if (decodeLen > expectedLen) {
2630
+ info("Truncating too long decode map.");
2631
+ decode.length = expectedLen;
2632
+ }
2633
+ return false;
2634
+ }
2635
+ function parsePostScriptFunction(source) {
2636
+ return new Parser(new Lexer(source)).parse();
2637
+ }
2638
+ function _nodesEqual(a, b) {
2639
+ if (a === b) {
2640
+ return true;
2641
+ }
2642
+ if (a.type !== b.type) {
2643
+ return false;
2644
+ }
2645
+ switch (a.type) {
2646
+ case PS_NODE.arg:
2647
+ return a.index === b.index;
2648
+ case PS_NODE.const:
2649
+ return a.value === b.value;
2650
+ case PS_NODE.unary:
2651
+ return a.op === b.op && _nodesEqual(a.operand, b.operand);
2652
+ case PS_NODE.binary:
2653
+ return a.op === b.op && _nodesEqual(a.first, b.first) && _nodesEqual(a.second, b.second);
2654
+ case PS_NODE.ternary:
2655
+ return _nodesEqual(a.cond, b.cond) && _nodesEqual(a.then, b.then) && _nodesEqual(a.otherwise, b.otherwise);
2656
+ default:
2657
+ return false;
2658
+ }
2659
+ }
2660
+ function _evalBinaryConst(op, a, b) {
2661
+ switch (op) {
2662
+ case TOKEN.add:
2663
+ return a + b;
2664
+ case TOKEN.sub:
2665
+ return a - b;
2666
+ case TOKEN.mul:
2667
+ return a * b;
2668
+ case TOKEN.div:
2669
+ return b !== 0 ? a / b : 0;
2670
+ // div by zero → 0
2671
+ case TOKEN.idiv:
2672
+ return b !== 0 ? Math.trunc(a / b) : 0;
2673
+ // div by zero → 0
2674
+ case TOKEN.mod:
2675
+ return b !== 0 ? a - Math.trunc(a / b) * b : 0;
2676
+ // div by zero → 0
2677
+ case TOKEN.exp: {
2678
+ const r = a ** b;
2679
+ return Number.isFinite(r) ? r : void 0;
2680
+ }
2681
+ case TOKEN.atan: {
2682
+ let deg = Math.atan2(a, b) * (180 / Math.PI);
2683
+ if (deg < 0) {
2684
+ deg += 360;
2685
+ }
2686
+ return deg;
2687
+ }
2688
+ case TOKEN.eq:
2689
+ return a === b;
2690
+ case TOKEN.ne:
2691
+ return a !== b;
2692
+ case TOKEN.gt:
2693
+ return a > b;
2694
+ case TOKEN.ge:
2695
+ return a >= b;
2696
+ case TOKEN.lt:
2697
+ return a < b;
2698
+ case TOKEN.le:
2699
+ return a <= b;
2700
+ case TOKEN.and:
2701
+ return typeof a === "boolean" ? a && b : a & b | 0;
2702
+ case TOKEN.or:
2703
+ return typeof a === "boolean" ? a || b : a | b | 0;
2704
+ case TOKEN.xor:
2705
+ return typeof a === "boolean" ? a !== b : a ^ b | 0;
2706
+ case TOKEN.bitshift:
2707
+ return b >= 0 ? a << b | 0 : a >> -b | 0;
2708
+ case TOKEN.min:
2709
+ return Math.min(a, b);
2710
+ case TOKEN.max:
2711
+ return Math.max(a, b);
2712
+ default:
2713
+ return void 0;
2714
+ }
2715
+ }
2716
+ function _evalUnaryConst(op, v) {
2717
+ switch (op) {
2718
+ case TOKEN.abs:
2719
+ return Math.abs(v);
2720
+ case TOKEN.neg:
2721
+ return -v;
2722
+ case TOKEN.ceiling:
2723
+ return Math.ceil(v);
2724
+ case TOKEN.floor:
2725
+ return Math.floor(v);
2726
+ case TOKEN.round:
2727
+ return Math.round(v);
2728
+ case TOKEN.truncate:
2729
+ return Math.trunc(v);
2730
+ case TOKEN.sqrt: {
2731
+ const r = Math.sqrt(v);
2732
+ return Number.isFinite(r) ? r : void 0;
2733
+ }
2734
+ case TOKEN.sin:
2735
+ return Math.sin(v % 360 * Math.PI / 180);
2736
+ case TOKEN.cos:
2737
+ return Math.cos(v % 360 * Math.PI / 180);
2738
+ case TOKEN.ln: {
2739
+ const r = Math.log(v);
2740
+ return Number.isFinite(r) ? r : void 0;
2741
+ }
2742
+ case TOKEN.log: {
2743
+ const r = Math.log10(v);
2744
+ return Number.isFinite(r) ? r : void 0;
2745
+ }
2746
+ case TOKEN.cvi:
2747
+ return Math.trunc(v);
2748
+ case TOKEN.cvr:
2749
+ return v;
2750
+ case TOKEN.not:
2751
+ return typeof v === "boolean" ? !v : ~v;
2752
+ default:
2753
+ return void 0;
2754
+ }
2755
+ }
2756
+ function _unaryValueType(op, operandType) {
2757
+ return op === TOKEN.not ? operandType : PS_VALUE_TYPE.numeric;
2758
+ }
2759
+ function _binaryValueType(op, firstType, secondType) {
2760
+ switch (op) {
2761
+ // Comparison operators always produce a boolean.
2762
+ case TOKEN.eq:
2763
+ case TOKEN.ne:
2764
+ case TOKEN.gt:
2765
+ case TOKEN.ge:
2766
+ case TOKEN.lt:
2767
+ case TOKEN.le:
2768
+ return PS_VALUE_TYPE.boolean;
2769
+ // and / or / xor preserve the type when both operands are the same known
2770
+ // type (both boolean or both numeric); otherwise the type is unknown.
2771
+ case TOKEN.and:
2772
+ case TOKEN.or:
2773
+ case TOKEN.xor:
2774
+ return firstType === secondType && firstType !== PS_VALUE_TYPE.unknown ? firstType : PS_VALUE_TYPE.unknown;
2775
+ // All arithmetic / bitshift operators produce a numeric result.
2776
+ default:
2777
+ return PS_VALUE_TYPE.numeric;
2778
+ }
2779
+ }
2780
+ function buildPostScriptJsFunction(source, domain, range, forceInterpreter = false) {
2781
+ const program = parsePostScriptFunction(source);
2782
+ const ir = !forceInterpreter && new PsJsCompiler(domain, range).compile(program);
2783
+ if (ir) {
2784
+ return (src, srcOffset, dest, destOffset) => {
2785
+ PsJsCompiler.execute(ir, src, srcOffset, dest, destOffset);
2786
+ };
2787
+ }
2788
+ return PSStackBasedInterpreter.build(program, domain, range);
2789
+ }
2598
2790
  function encodeFlate(bytes) {
2599
2791
  return deflate(bytes);
2600
2792
  }
@@ -9629,6 +9821,24 @@ function initializeTile(context, tileIndex) {
9629
9821
  }
9630
9822
  tile.codingStyleDefaultParameters = context.currentTile.COD;
9631
9823
  }
9824
+ function createCalibratedColorSpace(doc, family, parameters) {
9825
+ const dict = doc.resolveDict(parameters);
9826
+ const array = (key) => {
9827
+ const value = dict ? doc.resolveArray(dictGet(dict, key)) : void 0;
9828
+ return value?.items.map((item) => {
9829
+ const number = doc.resolve(item);
9830
+ return number?.kind === "number" ? number.value : 0;
9831
+ });
9832
+ };
9833
+ const whitePoint = array("WhitePoint") ?? [0.95047, 1, 1.08883];
9834
+ const blackPoint = array("BlackPoint");
9835
+ if (family === "CalGray") {
9836
+ const gamma = dict ? doc.resolve(dictGet(dict, "Gamma")) : void 0;
9837
+ return new CalGrayCS(whitePoint, blackPoint, gamma?.kind === "number" ? gamma.value : void 0);
9838
+ }
9839
+ if (family === "CalRGB") return new CalRGBCS(whitePoint, blackPoint, array("Gamma"), array("Matrix"));
9840
+ return new LabCS(whitePoint, blackPoint, array("Range"));
9841
+ }
9632
9842
  function resolveColorSpaceInfo(doc, csNode, resourcesDict) {
9633
9843
  if (!csNode) return { colorSpace: "rgb", colorSpaceLabel: "rgb", components: 3 };
9634
9844
  const resolved = doc.resolve(csNode);
@@ -9669,7 +9879,7 @@ function resolveColorSpaceInfo(doc, csNode, resourcesDict) {
9669
9879
  palette = lookupNode.bytes;
9670
9880
  }
9671
9881
  let resolvedBaseComp = baseInfo.components;
9672
- if (palette && (baseInfo.isLab || baseInfo.isSeparation || baseInfo.isDeviceN || baseInfo.calRgbGamma !== void 0 || baseInfo.calGrayGamma !== void 0)) {
9882
+ if (palette && (baseInfo.isSeparation || baseInfo.isDeviceN || baseInfo.calibrated !== void 0)) {
9673
9883
  const numEntries = Math.max(1, Math.min(hival + 1, Math.floor(palette.length / Math.max(1, baseInfo.components))));
9674
9884
  const rgbaPal = decodeSamplesToRgba(palette, numEntries, 1, 8, baseInfo);
9675
9885
  const rgbPal = new Uint8Array(numEntries * 3);
@@ -9699,74 +9909,21 @@ function resolveColorSpaceInfo(doc, csNode, resourcesDict) {
9699
9909
  }
9700
9910
  return { colorSpace: "rgb", colorSpaceLabel: "icc", components: 3 };
9701
9911
  }
9702
- if (kindName === "CalGray") {
9703
- const calDict = doc.resolveDict(resolved.items[1]);
9704
- const gammaNode = calDict ? doc.resolve(dictGet(calDict, "Gamma")) : void 0;
9705
- const gamma = gammaNode?.kind === "number" && gammaNode.value > 0 ? gammaNode.value : 1;
9706
- return { colorSpace: "gray", colorSpaceLabel: "cal-gray", components: 1, calGrayGamma: gamma };
9707
- }
9708
- if (kindName === "CalRGB") {
9709
- const calDict = doc.resolveDict(resolved.items[1]);
9710
- const gammaArr = calDict ? doc.resolveArray(dictGet(calDict, "Gamma")) : void 0;
9711
- let calRgbGamma = [1, 1, 1];
9712
- if (gammaArr && gammaArr.items.length >= 3) {
9713
- const gNums = gammaArr.items.slice(0, 3).map((it) => {
9714
- const r = doc.resolve(it);
9715
- return r?.kind === "number" && r.value > 0 ? r.value : 1;
9716
- });
9717
- calRgbGamma = [gNums[0], gNums[1], gNums[2]];
9718
- }
9719
- const matArr = calDict ? doc.resolveArray(dictGet(calDict, "Matrix")) : void 0;
9720
- let calRgbMatrix;
9721
- if (matArr && matArr.items.length >= 9) {
9722
- calRgbMatrix = matArr.items.slice(0, 9).map((it) => {
9723
- const r = doc.resolve(it);
9724
- return r?.kind === "number" ? r.value : 0;
9725
- });
9726
- }
9912
+ if (kindName === "CalGray" || kindName === "CalRGB" || kindName === "Lab") {
9913
+ const calibrated = createCalibratedColorSpace(doc, kindName, resolved.items[1]);
9727
9914
  return {
9728
- colorSpace: "rgb",
9729
- colorSpaceLabel: "cal-rgb",
9730
- components: 3,
9731
- calRgbGamma,
9732
- calRgbMatrix
9915
+ colorSpace: kindName === "CalGray" ? "gray" : "rgb",
9916
+ colorSpaceLabel: kindName === "CalGray" ? "cal-gray" : kindName === "CalRGB" ? "cal-rgb" : "lab",
9917
+ components: kindName === "CalGray" ? 1 : 3,
9918
+ calibrated
9733
9919
  };
9734
9920
  }
9735
- if (kindName === "Lab") {
9736
- const labDict = doc.resolveDict(resolved.items[1]);
9737
- const rangeArr = labDict ? doc.resolveArray(dictGet(labDict, "Range")) : void 0;
9738
- let labRange = [-100, 100, -100, 100];
9739
- if (rangeArr && rangeArr.items.length >= 4) {
9740
- const nums = rangeArr.items.slice(0, 4).map((it) => {
9741
- const r = doc.resolve(it);
9742
- return r?.kind === "number" ? r.value : 0;
9743
- });
9744
- labRange = [nums[0], nums[1], nums[2], nums[3]];
9745
- }
9746
- return { colorSpace: "rgb", colorSpaceLabel: "lab", components: 3, isLab: true, labRange };
9747
- }
9748
9921
  if (kindName === "Separation" || kindName === "DeviceN") {
9749
9922
  const isDevN = kindName === "DeviceN";
9750
9923
  const namesArr = isDevN ? doc.resolveArray(resolved.items[1]) : void 0;
9751
9924
  const devNComponents = isDevN && namesArr ? Math.max(1, namesArr.items.length) : 1;
9752
9925
  const altInfo = resolveColorSpaceInfo(doc, resolved.items[2], resourcesDict);
9753
9926
  const altSpace = altInfo.colorSpace === "cmyk" ? "cmyk" : altInfo.colorSpace === "gray" ? "gray" : "rgb";
9754
- const fnResolved = doc.resolve(resolved.items[3]);
9755
- const fnDict = fnResolved?.kind === "stream" ? fnResolved.dict : fnResolved?.kind === "dict" ? fnResolved : void 0;
9756
- const ftNode = fnDict ? doc.resolve(dictGet(fnDict, "FunctionType")) : void 0;
9757
- const tintFunctionType = ftNode?.kind === "number" ? ftNode.value : 2;
9758
- const c0Arr = fnDict ? doc.resolveArray(dictGet(fnDict, "C0")) : void 0;
9759
- const c1Arr = fnDict ? doc.resolveArray(dictGet(fnDict, "C1")) : void 0;
9760
- const nNode = fnDict ? doc.resolve(dictGet(fnDict, "N")) : void 0;
9761
- const c0 = c0Arr ? c0Arr.items.map((it) => {
9762
- const r = doc.resolve(it);
9763
- return r?.kind === "number" ? r.value : 0;
9764
- }) : altSpace === "cmyk" ? [0, 0, 0, 0] : altSpace === "gray" ? [1] : [1, 1, 1];
9765
- const c1 = c1Arr ? c1Arr.items.map((it) => {
9766
- const r = doc.resolve(it);
9767
- return r?.kind === "number" ? r.value : 0;
9768
- }) : altSpace === "cmyk" ? [0, 0, 0, 1] : altSpace === "gray" ? [0] : [0, 0, 0];
9769
- const sepN = nNode?.kind === "number" && nNode.value > 0 ? nNode.value : 1;
9770
9927
  return {
9771
9928
  colorSpace: altSpace,
9772
9929
  colorSpaceLabel: isDevN ? "devn" : "sep",
@@ -9774,12 +9931,9 @@ function resolveColorSpaceInfo(doc, csNode, resourcesDict) {
9774
9931
  isSeparation: !isDevN,
9775
9932
  isDeviceN: isDevN,
9776
9933
  separationAltSpace: altSpace,
9777
- separationC0: c0,
9778
- separationC1: c1,
9779
- separationN: sepN,
9934
+ alternateCalibrated: altInfo.calibrated,
9780
9935
  tintFunctionDoc: doc,
9781
- tintFunctionNode: resolved.items[3],
9782
- tintFunctionType
9936
+ tintFunctionNode: resolved.items[3]
9783
9937
  };
9784
9938
  }
9785
9939
  }
@@ -9929,141 +10083,55 @@ function decodeSamplesToRgba(rawSamples, width, height, bpc, csInfo, alphaSample
9929
10083
  const rgba = new Uint8Array(width * height * 4);
9930
10084
  const pixelCount = width * height;
9931
10085
  if (csInfo.isSeparation || csInfo.isDeviceN) {
9932
- const c0 = csInfo.separationC0 ?? [1, 1, 1];
9933
- const c1 = csInfo.separationC1 ?? [0, 0, 0];
9934
- const expN = csInfo.separationN ?? 1;
9935
10086
  const alt = csInfo.separationAltSpace ?? "rgb";
9936
10087
  const numCh = Math.max(1, csInfo.components);
9937
10088
  const step = bpc === 16 ? 2 : 1;
9938
- const useGenericTintFn = csInfo.tintFunctionDoc !== void 0 && csInfo.tintFunctionNode !== void 0 && (csInfo.tintFunctionType === 0 || csInfo.tintFunctionType === 3 || csInfo.tintFunctionType === 4);
9939
10089
  for (let p = 0; p < pixelCount; p++) {
9940
10090
  const chVals = [];
9941
- let wSum = 0;
9942
10091
  for (let ch3 = 0; ch3 < numCh; ch3++) {
9943
10092
  const sRaw = (rawSamples[(p * numCh + ch3) * step] ?? 0) / 255;
9944
- const tRemapped = remapUnitSampleWithDecode(sRaw, ch3, decodePairs);
9945
- chVals.push(tRemapped);
9946
- wSum += Math.pow(Math.max(0, Math.min(1, tRemapped)), expN);
9947
- }
9948
- if (useGenericTintFn) {
9949
- const outComps = evalShadingFunctionToComponents(
9950
- csInfo.tintFunctionDoc,
9951
- csInfo.tintFunctionNode,
9952
- chVals
9953
- );
9954
- if (alt === "cmyk") {
9955
- const c = outComps[0] ?? 0;
9956
- const m = outComps[1] ?? 0;
9957
- const y = outComps[2] ?? 0;
9958
- const k = outComps[3] ?? 0;
9959
- rgba[p * 4] = Math.round(Math.max(0, Math.min(1, (1 - c) * (1 - k))) * 255);
9960
- rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, (1 - m) * (1 - k))) * 255);
9961
- rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, (1 - y) * (1 - k))) * 255);
9962
- } else if (alt === "gray") {
9963
- const gByte = Math.round(Math.max(0, Math.min(1, outComps[0] ?? 0)) * 255);
9964
- rgba[p * 4] = gByte;
9965
- rgba[p * 4 + 1] = gByte;
9966
- rgba[p * 4 + 2] = gByte;
9967
- } else {
9968
- rgba[p * 4] = Math.round(Math.max(0, Math.min(1, outComps[0] ?? 0)) * 255);
9969
- rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, outComps[1] ?? 0)) * 255);
9970
- rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, outComps[2] ?? 0)) * 255);
9971
- }
9972
- rgba[p * 4 + 3] = 255;
9973
- continue;
10093
+ chVals.push(remapUnitSampleWithDecode(sRaw, ch3, decodePairs));
9974
10094
  }
9975
- const w = Math.max(0, Math.min(1, wSum));
9976
- if (alt === "cmyk") {
9977
- const c = (c0[0] ?? 0) + w * ((c1[0] ?? 0) - (c0[0] ?? 0));
9978
- const m = (c0[1] ?? 0) + w * ((c1[1] ?? 0) - (c0[1] ?? 0));
9979
- const y = (c0[2] ?? 0) + w * ((c1[2] ?? 0) - (c0[2] ?? 0));
9980
- const k = (c0[3] ?? 0) + w * ((c1[3] ?? 1) - (c0[3] ?? 0));
9981
- rgba[p * 4] = Math.round(Math.max(0, Math.min(1, (1 - c) * (1 - k))) * 255);
9982
- rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, (1 - m) * (1 - k))) * 255);
9983
- rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, (1 - y) * (1 - k))) * 255);
10095
+ const outComps = evalShadingFunctionToComponents(
10096
+ csInfo.tintFunctionDoc,
10097
+ csInfo.tintFunctionNode,
10098
+ chVals
10099
+ );
10100
+ if (csInfo.alternateCalibrated) {
10101
+ rgba.set(csInfo.alternateCalibrated.getRgb(outComps, 0), p * 4);
10102
+ } else if (alt === "cmyk") {
10103
+ rgba.set(cmykColorSpace.getRgb([outComps[0] ?? 0, outComps[1] ?? 0, outComps[2] ?? 0, outComps[3] ?? 0], 0), p * 4);
9984
10104
  } else if (alt === "gray") {
9985
- const gVal = (c0[0] ?? 1) + w * ((c1[0] ?? 0) - (c0[0] ?? 1));
9986
- const gByte = Math.round(Math.max(0, Math.min(1, gVal)) * 255);
10105
+ const gByte = Math.round(Math.max(0, Math.min(1, outComps[0] ?? 0)) * 255);
9987
10106
  rgba[p * 4] = gByte;
9988
10107
  rgba[p * 4 + 1] = gByte;
9989
10108
  rgba[p * 4 + 2] = gByte;
9990
10109
  } else {
9991
- const rVal = (c0[0] ?? 1) + w * ((c1[0] ?? 0) - (c0[0] ?? 1));
9992
- const gVal = (c0[1] ?? 1) + w * ((c1[1] ?? 0) - (c0[1] ?? 1));
9993
- const bVal = (c0[2] ?? 1) + w * ((c1[2] ?? 0) - (c0[2] ?? 1));
9994
- rgba[p * 4] = Math.round(Math.max(0, Math.min(1, rVal)) * 255);
9995
- rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, gVal)) * 255);
9996
- rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, bVal)) * 255);
10110
+ rgba[p * 4] = Math.round(Math.max(0, Math.min(1, outComps[0] ?? 0)) * 255);
10111
+ rgba[p * 4 + 1] = Math.round(Math.max(0, Math.min(1, outComps[1] ?? 0)) * 255);
10112
+ rgba[p * 4 + 2] = Math.round(Math.max(0, Math.min(1, outComps[2] ?? 0)) * 255);
9997
10113
  }
9998
10114
  rgba[p * 4 + 3] = 255;
9999
10115
  }
10000
- } else if (csInfo.isLab) {
10001
- const [amin, amax, bmin, bmax] = csInfo.labRange ?? [-100, 100, -100, 100];
10002
- const invF = (t) => t > 6 / 29 ? t * t * t : 3 * (6 / 29) * (6 / 29) * (t - 4 / 29);
10003
- const toSrgb = (u) => {
10004
- const c = u <= 31308e-7 ? 12.92 * u : 1.055 * Math.pow(u, 1 / 2.4) - 0.055;
10005
- return Math.round(Math.max(0, Math.min(1, c)) * 255);
10006
- };
10116
+ } else if (csInfo.calibrated?.name === "Lab") {
10117
+ const { amin, amax, bmin, bmax } = csInfo.calibrated;
10118
+ const step = bpc === 16 ? 2 : 1;
10007
10119
  for (let p = 0; p < pixelCount; p++) {
10008
- const s0 = (rawSamples[p * 3] ?? 0) / 255;
10009
- const s1 = (rawSamples[p * 3 + 1] ?? 128) / 255;
10010
- const s2 = (rawSamples[p * 3 + 2] ?? 128) / 255;
10011
- const L = s0 * 100;
10012
- if (L <= 0.01) {
10013
- rgba[p * 4] = 0;
10014
- rgba[p * 4 + 1] = 0;
10015
- rgba[p * 4 + 2] = 0;
10016
- rgba[p * 4 + 3] = 255;
10017
- continue;
10018
- }
10019
- const a = amin + s1 * (amax - amin);
10020
- const b = bmin + s2 * (bmax - bmin);
10021
- const fy = (L + 16) / 116;
10022
- const fx = fy + a / 500;
10023
- const fz = fy - b / 200;
10024
- const X = 0.95047 * invF(fx);
10025
- const Y = 1 * invF(fy);
10026
- const Z = 1.08883 * invF(fz);
10027
- const linR = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
10028
- const linG = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
10029
- const linB = X * 0.0557 + Y * -0.204 + Z * 1.057;
10030
- rgba[p * 4] = toSrgb(linR);
10031
- rgba[p * 4 + 1] = toSrgb(linG);
10032
- rgba[p * 4 + 2] = toSrgb(linB);
10120
+ const L = (rawSamples[p * 3 * step] ?? 0) / 255 * 100;
10121
+ const a = amin + (rawSamples[(p * 3 + 1) * step] ?? 128) / 255 * (amax - amin);
10122
+ const b = bmin + (rawSamples[(p * 3 + 2) * step] ?? 128) / 255 * (bmax - bmin);
10123
+ rgba.set(csInfo.calibrated.getRgb([L, a, b], 0), p * 4);
10033
10124
  rgba[p * 4 + 3] = 255;
10034
10125
  }
10035
10126
  } else if (csInfo.colorSpace === "rgb") {
10036
- const hasCalRgb = Boolean(csInfo.calRgbGamma || csInfo.calRgbMatrix);
10037
- const toSrgbByte = (u) => {
10038
- const c = u <= 31308e-7 ? 12.92 * u : 1.055 * Math.pow(u, 1 / 2.4) - 0.055;
10039
- return Math.round(Math.max(0, Math.min(1, c)) * 255);
10040
- };
10041
10127
  const writeRgbPixel = (p, rByte, gByte, bByte) => {
10042
- let rU = remapUnitSampleWithDecode(rByte / 255, 0, decodePairs);
10043
- let gU = remapUnitSampleWithDecode(gByte / 255, 1, decodePairs);
10044
- let bU = remapUnitSampleWithDecode(bByte / 255, 2, decodePairs);
10045
- if (hasCalRgb) {
10046
- const [gr, gg, gb] = csInfo.calRgbGamma ?? [1, 1, 1];
10047
- const ag = Math.pow(rU, gr);
10048
- const bg = Math.pow(gU, gg);
10049
- const cg = Math.pow(bU, gb);
10050
- if (csInfo.calRgbMatrix && csInfo.calRgbMatrix.length >= 9) {
10051
- const m = csInfo.calRgbMatrix;
10052
- const X = m[0] * ag + m[3] * bg + m[6] * cg;
10053
- const Y = m[1] * ag + m[4] * bg + m[7] * cg;
10054
- const Z = m[2] * ag + m[5] * bg + m[8] * cg;
10055
- const linR = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
10056
- const linG = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
10057
- const linB = X * 0.0557 + Y * -0.204 + Z * 1.057;
10058
- rgba[p * 4] = toSrgbByte(linR);
10059
- rgba[p * 4 + 1] = toSrgbByte(linG);
10060
- rgba[p * 4 + 2] = toSrgbByte(linB);
10061
- rgba[p * 4 + 3] = 255;
10062
- return;
10063
- }
10064
- rU = ag;
10065
- gU = bg;
10066
- bU = cg;
10128
+ const rU = remapUnitSampleWithDecode(rByte / 255, 0, decodePairs);
10129
+ const gU = remapUnitSampleWithDecode(gByte / 255, 1, decodePairs);
10130
+ const bU = remapUnitSampleWithDecode(bByte / 255, 2, decodePairs);
10131
+ if (csInfo.calibrated) {
10132
+ rgba.set(csInfo.calibrated.getRgb([rU, gU, bU], 0), p * 4);
10133
+ rgba[p * 4 + 3] = 255;
10134
+ return;
10067
10135
  }
10068
10136
  rgba[p * 4] = Math.round(rU * 255);
10069
10137
  rgba[p * 4 + 1] = Math.round(gU * 255);
@@ -10083,10 +10151,11 @@ function decodeSamplesToRgba(rawSamples, width, height, bpc, csInfo, alphaSample
10083
10151
  }
10084
10152
  } else if (csInfo.colorSpace === "gray") {
10085
10153
  const writeGrayPixel = (p, gByte) => {
10086
- let gU = remapUnitSampleWithDecode(gByte / 255, 0, decodePairs);
10087
- if (csInfo.calGrayGamma && csInfo.calGrayGamma !== 1) {
10088
- const lin = Math.pow(gU, csInfo.calGrayGamma);
10089
- gU = lin <= 31308e-7 ? 12.92 * lin : 1.055 * Math.pow(lin, 1 / 2.4) - 0.055;
10154
+ const gU = remapUnitSampleWithDecode(gByte / 255, 0, decodePairs);
10155
+ if (csInfo.calibrated) {
10156
+ rgba.set(csInfo.calibrated.getRgb([gU], 0), p * 4);
10157
+ rgba[p * 4 + 3] = 255;
10158
+ return;
10090
10159
  }
10091
10160
  const outG = Math.round(Math.max(0, Math.min(1, gU)) * 255);
10092
10161
  rgba[p * 4] = outG;
@@ -10142,9 +10211,7 @@ function decodeSamplesToRgba(rawSamples, width, height, bpc, csInfo, alphaSample
10142
10211
  const m = remapUnitSampleWithDecode((rawSamples[p * stride + chStep] ?? 0) / 255, 1, decodePairs);
10143
10212
  const y = remapUnitSampleWithDecode((rawSamples[p * stride + chStep * 2] ?? 0) / 255, 2, decodePairs);
10144
10213
  const k = remapUnitSampleWithDecode((rawSamples[p * stride + chStep * 3] ?? 0) / 255, 3, decodePairs);
10145
- rgba[p * 4] = Math.round((1 - c) * (1 - k) * 255);
10146
- rgba[p * 4 + 1] = Math.round((1 - m) * (1 - k) * 255);
10147
- rgba[p * 4 + 2] = Math.round((1 - y) * (1 - k) * 255);
10214
+ rgba.set(cmykColorSpace.getRgb([c, m, y, k], 0), p * 4);
10148
10215
  rgba[p * 4 + 3] = 255;
10149
10216
  }
10150
10217
  } else if (csInfo.colorSpace === "index") {
@@ -10182,9 +10249,7 @@ function decodeSamplesToRgba(rawSamples, width, height, bpc, csInfo, alphaSample
10182
10249
  const m = pal[idx * 4 + 1] / 255;
10183
10250
  const yel = pal[idx * 4 + 2] / 255;
10184
10251
  const k = pal[idx * 4 + 3] / 255;
10185
- rgba[p * 4] = Math.round((1 - c) * (1 - k) * 255);
10186
- rgba[p * 4 + 1] = Math.round((1 - m) * (1 - k) * 255);
10187
- rgba[p * 4 + 2] = Math.round((1 - yel) * (1 - k) * 255);
10252
+ rgba.set(cmykColorSpace.getRgb([c, m, yel, k], 0), p * 4);
10188
10253
  } else {
10189
10254
  rgba[p * 4] = pal[idx * baseComp];
10190
10255
  rgba[p * 4 + 1] = pal[idx * baseComp + 1];
@@ -10655,193 +10720,6 @@ function resolvePageFonts(doc, resourcesDict) {
10655
10720
  }
10656
10721
  return fonts;
10657
10722
  }
10658
- function evaluateType4PostScriptTokens(tokens, initialStack) {
10659
- const stack = [...initialStack];
10660
- const runRange = (start, end) => {
10661
- let i = start;
10662
- while (i < end) {
10663
- const tok = tokens[i];
10664
- if (tok === "{") {
10665
- let depth = 1;
10666
- let j = i + 1;
10667
- while (j < end && depth > 0) {
10668
- if (tokens[j] === "{") depth++;
10669
- else if (tokens[j] === "}") depth--;
10670
- j++;
10671
- }
10672
- const blockStart = i + 1;
10673
- const blockEnd = j - 1;
10674
- if (j < end && tokens[j] === "{") {
10675
- let depth2 = 1;
10676
- let k = j + 1;
10677
- while (k < end && depth2 > 0) {
10678
- if (tokens[k] === "{") depth2++;
10679
- else if (tokens[k] === "}") depth2--;
10680
- k++;
10681
- }
10682
- if (k < end && tokens[k] === "ifelse") {
10683
- const cond = stack.pop() ?? 0;
10684
- if (cond !== 0) runRange(blockStart, blockEnd);
10685
- else runRange(j + 1, k - 1);
10686
- i = k + 1;
10687
- continue;
10688
- }
10689
- }
10690
- if (j < end && tokens[j] === "if") {
10691
- const cond = stack.pop() ?? 0;
10692
- if (cond !== 0) runRange(blockStart, blockEnd);
10693
- i = j + 1;
10694
- continue;
10695
- }
10696
- runRange(blockStart, blockEnd);
10697
- i = j;
10698
- continue;
10699
- }
10700
- if (tok === "}") {
10701
- i++;
10702
- continue;
10703
- }
10704
- const numVal2 = Number(tok);
10705
- if (tok.length > 0 && !Number.isNaN(numVal2)) {
10706
- stack.push(numVal2);
10707
- } else if (tok === "true") {
10708
- stack.push(1);
10709
- } else if (tok === "false") {
10710
- stack.push(0);
10711
- } else if (tok === "add") {
10712
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10713
- stack.push(a + b);
10714
- } else if (tok === "sub") {
10715
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10716
- stack.push(a - b);
10717
- } else if (tok === "mul") {
10718
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10719
- stack.push(a * b);
10720
- } else if (tok === "div") {
10721
- const b = stack.pop() ?? 1, a = stack.pop() ?? 0;
10722
- stack.push(Math.abs(b) > 1e-12 ? a / b : 0);
10723
- } else if (tok === "idiv") {
10724
- const b = stack.pop() ?? 1, a = stack.pop() ?? 0;
10725
- stack.push(Math.abs(b) > 1e-12 ? Math.trunc(a / b) : 0);
10726
- } else if (tok === "mod") {
10727
- const b = stack.pop() ?? 1, a = stack.pop() ?? 0;
10728
- stack.push(Math.abs(b) > 1e-12 ? a % b : 0);
10729
- } else if (tok === "neg") {
10730
- stack.push(-(stack.pop() ?? 0));
10731
- } else if (tok === "abs") {
10732
- stack.push(Math.abs(stack.pop() ?? 0));
10733
- } else if (tok === "ceiling") {
10734
- stack.push(Math.ceil(stack.pop() ?? 0));
10735
- } else if (tok === "floor") {
10736
- stack.push(Math.floor(stack.pop() ?? 0));
10737
- } else if (tok === "round") {
10738
- stack.push(Math.round(stack.pop() ?? 0));
10739
- } else if (tok === "truncate" || tok === "cvi") {
10740
- stack.push(Math.trunc(stack.pop() ?? 0));
10741
- } else if (tok === "sqrt") {
10742
- stack.push(Math.sqrt(Math.max(0, stack.pop() ?? 0)));
10743
- } else if (tok === "sin") {
10744
- stack.push(Math.sin((stack.pop() ?? 0) * Math.PI / 180));
10745
- } else if (tok === "cos") {
10746
- stack.push(Math.cos((stack.pop() ?? 0) * Math.PI / 180));
10747
- } else if (tok === "atan") {
10748
- const dx = stack.pop() ?? 1, dy = stack.pop() ?? 0;
10749
- let deg = Math.atan2(dy, dx) * 180 / Math.PI;
10750
- if (deg < 0) deg += 360;
10751
- stack.push(deg);
10752
- } else if (tok === "exp") {
10753
- const exp = stack.pop() ?? 1, base = stack.pop() ?? 0;
10754
- stack.push(Math.pow(base, exp));
10755
- } else if (tok === "ln") {
10756
- stack.push(Math.log(Math.max(1e-12, stack.pop() ?? 1)));
10757
- } else if (tok === "log") {
10758
- stack.push(Math.log10(Math.max(1e-12, stack.pop() ?? 1)));
10759
- } else if (tok === "dup") {
10760
- if (stack.length > 0) stack.push(stack[stack.length - 1]);
10761
- } else if (tok === "exch") {
10762
- if (stack.length >= 2) {
10763
- const b = stack.pop(), a = stack.pop();
10764
- stack.push(b, a);
10765
- }
10766
- } else if (tok === "pop") {
10767
- stack.pop();
10768
- } else if (tok === "copy") {
10769
- const n = Math.max(0, Math.trunc(stack.pop() ?? 0));
10770
- const slice = stack.slice(Math.max(0, stack.length - n));
10771
- stack.push(...slice);
10772
- } else if (tok === "index") {
10773
- const n = Math.max(0, Math.trunc(stack.pop() ?? 0));
10774
- const idx = stack.length - 1 - n;
10775
- if (idx >= 0 && idx < stack.length) stack.push(stack[idx]);
10776
- } else if (tok === "roll") {
10777
- const jShift = Math.trunc(stack.pop() ?? 0);
10778
- const n = Math.max(0, Math.trunc(stack.pop() ?? 0));
10779
- if (n > 0 && stack.length >= n) {
10780
- const sub = stack.splice(stack.length - n, n);
10781
- const modShift = (jShift % n + n) % n;
10782
- const rolled = [...sub.slice(n - modShift), ...sub.slice(0, n - modShift)];
10783
- stack.push(...rolled);
10784
- }
10785
- } else if (tok === "eq") {
10786
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10787
- stack.push(Math.abs(a - b) < 1e-9 ? 1 : 0);
10788
- } else if (tok === "ne") {
10789
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10790
- stack.push(Math.abs(a - b) >= 1e-9 ? 1 : 0);
10791
- } else if (tok === "gt") {
10792
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10793
- stack.push(a > b ? 1 : 0);
10794
- } else if (tok === "ge") {
10795
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10796
- stack.push(a >= b ? 1 : 0);
10797
- } else if (tok === "lt") {
10798
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10799
- stack.push(a < b ? 1 : 0);
10800
- } else if (tok === "le") {
10801
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10802
- stack.push(a <= b ? 1 : 0);
10803
- } else if (tok === "and") {
10804
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10805
- stack.push(a !== 0 && b !== 0 ? 1 : 0);
10806
- } else if (tok === "or") {
10807
- const b = stack.pop() ?? 0, a = stack.pop() ?? 0;
10808
- stack.push(a !== 0 || b !== 0 ? 1 : 0);
10809
- } else if (tok === "not") {
10810
- const a = stack.pop() ?? 0;
10811
- stack.push(a === 0 ? 1 : 0);
10812
- }
10813
- i++;
10814
- }
10815
- };
10816
- runRange(0, tokens.length);
10817
- return stack;
10818
- }
10819
- function tokenizePostScriptCode(bytes) {
10820
- const tokens = [];
10821
- let cur = "";
10822
- for (let i = 0; i < bytes.length; i++) {
10823
- const ch3 = String.fromCharCode(bytes[i]);
10824
- if (ch3 === "{" || ch3 === "}") {
10825
- if (cur.length > 0) {
10826
- tokens.push(cur);
10827
- cur = "";
10828
- }
10829
- tokens.push(ch3);
10830
- } else if (ch3 === " " || ch3 === " " || ch3 === "\n" || ch3 === "\r") {
10831
- if (cur.length > 0) {
10832
- tokens.push(cur);
10833
- cur = "";
10834
- }
10835
- } else {
10836
- cur += ch3;
10837
- }
10838
- }
10839
- if (cur.length > 0) tokens.push(cur);
10840
- if (tokens[0] === "{" && tokens[tokens.length - 1] === "}") {
10841
- return tokens.slice(1, -1);
10842
- }
10843
- return tokens;
10844
- }
10845
10723
  function evalShadingFunctionToComponents(doc, fnNode, inputs) {
10846
10724
  const inArr = typeof inputs === "number" ? [inputs] : inputs;
10847
10725
  const t = inArr[0] ?? 0;
@@ -10888,35 +10766,50 @@ function evalShadingFunctionToComponents(doc, fnNode, inputs) {
10888
10766
  const decode = getNums("Decode", range);
10889
10767
  const nOut = Math.max(1, Math.floor((decode.length || range.length || 6) / 2));
10890
10768
  const mIn = Math.max(1, size.length);
10891
- let flatGridIndex = 0;
10769
+ const streamBytes = doc.decodeStream(resolved);
10770
+ let vertices = [{ index: 0, weight: 1 }];
10892
10771
  let stride = 1;
10893
10772
  for (let i = 0; i < mIn; i++) {
10894
10773
  const d02 = dom[i * 2] ?? 0;
10895
10774
  const d12 = dom[i * 2 + 1] ?? 1;
10896
- const sMax = Math.max(1, (size[i] ?? 2) - 1);
10775
+ const sMax = Math.max(0, (size[i] ?? 2) - 1);
10897
10776
  const e0 = encode[i * 2] ?? 0;
10898
10777
  const e1 = encode[i * 2 + 1] ?? sMax;
10899
10778
  const x = Math.max(d02, Math.min(d12, inArr[i] ?? 0));
10900
- const u = Math.abs(d12 - d02) > 1e-8 ? (x - d02) / (d12 - d02) : 0;
10901
- const idx = Math.round(Math.max(0, Math.min(sMax, e0 + u * (e1 - e0))));
10902
- flatGridIndex += idx * stride;
10779
+ const u = d12 === d02 ? 0 : (x - d02) / (d12 - d02);
10780
+ const e = Math.max(0, Math.min(sMax, e0 + u * (e1 - e0)));
10781
+ const low = Math.floor(e), fraction = e - low;
10782
+ const next = [];
10783
+ for (const vertex of vertices) {
10784
+ const index = vertex.index + low * stride;
10785
+ if (index * nOut * bps < streamBytes.length * 8) next.push({ index, weight: vertex.weight * (1 - fraction) });
10786
+ if (fraction && (index + stride) * nOut * bps < streamBytes.length * 8) {
10787
+ next.push({ index: index + stride, weight: vertex.weight * fraction });
10788
+ }
10789
+ }
10790
+ vertices = next;
10903
10791
  stride *= size[i] ?? 2;
10904
10792
  }
10905
- const streamBytes = doc.decodeStream(resolved);
10793
+ const maxSample = 2 ** bps - 1;
10794
+ const readSample = (index) => {
10795
+ let bitOffset = index * bps, remaining = bps, value = 0;
10796
+ while (remaining > 0) {
10797
+ const bitInByte = bitOffset % 8;
10798
+ const take = Math.min(remaining, 8 - bitInByte);
10799
+ const byte = streamBytes[Math.floor(bitOffset / 8)] ?? 0;
10800
+ value = value * 2 ** take + (byte >> 8 - bitInByte - take & (1 << take) - 1);
10801
+ bitOffset += take;
10802
+ remaining -= take;
10803
+ }
10804
+ return value / maxSample;
10805
+ };
10906
10806
  const out2 = [];
10907
- const maxSample = bps === 16 ? 65535 : 255;
10908
10807
  for (let j = 0; j < nOut; j++) {
10909
- const sampleIdx = flatGridIndex * nOut + j;
10910
- let rawVal = 0;
10911
- if (bps === 16) {
10912
- rawVal = (streamBytes[sampleIdx * 2] ?? 0) << 8 | (streamBytes[sampleIdx * 2 + 1] ?? 0);
10913
- } else {
10914
- rawVal = streamBytes[sampleIdx] ?? 0;
10915
- }
10916
- const frac = rawVal / maxSample;
10808
+ let value = 0;
10809
+ for (const vertex of vertices) value += readSample(vertex.index * nOut + j) * vertex.weight;
10917
10810
  const dec0 = decode[j * 2] ?? 0;
10918
10811
  const dec1 = decode[j * 2 + 1] ?? 1;
10919
- out2.push(dec0 + frac * (dec1 - dec0));
10812
+ out2.push(dec0 + value * (dec1 - dec0));
10920
10813
  }
10921
10814
  return clampRange(out2);
10922
10815
  }
@@ -10926,34 +10819,40 @@ function evalShadingFunctionToComponents(doc, fnNode, inputs) {
10926
10819
  const d12 = dom[i * 2 + 1] ?? 1;
10927
10820
  return Math.max(d02, Math.min(d12, v));
10928
10821
  });
10929
- const tokens = tokenizePostScriptCode(doc.decodeStream(resolved));
10930
- const stackOut = evaluateType4PostScriptTokens(tokens, clampedInputs);
10931
- return clampRange(stackOut);
10822
+ const source = bytesToString3(doc.decodeStream(resolved));
10823
+ let cached = postScriptFunctions.get(resolved);
10824
+ if (!cached || cached.source !== source || cached.domain.length !== dom.length || cached.domain.some((value, index) => value !== dom[index]) || cached.range.length !== range.length || cached.range.some((value, index) => value !== range[index])) {
10825
+ cached = { source, domain: dom, range, evaluate: buildPostScriptJsFunction(source, dom, range) };
10826
+ postScriptFunctions.set(resolved, cached);
10827
+ }
10828
+ const output = [];
10829
+ cached.evaluate(clampedInputs, 0, output, 0);
10830
+ return output;
10932
10831
  }
10933
10832
  if (ft === 3) {
10934
10833
  const fnsArr = doc.resolveArray(dictGet(fnDict, "Functions"));
10935
10834
  const bounds = getNums("Bounds", []);
10936
10835
  const encode = getNums("Encode", []);
10937
10836
  if (fnsArr && fnsArr.items.length > 0) {
10837
+ const input = Math.max(dom[0] ?? 0, Math.min(dom[1] ?? 1, t));
10938
10838
  let segIdx = 0;
10939
- while (segIdx < bounds.length && t >= bounds[segIdx]) segIdx++;
10839
+ while (segIdx < bounds.length && input >= bounds[segIdx]) segIdx++;
10940
10840
  segIdx = Math.min(fnsArr.items.length - 1, segIdx);
10941
10841
  const b0 = segIdx === 0 ? dom[0] ?? 0 : bounds[segIdx - 1];
10942
10842
  const b1 = segIdx < bounds.length ? bounds[segIdx] : dom[1] ?? 1;
10943
10843
  const e0 = encode[segIdx * 2] ?? 0;
10944
10844
  const e1 = encode[segIdx * 2 + 1] ?? 1;
10945
- const localT = Math.abs(b1 - b0) > 1e-8 ? e0 + (t - b0) / (b1 - b0) * (e1 - e0) : e0;
10946
- return evalShadingFunctionToComponents(doc, fnsArr.items[segIdx], Math.max(0, Math.min(1, localT)));
10845
+ const localT = b1 !== b0 ? e0 + (input - b0) / (b1 - b0) * (e1 - e0) : e0;
10846
+ return clampRange(evalShadingFunctionToComponents(doc, fnsArr.items[segIdx], localT));
10947
10847
  }
10948
10848
  }
10949
- const c0 = getNums("C0", [0, 0, 0]);
10950
- const c1 = getNums("C1", [1, 1, 1]);
10849
+ const c0 = getNums("C0", [0]);
10850
+ const c1 = getNums("C1", [1]);
10951
10851
  const nNode = doc.resolve(dictGet(fnDict, "N"));
10952
- const expN = nNode?.kind === "number" && nNode.value > 0 ? nNode.value : 1;
10852
+ const expN = nNode?.kind === "number" ? nNode.value : 1;
10953
10853
  const d0 = dom[0] ?? 0;
10954
10854
  const d1 = dom[1] ?? 1;
10955
- const normT = Math.abs(d1 - d0) > 1e-8 ? (t - d0) / (d1 - d0) : t;
10956
- const w = Math.pow(Math.max(0, Math.min(1, normT)), expN);
10855
+ const w = Math.pow(Math.max(d0, Math.min(d1, t)), expN);
10957
10856
  const len = Math.max(c0.length, c1.length);
10958
10857
  const out = [];
10959
10858
  for (let i = 0; i < len; i++) {
@@ -10969,30 +10868,14 @@ function shadingComponentsToRgb(csName, comps) {
10969
10868
  return [v, v, v];
10970
10869
  }
10971
10870
  if (csName === "DeviceCMYK" || csName === "CMYK" || comps.length >= 4) {
10972
- const cc = comps[0] ?? 0, cm = comps[1] ?? 0, cy = comps[2] ?? 0, ck = comps[3] ?? 0;
10973
- return [(1 - cc) * (1 - ck), (1 - cm) * (1 - kClamp(ck)), (1 - cy) * (1 - kClamp(ck))];
10871
+ const rgb2 = cmykColorSpace2.getRgb([comps[0] ?? 0, comps[1] ?? 0, comps[2] ?? 0, comps[3] ?? 0], 0);
10872
+ return [rgb2[0] / 255, rgb2[1] / 255, rgb2[2] / 255];
10974
10873
  }
10975
10874
  return [comps[0] ?? 0, comps[1] ?? 0, comps[2] ?? 0];
10976
10875
  }
10977
10876
  function kClamp(v) {
10978
10877
  return Math.max(0, Math.min(1, v));
10979
10878
  }
10980
- function xyzToSrgb(X, Y, Z, Xw = 0.95047, Yw = 1, Zw = 1.08883) {
10981
- const scaleX = Xw > 1e-6 ? 0.95047 / Xw : 1;
10982
- const scaleY = Yw > 1e-6 ? 1 / Yw : 1;
10983
- const scaleZ = Zw > 1e-6 ? 1.08883 / Zw : 1;
10984
- const x = X * scaleX;
10985
- const y = Y * scaleY;
10986
- const z = Z * scaleZ;
10987
- const rl = 3.2404542 * x - 1.5371385 * y - 0.4985314 * z;
10988
- const gl = -0.969266 * x + 1.8760108 * y + 0.041556 * z;
10989
- const bl = 0.0556434 * x - 0.2040259 * y + 1.0572252 * z;
10990
- const toGamma = (u) => {
10991
- const c = Math.max(0, Math.min(1, u));
10992
- return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
10993
- };
10994
- return [toGamma(rl), toGamma(gl), toGamma(bl)];
10995
- }
10996
10879
  function getColorSpaceComponentCount(doc, csNode, activeResources, depth = 0) {
10997
10880
  if (!csNode || depth > 4) return 3;
10998
10881
  const resolved = doc ? doc.resolve(csNode) : csNode;
@@ -11049,63 +10932,10 @@ function convertColorSpaceComponentsToRgb(doc, csNode, csNameFallback, comps, ac
11049
10932
  if (resolved.kind === "array" && resolved.items.length > 0 && doc) {
11050
10933
  const familyNode = doc.resolve(resolved.items[0]);
11051
10934
  const family = familyNode?.kind === "name" ? familyNode.decoded : "";
11052
- if (family === "CalGray") {
11053
- const paramDict = resolved.items[1] ? doc.resolveDict(resolved.items[1]) : void 0;
11054
- const gNode = paramDict ? doc.resolve(dictGet(paramDict, "Gamma")) : void 0;
11055
- const gamma = gNode?.kind === "number" && gNode.value > 0 ? gNode.value : 1;
11056
- const a = Math.pow(kClamp(comps[0] ?? 0), gamma);
11057
- return [a, a, a];
11058
- }
11059
- if (family === "CalRGB") {
11060
- const paramDict = resolved.items[1] ? doc.resolveDict(resolved.items[1]) : void 0;
11061
- const gammaArr = paramDict ? doc.resolveArray(dictGet(paramDict, "Gamma")) : void 0;
11062
- const getArrNum = (arr, idx, fb) => {
11063
- const r = arr && arr.items[idx] ? doc.resolve(arr.items[idx]) : void 0;
11064
- return r?.kind === "number" ? r.value : fb;
11065
- };
11066
- const gr = getArrNum(gammaArr, 0, 1);
11067
- const gg = getArrNum(gammaArr, 1, 1);
11068
- const gb = getArrNum(gammaArr, 2, 1);
11069
- const ag = Math.pow(kClamp(comps[0] ?? 0), gr > 0 ? gr : 1);
11070
- const bg = Math.pow(kClamp(comps[1] ?? 0), gg > 0 ? gg : 1);
11071
- const cg = Math.pow(kClamp(comps[2] ?? 0), gb > 0 ? gb : 1);
11072
- const matArr = paramDict ? doc.resolveArray(dictGet(paramDict, "Matrix")) : void 0;
11073
- if (matArr && matArr.items.length >= 9) {
11074
- const m = (i) => getArrNum(matArr, i, 0);
11075
- const X = m(0) * ag + m(3) * bg + m(6) * cg;
11076
- const Y = m(1) * ag + m(4) * bg + m(7) * cg;
11077
- const Z = m(2) * ag + m(5) * bg + m(8) * cg;
11078
- const wpArr = paramDict ? doc.resolveArray(dictGet(paramDict, "WhitePoint")) : void 0;
11079
- const Xw = getArrNum(wpArr, 0, 0.95047);
11080
- const Yw = getArrNum(wpArr, 1, 1);
11081
- const Zw = getArrNum(wpArr, 2, 1.08883);
11082
- return xyzToSrgb(X, Y, Z, Xw, Yw, Zw);
11083
- }
11084
- return [ag, bg, cg];
11085
- }
11086
- if (family === "Lab") {
11087
- const paramDict = resolved.items[1] ? doc.resolveDict(resolved.items[1]) : void 0;
11088
- const wpArr = paramDict ? doc.resolveArray(dictGet(paramDict, "WhitePoint")) : void 0;
11089
- const rangeArr = paramDict ? doc.resolveArray(dictGet(paramDict, "Range")) : void 0;
11090
- const getNum = (arr, idx, fb) => {
11091
- const r = arr && arr.items[idx] ? doc.resolve(arr.items[idx]) : void 0;
11092
- return r?.kind === "number" ? r.value : fb;
11093
- };
11094
- const Xw = getNum(wpArr, 0, 0.95047);
11095
- const Yw = getNum(wpArr, 1, 1);
11096
- const Zw = getNum(wpArr, 2, 1.08883);
11097
- const amin = getNum(rangeArr, 0, -100);
11098
- const amax = getNum(rangeArr, 1, 100);
11099
- const bmin = getNum(rangeArr, 2, -100);
11100
- const bmax = getNum(rangeArr, 3, 100);
11101
- const Lstar = Math.max(0, Math.min(100, comps[0] ?? 0));
11102
- const astar = Math.max(amin, Math.min(amax, comps[1] ?? 0));
11103
- const bstar = Math.max(bmin, Math.min(bmax, comps[2] ?? 0));
11104
- const M = (Lstar + 16) / 116;
11105
- const L = M + astar / 500;
11106
- const N = M - bstar / 200;
11107
- const gFn = (x) => x >= 6 / 29 ? x * x * x : 108 / 841 * (x - 4 / 29);
11108
- return xyzToSrgb(Xw * gFn(L), Yw * gFn(M), Zw * gFn(N), Xw, Yw, Zw);
10935
+ if (family === "CalGray" || family === "CalRGB" || family === "Lab") {
10936
+ const colorSpace = createCalibratedColorSpace(doc, family, resolved.items[1]);
10937
+ const rgb2 = colorSpace.getRgb(comps, 0);
10938
+ return [rgb2[0] / 255, rgb2[1] / 255, rgb2[2] / 255];
11109
10939
  }
11110
10940
  if (family === "ICCBased" && resolved.items[1]) {
11111
10941
  const iccNode = doc.resolve(resolved.items[1]);
@@ -11756,7 +11586,8 @@ function evaluateContentStreamToDisplayList(params) {
11756
11586
  const shDict = shNode?.kind === "dict" ? shNode : shNode?.kind === "stream" ? shNode.dict : void 0;
11757
11587
  const shStream = shNode?.kind === "stream" ? shNode : void 0;
11758
11588
  if (shDict) {
11759
- const targetBox = st.clipRect ?? [0, 0, params.width, params.height];
11589
+ const [originX, originY] = params.origin ?? [0, 0];
11590
+ const targetBox = st.clipRect ?? [originX, originY, originX + params.width, originY + params.height];
11760
11591
  const img = renderShadingDictToImage(
11761
11592
  params.cosDoc,
11762
11593
  shDict,
@@ -11795,12 +11626,10 @@ function evaluateContentStreamToDisplayList(params) {
11795
11626
  } else if (operator === "RG" || operator === "SC" || operator === "SCN") {
11796
11627
  st.strokeColor = resolveScColorOperands(operator === "RG" ? "DeviceRGB" : st.strokeColorSpaceName, ops, activeResources);
11797
11628
  } else if (operator === "k") {
11798
- const c = num(0), m = num(1), y = num(2), k = num(3);
11799
- st.fillColor = { r: (1 - c) * (1 - k), g: (1 - m) * (1 - k), b: (1 - y) * (1 - k) };
11629
+ st.fillColor = resolveScColorOperands("DeviceCMYK", ops, activeResources);
11800
11630
  st.fillPatternName = void 0;
11801
11631
  } else if (operator === "K") {
11802
- const c = num(0), m = num(1), y = num(2), k = num(3);
11803
- st.strokeColor = { r: (1 - c) * (1 - k), g: (1 - m) * (1 - k), b: (1 - y) * (1 - k) };
11632
+ st.strokeColor = resolveScColorOperands("DeviceCMYK", ops, activeResources);
11804
11633
  } else if (operator === "gs" && params.cosDoc && activeResources && ops[0]?.kind === "name") {
11805
11634
  const extDict = params.cosDoc.resolveDict(dictGet(activeResources, "ExtGState"));
11806
11635
  const gsDict = extDict ? params.cosDoc.resolveDict(dictGet(extDict, ops[0].decoded)) : void 0;
@@ -12009,7 +11838,7 @@ function evaluateContentStreamToDisplayList(params) {
12009
11838
  stateStack.pop();
12010
11839
  capturedOperations = parentOperations;
12011
11840
  }
12012
- if (compositeGroup) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
11841
+ if (compositeGroup) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, isolated, bboxClip: nextClipPaths?.[0], blendMode: st.blendMode, clipRect: st.clipRect } });
12013
11842
  };
12014
11843
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
12015
11844
  for (const node of nodes) {
@@ -12593,6 +12422,7 @@ function evaluateContentStreamToDisplayList(params) {
12593
12422
  pageIndex: params.pageIndex,
12594
12423
  width: params.width,
12595
12424
  height: params.height,
12425
+ ...params.origin ? { origin: params.origin } : {},
12596
12426
  rotation: params.rotation ?? 0,
12597
12427
  glyphs,
12598
12428
  paths,
@@ -14718,7 +14548,7 @@ function prepareStroke(path, scale) {
14718
14548
  }
14719
14549
  return { matrix, width, dashArray, dashPhase };
14720
14550
  }
14721
- function strokeContours(path, pageHeight, scale) {
14551
+ function strokeContours(path, pageHeight, scale, originX = 0, originY = 0) {
14722
14552
  const stroke = prepareStroke(path, scale);
14723
14553
  if (!stroke) return [];
14724
14554
  const inverse = inverseStrokeMatrix(stroke.matrix);
@@ -14730,8 +14560,8 @@ function strokeContours(path, pageHeight, scale) {
14730
14560
  (inverse[1] * x + inverse[3] * y + inverse[5]) * strokeScale
14731
14561
  ];
14732
14562
  const toScreen = ([x, y]) => [
14733
- (a * x / strokeScale + c * y / strokeScale + e) * scale,
14734
- (pageHeight - b * x / strokeScale - d * y / strokeScale - f) * scale
14563
+ (a * x / strokeScale + c * y / strokeScale + e - originX) * scale,
14564
+ (pageHeight + originY - b * x / strokeScale - d * y / strokeScale - f) * scale
14735
14565
  ];
14736
14566
  const contours = strokeOutlines(
14737
14567
  segmentsToScreenPaths(path.segments, pageHeight, scale, project),
@@ -14889,18 +14719,34 @@ function renderSoftMask(mask, displayList, scale) {
14889
14719
  }
14890
14720
  return bitmap;
14891
14721
  }
14892
- function hasBlendModes(operations) {
14893
- return operations.some((operation) => !!operation.value.blendMode && operation.value.blendMode !== "Normal" && operation.value.blendMode !== "Compatible" || operation.kind === "group" && hasBlendModes(operation.value.operations));
14722
+ function getDisplayListCropBox(list) {
14723
+ const full = [0, 0, list.width, list.height];
14724
+ const box = list.cropBox;
14725
+ if (!box || !box.every(Number.isFinite)) return full;
14726
+ const x0 = Math.max(0, Math.min(box[0], box[2]));
14727
+ const y0 = Math.max(0, Math.min(box[1], box[3]));
14728
+ const x1 = Math.min(list.width, Math.max(box[0], box[2]));
14729
+ const y1 = Math.min(list.height, Math.max(box[1], box[3]));
14730
+ return x1 > x0 && y1 > y0 ? [x0, y0, x1, y1] : full;
14731
+ }
14732
+ function hasCompositingEffects(operations, includeSoftMasks = false) {
14733
+ return operations.some((operation) => includeSoftMasks && !!operation.value.softMask || !!operation.value.blendMode && operation.value.blendMode !== "Normal" && operation.value.blendMode !== "Compatible" || operation.kind === "group" && hasCompositingEffects(operation.value.operations, includeSoftMasks));
14734
+ }
14735
+ function needsGroupBackdrop(group) {
14736
+ return group.isolated === false && !!group.softMask && hasCompositingEffects(group.operations, true);
14894
14737
  }
14895
14738
  function renderDisplayListToBitmap(displayList, options = {}) {
14896
14739
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
14897
14740
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
14898
14741
  const scaleY = options.dpiY !== void 0 ? options.dpiY / 72 : baseScale;
14899
14742
  const scale = scaleX;
14743
+ const [originX, originY] = displayList.origin ?? [0, 0];
14744
+ const pageTop = originY + displayList.height;
14745
+ const toScreen = (x, y) => [(x - originX) * scale, (pageTop - y) * scale];
14900
14746
  const width = Math.max(1, Math.round(displayList.width * scale));
14901
14747
  const height = Math.max(1, Math.round(displayList.height * scale));
14902
14748
  const rgba = new Uint8Array(width * height * 4);
14903
- const deferBackground = !options.transparent && hasBlendModes(paintOperations(displayList));
14749
+ const deferBackground = !options.transparent && hasCompositingEffects(paintOperations(displayList));
14904
14750
  const transparent = options.transparent || deferBackground;
14905
14751
  const bg = options.background ?? { r: 1, g: 1, b: 1 };
14906
14752
  const bgR = transparent ? 0 : Math.round(bg.r * 255);
@@ -14925,14 +14771,27 @@ function renderDisplayListToBitmap(displayList, options = {}) {
14925
14771
  let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
14926
14772
  if (operation.kind === "group") {
14927
14773
  const group = operation.value;
14928
- const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
14774
+ let operations = group.operations;
14775
+ if (needsGroupBackdrop(group)) {
14776
+ operations = [{ kind: "image", value: {
14777
+ name: "GroupBackdrop",
14778
+ width,
14779
+ height,
14780
+ decodedRgba: rgba.slice(),
14781
+ matrix: [width / scale, 0, 0, height / scale, originX, pageTop - height / scale],
14782
+ colorSpace: "DeviceRGB",
14783
+ bitsPerComponent: 8,
14784
+ ...group.bboxClip ? { clipPaths: [group.bboxClip] } : {}
14785
+ } }, ...operations];
14786
+ }
14787
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, useCropBox: false, transparent: true });
14929
14788
  for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
14930
14789
  operation = { kind: "image", value: {
14931
14790
  name: "TransparencyGroup",
14932
14791
  width: bitmap.width,
14933
14792
  height: bitmap.height,
14934
14793
  decodedRgba: bitmap.data,
14935
- matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
14794
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, originX, pageTop - bitmap.height / scale],
14936
14795
  colorSpace: "DeviceRGB",
14937
14796
  bitsPerComponent: 8,
14938
14797
  blendMode: group.blendMode,
@@ -14946,7 +14805,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
14946
14805
  for (const clip of clips) {
14947
14806
  const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
14948
14807
  const layer = new Uint8Array(width * height * 4);
14949
- fillEdgesScanline4x4(layer, width, height, pathsToEdges(segmentsToScreenPaths(segments, displayList.height, scale), true), { r: 1, g: 1, b: 1 }, 1, fillRule);
14808
+ fillEdgesScanline4x4(layer, width, height, pathsToEdges(segmentsToScreenPaths(segments, displayList.height, scale, toScreen), true), { r: 1, g: 1, b: 1 }, 1, fillRule);
14950
14809
  for (let i = 3; i < layer.length; i += 4) clipMask[i] = Math.round(clipMask[i] * layer[i] / 255);
14951
14810
  }
14952
14811
  cachedClips = clips;
@@ -14993,15 +14852,15 @@ function renderDisplayListToBitmap(displayList, options = {}) {
14993
14852
  if (operation.kind === "path") {
14994
14853
  const path = operation.value;
14995
14854
  if (path.fillColor) {
14996
- const edges = pathsToEdges(segmentsToScreenPaths(path.segments, displayList.height, scale), true);
14997
- const clipScreen = path.clipRect ? [path.clipRect[0] * scale, (displayList.height - path.clipRect[3]) * scale, path.clipRect[2] * scale, (displayList.height - path.clipRect[1]) * scale] : void 0;
14855
+ const edges = pathsToEdges(segmentsToScreenPaths(path.segments, displayList.height, scale, toScreen), true);
14856
+ const clipScreen = path.clipRect ? [(path.clipRect[0] - originX) * scale, (pageTop - path.clipRect[3]) * scale, (path.clipRect[2] - originX) * scale, (pageTop - path.clipRect[1]) * scale] : void 0;
14998
14857
  fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
14999
14858
  }
15000
14859
  if (path.strokeColor) {
15001
14860
  const rawSw = path.strokeWidth * scale * (path.strokeMatrix ? Math.hypot(path.strokeMatrix[0], path.strokeMatrix[1]) : 1);
15002
14861
  const strokeAlpha = options.thinLineMode === "shape" && rawSw < 1 ? (path.strokeAlpha ?? 1) * Math.max(0.25, rawSw) : path.strokeAlpha ?? 1;
15003
- const edges = pathsToEdges(strokeContours(path, displayList.height, scale).map((points) => ({ points, closed: true })));
15004
- const clipScreen = path.clipRect ? [path.clipRect[0] * scale, (displayList.height - path.clipRect[3]) * scale, path.clipRect[2] * scale, (displayList.height - path.clipRect[1]) * scale] : void 0;
14862
+ const edges = pathsToEdges(strokeContours(path, displayList.height, scale, originX, originY).map((points) => ({ points, closed: true })));
14863
+ const clipScreen = path.clipRect ? [(path.clipRect[0] - originX) * scale, (pageTop - path.clipRect[3]) * scale, (path.clipRect[2] - originX) * scale, (pageTop - path.clipRect[1]) * scale] : void 0;
15005
14864
  fillEdgesScanline4x4(
15006
14865
  rgba,
15007
14866
  width,
@@ -15024,12 +14883,12 @@ function renderDisplayListToBitmap(displayList, options = {}) {
15024
14883
  if (Math.abs(det) <= 1e-8) continue;
15025
14884
  const cornersPdfX = [e, a + e, a + c + e, c + e];
15026
14885
  const cornersPdfY = [f, b + f, b + d + f, d + f];
15027
- const cornersPx = cornersPdfX.map((cx) => cx * scale);
15028
- const cornersPy = cornersPdfY.map((cy) => (displayList.height - cy) * scale);
15029
- const clipMinPx = img.clipRect ? Math.floor(img.clipRect[0] * scale) : 0;
15030
- const clipMaxPx = img.clipRect ? Math.ceil(img.clipRect[2] * scale) - 1 : width - 1;
15031
- const clipMinPy = img.clipRect ? Math.floor((displayList.height - img.clipRect[3]) * scale) : 0;
15032
- const clipMaxPy = img.clipRect ? Math.ceil((displayList.height - img.clipRect[1]) * scale) - 1 : height - 1;
14886
+ const cornersPx = cornersPdfX.map((cx) => (cx - originX) * scale);
14887
+ const cornersPy = cornersPdfY.map((cy) => (pageTop - cy) * scale);
14888
+ const clipMinPx = img.clipRect ? Math.floor((img.clipRect[0] - originX) * scale) : 0;
14889
+ const clipMaxPx = img.clipRect ? Math.ceil((img.clipRect[2] - originX) * scale) - 1 : width - 1;
14890
+ const clipMinPy = img.clipRect ? Math.floor((pageTop - img.clipRect[3]) * scale) : 0;
14891
+ const clipMaxPy = img.clipRect ? Math.ceil((pageTop - img.clipRect[1]) * scale) - 1 : height - 1;
15033
14892
  const minPx = Math.max(0, clipMinPx, Math.floor(Math.min(...cornersPx)));
15034
14893
  const maxPx = Math.min(width - 1, clipMaxPx, Math.ceil(Math.max(...cornersPx)) - 1);
15035
14894
  const minPy = Math.max(0, clipMinPy, Math.floor(Math.min(...cornersPy)));
@@ -15046,11 +14905,11 @@ function renderDisplayListToBitmap(displayList, options = {}) {
15046
14905
  const smooth = Math.fround((s1 + s2 + Math.hypot(s1 - s2, 2 * cross)) / 2) <= 1;
15047
14906
  const sample = new Float64Array(4);
15048
14907
  for (let py = minPy; py <= maxPy; py++) {
15049
- const yPdf = displayList.height - (py + 0.5) / scale;
14908
+ const yPdf = pageTop - (py + 0.5) / scale;
15050
14909
  if (img.clipRect && (yPdf < img.clipRect[1] || yPdf > img.clipRect[3])) continue;
15051
14910
  const dyPdf = yPdf - f;
15052
14911
  for (let px = minPx; px <= maxPx; px++) {
15053
- const xPdf = (px + 0.5) / scale;
14912
+ const xPdf = originX + (px + 0.5) / scale;
15054
14913
  if (img.clipRect && (xPdf < img.clipRect[0] || xPdf > img.clipRect[2])) continue;
15055
14914
  const dxPdf = xPdf - e;
15056
14915
  const u = (d * dxPdf - c * dyPdf) / det;
@@ -15111,6 +14970,15 @@ function renderDisplayListToBitmap(displayList, options = {}) {
15111
14970
  }
15112
14971
  result = { width: targetW, height: targetH, data: resampled };
15113
14972
  }
14973
+ if (options.useCropBox) {
14974
+ const box = getDisplayListCropBox(displayList);
14975
+ result = cropRgbaBitmap(result, {
14976
+ x: box[0] * scaleX,
14977
+ y: (displayList.height - box[3]) * scaleY,
14978
+ width: (box[2] - box[0]) * scaleX,
14979
+ height: (box[3] - box[1]) * scaleY
14980
+ });
14981
+ }
15114
14982
  result = rotateRgbaBitmapQuarterTurns(result, displayList.rotation ?? 0);
15115
14983
  if (options.cropRect) {
15116
14984
  result = cropRgbaBitmap(result, options.cropRect);
@@ -15571,6 +15439,36 @@ var fixedDistCodeTab;
15571
15439
  var FlateStream;
15572
15440
  var getMetrics;
15573
15441
  var getFontBasicMetrics;
15442
+ var ColorSpace;
15443
+ var DeviceCmykCS;
15444
+ var CalGrayCS;
15445
+ var CalRGBCS;
15446
+ var LabCS;
15447
+ var TOKEN;
15448
+ var Token;
15449
+ var Lexer;
15450
+ var PS_VALUE_TYPE;
15451
+ var PS_NODE;
15452
+ var PsNode;
15453
+ var PsProgram;
15454
+ var PsBlock;
15455
+ var PsNumber;
15456
+ var PsOperator;
15457
+ var PsIf;
15458
+ var PsIfElse;
15459
+ var PsArgNode;
15460
+ var PsConstNode;
15461
+ var PsUnaryNode;
15462
+ var PsBinaryNode;
15463
+ var PsTernaryNode;
15464
+ var Parser;
15465
+ var MAX_STACK_SIZE;
15466
+ var PSStackToTree;
15467
+ var OP;
15468
+ var _DEG_TO_RAD;
15469
+ var _RAD_TO_DEG;
15470
+ var PsJsCompiler;
15471
+ var PSStackBasedInterpreter;
15574
15472
  var PdfError;
15575
15473
  var DEFAULT_MAX_DECODED_BYTES;
15576
15474
  var BoundedFlateStream;
@@ -15689,6 +15587,9 @@ var __webpack_exports__JpxImage;
15689
15587
  var __webpack_exports__VerbosityLevel;
15690
15588
  var __webpack_exports__getVerbosityLevel;
15691
15589
  var __webpack_exports__setVerbosityLevel;
15590
+ var cmykColorSpace;
15591
+ var cmykColorSpace2;
15592
+ var postScriptFunctions;
15692
15593
  var ACROFORM_FONT_ALIAS_MAP;
15693
15594
  var PdfPage;
15694
15595
  var MAX_STROKE_VERTICES;
@@ -36794,6 +36695,2422 @@ var init_dist = __esm({
36794
36695
  xHeight: Math.NaN
36795
36696
  };
36796
36697
  });
36698
+ ColorSpace = class _ColorSpace {
36699
+ static #rgbBuf = new Uint8ClampedArray(3);
36700
+ constructor(name, numComps) {
36701
+ if ((typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) && this.constructor === _ColorSpace) {
36702
+ unreachable2("Cannot initialize ColorSpace.");
36703
+ }
36704
+ this.name = name;
36705
+ this.numComps = numComps;
36706
+ }
36707
+ /**
36708
+ * Converts the color value to the RGB color. The color components are
36709
+ * located in the src array starting from the srcOffset. Returns the array
36710
+ * of the rgb components, each value ranging from [0,255].
36711
+ */
36712
+ getRgb(src, srcOffset, output = new Uint8ClampedArray(3)) {
36713
+ this.getRgbItem(src, srcOffset, output, 0);
36714
+ return output;
36715
+ }
36716
+ getRgbHex(src, srcOffset) {
36717
+ const buffer = this.getRgb(src, srcOffset, _ColorSpace.#rgbBuf);
36718
+ return Util.makeHexColor(buffer[0], buffer[1], buffer[2]);
36719
+ }
36720
+ /**
36721
+ * Converts the color value to the RGB color, similar to the getRgb method.
36722
+ * The result placed into the dest array starting from the destOffset.
36723
+ */
36724
+ getRgbItem(src, srcOffset, dest, destOffset) {
36725
+ unreachable2("Should not call ColorSpace.getRgbItem");
36726
+ }
36727
+ /**
36728
+ * Converts the specified number of the color values to the RGB colors.
36729
+ * The colors are located in the src array starting from the srcOffset.
36730
+ * The result is placed into the dest array starting from the destOffset.
36731
+ * The src array items shall be in [0,2^bits) range, the dest array items
36732
+ * will be in [0,255] range. alpha01 indicates how many alpha components
36733
+ * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
36734
+ * array).
36735
+ */
36736
+ getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
36737
+ unreachable2("Should not call ColorSpace.getRgbBuffer");
36738
+ }
36739
+ /**
36740
+ * Converts `count` unscaled colors to RGB, starting at `destOffset`.
36741
+ * Components use the native color-space ranges expected by `getRgbItem`,
36742
+ * and each output has a `3 + alpha01` byte stride.
36743
+ * Subclasses may override this to batch expensive conversions.
36744
+ */
36745
+ getRgbItems(src, count, dest, destOffset, alpha01) {
36746
+ const { numComps } = this;
36747
+ for (let i = 0, srcOffset = 0; i < count; i++, srcOffset += numComps) {
36748
+ this.getRgbItem(src, srcOffset, dest, destOffset);
36749
+ destOffset += 3 + alpha01;
36750
+ }
36751
+ }
36752
+ /**
36753
+ * Returns true if source data will be equal the result/output data.
36754
+ */
36755
+ isPassthrough(bits) {
36756
+ return false;
36757
+ }
36758
+ /**
36759
+ * Refer to the static `ColorSpace.isDefaultDecode` method below.
36760
+ */
36761
+ isDefaultDecode(decode, bpc) {
36762
+ return _ColorSpace.isDefaultDecode(decode, this.numComps);
36763
+ }
36764
+ /**
36765
+ * Fills in the RGB colors in the destination buffer. alpha01 indicates
36766
+ * how many alpha components there are in the dest array; it will be either
36767
+ * 0 (RGB array) or 1 (RGBA array).
36768
+ */
36769
+ fillRgb(dest, originalWidth, originalHeight, width, height, actualHeight, bpc, comps, alpha01) {
36770
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
36771
+ assert2(
36772
+ dest instanceof Uint8ClampedArray,
36773
+ 'ColorSpace.fillRgb: Unsupported "dest" type.'
36774
+ );
36775
+ }
36776
+ const count = originalWidth * originalHeight;
36777
+ let rgbBuf = null;
36778
+ const numComponentColors = 1 << bpc;
36779
+ const needsResizing = originalHeight !== height || originalWidth !== width;
36780
+ if (this.isPassthrough(bpc)) {
36781
+ rgbBuf = comps;
36782
+ } else if (this.numComps === 1 && count > numComponentColors && this.name !== "DeviceGray" && this.name !== "DeviceRGB") {
36783
+ const allColors = bpc <= 8 ? new Uint8Array(numComponentColors) : new Uint16Array(numComponentColors);
36784
+ for (let i = 0; i < numComponentColors; i++) {
36785
+ allColors[i] = i;
36786
+ }
36787
+ const colorMap = new Uint8ClampedArray(numComponentColors * 3);
36788
+ this.getRgbBuffer(
36789
+ allColors,
36790
+ 0,
36791
+ numComponentColors,
36792
+ colorMap,
36793
+ 0,
36794
+ bpc,
36795
+ /* alpha01 = */
36796
+ 0
36797
+ );
36798
+ if (!needsResizing) {
36799
+ let destPos = 0;
36800
+ for (let i = 0; i < count; ++i) {
36801
+ const key = comps[i] * 3;
36802
+ dest[destPos++] = colorMap[key];
36803
+ dest[destPos++] = colorMap[key + 1];
36804
+ dest[destPos++] = colorMap[key + 2];
36805
+ destPos += alpha01;
36806
+ }
36807
+ } else {
36808
+ rgbBuf = new Uint8Array(count * 3);
36809
+ let rgbPos = 0;
36810
+ for (let i = 0; i < count; ++i) {
36811
+ const key = comps[i] * 3;
36812
+ rgbBuf[rgbPos++] = colorMap[key];
36813
+ rgbBuf[rgbPos++] = colorMap[key + 1];
36814
+ rgbBuf[rgbPos++] = colorMap[key + 2];
36815
+ }
36816
+ }
36817
+ } else if (!needsResizing) {
36818
+ this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc, alpha01);
36819
+ } else {
36820
+ rgbBuf = new Uint8ClampedArray(count * 3);
36821
+ this.getRgbBuffer(
36822
+ comps,
36823
+ 0,
36824
+ count,
36825
+ rgbBuf,
36826
+ 0,
36827
+ bpc,
36828
+ /* alpha01 = */
36829
+ 0
36830
+ );
36831
+ }
36832
+ if (rgbBuf) {
36833
+ if (needsResizing) {
36834
+ resizeRgbImage(
36835
+ rgbBuf,
36836
+ dest,
36837
+ originalWidth,
36838
+ originalHeight,
36839
+ width,
36840
+ height,
36841
+ alpha01
36842
+ );
36843
+ } else {
36844
+ let destPos = 0, rgbPos = 0;
36845
+ for (let i = 0, ii = width * actualHeight; i < ii; i++) {
36846
+ dest[destPos++] = rgbBuf[rgbPos++];
36847
+ dest[destPos++] = rgbBuf[rgbPos++];
36848
+ dest[destPos++] = rgbBuf[rgbPos++];
36849
+ destPos += alpha01;
36850
+ }
36851
+ }
36852
+ }
36853
+ }
36854
+ /**
36855
+ * True if the colorspace has components in the default range of [0, 1].
36856
+ * This should be true for all colorspaces except for lab color spaces
36857
+ * which are [0,100], [-128, 127], [-128, 127].
36858
+ */
36859
+ get usesZeroToOneRange() {
36860
+ return shadow2(this, "usesZeroToOneRange", true);
36861
+ }
36862
+ /**
36863
+ * Checks if a decode map matches the default decode map for a color space.
36864
+ * This handles the general decode maps where there are two values per
36865
+ * component, e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
36866
+ * This does not handle Lab, Indexed, or Pattern decode maps since they are
36867
+ * slightly different.
36868
+ * @param {Array} decode - Decode map (usually from an image).
36869
+ * @param {number} numComps - Number of components the color space has.
36870
+ */
36871
+ static isDefaultDecode(decode, numComps) {
36872
+ if (isDefaultDecodeHelper(decode, numComps * 2)) {
36873
+ return true;
36874
+ }
36875
+ for (let i = 0, ii = decode.length; i < ii; i += 2) {
36876
+ if (decode[i] !== 0 || decode[i + 1] !== 1) {
36877
+ return false;
36878
+ }
36879
+ }
36880
+ return true;
36881
+ }
36882
+ };
36883
+ DeviceCmykCS = class extends ColorSpace {
36884
+ constructor() {
36885
+ super("DeviceCMYK", 4);
36886
+ }
36887
+ // The coefficients below was found using numerical analysis: the method of
36888
+ // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
36889
+ // where color_value is the tabular value from the table of sampled RGB colors
36890
+ // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
36891
+ // CMYK color conversion using the estimation below:
36892
+ // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
36893
+ #toRgb(src, srcOffset, srcScale, dest, destOffset) {
36894
+ const c = src[srcOffset] * srcScale;
36895
+ const m = src[srcOffset + 1] * srcScale;
36896
+ const y = src[srcOffset + 2] * srcScale;
36897
+ const k = src[srcOffset + 3] * srcScale;
36898
+ dest[destOffset] = 255 + c * (-4.387332384609988 * c + 54.48615194189176 * m + 18.82290502165302 * y + 212.25662451639585 * k + -285.2331026137004) + m * (1.7149763477362134 * m - 5.6096736904047315 * y + -17.873870861415444 * k - 5.497006427196366) + y * (-2.5217340131683033 * y - 21.248923337353073 * k + 17.5119270841813) + k * (-21.86122147463605 * k - 189.48180835922747);
36899
+ dest[destOffset + 1] = 255 + c * (8.841041422036149 * c + 60.118027045597366 * m + 6.871425592049007 * y + 31.159100130055922 * k + -79.2970844816548) + m * (-15.310361306967817 * m + 17.575251261109482 * y + 131.35250912493976 * k - 190.9453302588951) + y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) + k * (-20.737325471181034 * k - 187.80453709719578);
36900
+ dest[destOffset + 2] = 255 + c * (0.8842522430003296 * c + 8.078677503112928 * m + 30.89978309703729 * y - 0.23883238689178934 * k + -14.183576799673286) + m * (10.49593273432072 * m + 63.02378494754052 * y + 50.606957656360734 * k - 112.23884253719248) + y * (0.03296041114873217 * y + 115.60384449646641 * k + -193.58209356861505) + k * (-22.33816807309886 * k - 180.12613974708367);
36901
+ }
36902
+ getRgbItem(src, srcOffset, dest, destOffset) {
36903
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
36904
+ assert2(
36905
+ dest instanceof Uint8ClampedArray,
36906
+ 'DeviceCmykCS.getRgbItem: Unsupported "dest" type.'
36907
+ );
36908
+ }
36909
+ this.#toRgb(src, srcOffset, 1, dest, destOffset);
36910
+ }
36911
+ getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
36912
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
36913
+ assert2(
36914
+ dest instanceof Uint8ClampedArray,
36915
+ 'DeviceCmykCS.getRgbBuffer: Unsupported "dest" type.'
36916
+ );
36917
+ }
36918
+ const scale = 1 / ((1 << bits) - 1);
36919
+ for (let i = 0; i < count; i++) {
36920
+ this.#toRgb(src, srcOffset, scale, dest, destOffset);
36921
+ srcOffset += 4;
36922
+ destOffset += 3 + alpha01;
36923
+ }
36924
+ }
36925
+ };
36926
+ CalGrayCS = class extends ColorSpace {
36927
+ constructor(whitePoint, blackPoint, gamma) {
36928
+ super("CalGray", 1);
36929
+ if (!whitePoint) {
36930
+ throw new FormatError(
36931
+ "WhitePoint missing - required for color space CalGray"
36932
+ );
36933
+ }
36934
+ [this.XW, this.YW, this.ZW] = whitePoint;
36935
+ [this.XB, this.YB, this.ZB] = blackPoint || [0, 0, 0];
36936
+ this.G = gamma || 1;
36937
+ if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
36938
+ throw new FormatError(
36939
+ `Invalid WhitePoint components for ${this.name}, no fallback available`
36940
+ );
36941
+ }
36942
+ if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
36943
+ info(`Invalid BlackPoint for ${this.name}, falling back to default.`);
36944
+ this.XB = this.YB = this.ZB = 0;
36945
+ }
36946
+ if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
36947
+ warn2(
36948
+ `${this.name}, BlackPoint: XB: ${this.XB}, YB: ${this.YB}, ZB: ${this.ZB}, only default values are supported.`
36949
+ );
36950
+ }
36951
+ if (this.G < 1) {
36952
+ info(
36953
+ `Invalid Gamma: ${this.G} for ${this.name}, falling back to default.`
36954
+ );
36955
+ this.G = 1;
36956
+ }
36957
+ }
36958
+ #toRgb(src, srcOffset, dest, destOffset, scale) {
36959
+ const A = src[srcOffset] * scale;
36960
+ const AG = A ** this.G;
36961
+ const L = this.YW * AG;
36962
+ const val = Math.max(295.8 * L ** 0.3333333333333333 - 40.8, 0);
36963
+ dest[destOffset] = val;
36964
+ dest[destOffset + 1] = val;
36965
+ dest[destOffset + 2] = val;
36966
+ }
36967
+ getRgbItem(src, srcOffset, dest, destOffset) {
36968
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
36969
+ assert2(
36970
+ dest instanceof Uint8ClampedArray,
36971
+ 'CalGrayCS.getRgbItem: Unsupported "dest" type.'
36972
+ );
36973
+ }
36974
+ this.#toRgb(src, srcOffset, dest, destOffset, 1);
36975
+ }
36976
+ getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
36977
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
36978
+ assert2(
36979
+ dest instanceof Uint8ClampedArray,
36980
+ 'CalGrayCS.getRgbBuffer: Unsupported "dest" type.'
36981
+ );
36982
+ }
36983
+ const scale = 1 / ((1 << bits) - 1);
36984
+ for (let i = 0; i < count; ++i) {
36985
+ this.#toRgb(src, srcOffset, dest, destOffset, scale);
36986
+ srcOffset += 1;
36987
+ destOffset += 3 + alpha01;
36988
+ }
36989
+ }
36990
+ };
36991
+ CalRGBCS = class _CalRGBCS extends ColorSpace {
36992
+ // See http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html for these
36993
+ // matrices.
36994
+ // prettier-ignore
36995
+ static #BRADFORD_SCALE_MATRIX = new Float32Array([
36996
+ 0.8951,
36997
+ 0.2664,
36998
+ -0.1614,
36999
+ -0.7502,
37000
+ 1.7135,
37001
+ 0.0367,
37002
+ 0.0389,
37003
+ -0.0685,
37004
+ 1.0296
37005
+ ]);
37006
+ // prettier-ignore
37007
+ static #BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([
37008
+ 0.9869929,
37009
+ -0.1470543,
37010
+ 0.1599627,
37011
+ 0.4323053,
37012
+ 0.5183603,
37013
+ 0.0492912,
37014
+ -85287e-7,
37015
+ 0.0400428,
37016
+ 0.9684867
37017
+ ]);
37018
+ // See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html.
37019
+ // prettier-ignore
37020
+ static #SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([
37021
+ 3.2404542,
37022
+ -1.5371385,
37023
+ -0.4985314,
37024
+ -0.969266,
37025
+ 1.8760108,
37026
+ 0.041556,
37027
+ 0.0556434,
37028
+ -0.2040259,
37029
+ 1.0572252
37030
+ ]);
37031
+ static #FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]);
37032
+ static #tempNormalizeMatrix = new Float32Array(3);
37033
+ static #tempConvertMatrix1 = new Float32Array(3);
37034
+ static #tempConvertMatrix2 = new Float32Array(3);
37035
+ static #DECODE_L_CONSTANT = ((8 + 16) / 116) ** 3 / 8;
37036
+ constructor(whitePoint, blackPoint, gamma, matrix) {
37037
+ super("CalRGB", 3);
37038
+ if (!whitePoint) {
37039
+ throw new FormatError(
37040
+ "WhitePoint missing - required for color space CalRGB"
37041
+ );
37042
+ }
37043
+ const [XW, YW, ZW] = this.whitePoint = whitePoint;
37044
+ const [XB, YB, ZB] = this.blackPoint = blackPoint || new Float32Array(3);
37045
+ [this.GR, this.GG, this.GB] = gamma || new Float32Array([1, 1, 1]);
37046
+ [
37047
+ this.MXA,
37048
+ this.MYA,
37049
+ this.MZA,
37050
+ this.MXB,
37051
+ this.MYB,
37052
+ this.MZB,
37053
+ this.MXC,
37054
+ this.MYC,
37055
+ this.MZC
37056
+ ] = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
37057
+ if (XW < 0 || ZW < 0 || YW !== 1) {
37058
+ throw new FormatError(
37059
+ `Invalid WhitePoint components for ${this.name}, no fallback available`
37060
+ );
37061
+ }
37062
+ if (XB < 0 || YB < 0 || ZB < 0) {
37063
+ info(
37064
+ `Invalid BlackPoint for ${this.name} [${XB}, ${YB}, ${ZB}], falling back to default.`
37065
+ );
37066
+ this.blackPoint = new Float32Array(3);
37067
+ }
37068
+ if (this.GR < 0 || this.GG < 0 || this.GB < 0) {
37069
+ info(
37070
+ `Invalid Gamma [${this.GR}, ${this.GG}, ${this.GB}] for ${this.name}, falling back to default.`
37071
+ );
37072
+ this.GR = this.GG = this.GB = 1;
37073
+ }
37074
+ }
37075
+ #matrixProduct(a, b, result) {
37076
+ result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
37077
+ result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];
37078
+ result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];
37079
+ }
37080
+ #toFlat(sourceWhitePoint, LMS, result) {
37081
+ result[0] = LMS[0] * 1 / sourceWhitePoint[0];
37082
+ result[1] = LMS[1] * 1 / sourceWhitePoint[1];
37083
+ result[2] = LMS[2] * 1 / sourceWhitePoint[2];
37084
+ }
37085
+ #toD65(sourceWhitePoint, LMS, result) {
37086
+ const D65X = 0.95047;
37087
+ const D65Y = 1;
37088
+ const D65Z = 1.08883;
37089
+ result[0] = LMS[0] * D65X / sourceWhitePoint[0];
37090
+ result[1] = LMS[1] * D65Y / sourceWhitePoint[1];
37091
+ result[2] = LMS[2] * D65Z / sourceWhitePoint[2];
37092
+ }
37093
+ #sRGBTransferFunction(color) {
37094
+ if (color <= 31308e-7) {
37095
+ return MathClamp(12.92 * color, 0, 1);
37096
+ }
37097
+ return color >= 0.99554525 ? 1 : MathClamp((1 + 0.055) * color ** (1 / 2.4) - 0.055, 0, 1);
37098
+ }
37099
+ #decodeL(L) {
37100
+ if (L < 0) {
37101
+ return -this.#decodeL(-L);
37102
+ }
37103
+ return L > 8 ? ((L + 16) / 116) ** 3 : L * _CalRGBCS.#DECODE_L_CONSTANT;
37104
+ }
37105
+ #compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {
37106
+ if (sourceBlackPoint[0] === 0 && sourceBlackPoint[1] === 0 && sourceBlackPoint[2] === 0) {
37107
+ result[0] = XYZ_Flat[0];
37108
+ result[1] = XYZ_Flat[1];
37109
+ result[2] = XYZ_Flat[2];
37110
+ return;
37111
+ }
37112
+ const zeroDecodeL = this.#decodeL(0);
37113
+ const X_DST = zeroDecodeL;
37114
+ const X_SRC = this.#decodeL(sourceBlackPoint[0]);
37115
+ const Y_DST = zeroDecodeL;
37116
+ const Y_SRC = this.#decodeL(sourceBlackPoint[1]);
37117
+ const Z_DST = zeroDecodeL;
37118
+ const Z_SRC = this.#decodeL(sourceBlackPoint[2]);
37119
+ const X_Scale = (1 - X_DST) / (1 - X_SRC);
37120
+ const X_Offset = 1 - X_Scale;
37121
+ const Y_Scale = (1 - Y_DST) / (1 - Y_SRC);
37122
+ const Y_Offset = 1 - Y_Scale;
37123
+ const Z_Scale = (1 - Z_DST) / (1 - Z_SRC);
37124
+ const Z_Offset = 1 - Z_Scale;
37125
+ result[0] = XYZ_Flat[0] * X_Scale + X_Offset;
37126
+ result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;
37127
+ result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;
37128
+ }
37129
+ #normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {
37130
+ if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {
37131
+ result[0] = XYZ_In[0];
37132
+ result[1] = XYZ_In[1];
37133
+ result[2] = XYZ_In[2];
37134
+ return;
37135
+ }
37136
+ const LMS = result;
37137
+ this.#matrixProduct(_CalRGBCS.#BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
37138
+ const LMS_Flat = _CalRGBCS.#tempNormalizeMatrix;
37139
+ this.#toFlat(sourceWhitePoint, LMS, LMS_Flat);
37140
+ this.#matrixProduct(
37141
+ _CalRGBCS.#BRADFORD_SCALE_INVERSE_MATRIX,
37142
+ LMS_Flat,
37143
+ result
37144
+ );
37145
+ }
37146
+ #normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {
37147
+ const LMS = result;
37148
+ this.#matrixProduct(_CalRGBCS.#BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
37149
+ const LMS_D65 = _CalRGBCS.#tempNormalizeMatrix;
37150
+ this.#toD65(sourceWhitePoint, LMS, LMS_D65);
37151
+ this.#matrixProduct(
37152
+ _CalRGBCS.#BRADFORD_SCALE_INVERSE_MATRIX,
37153
+ LMS_D65,
37154
+ result
37155
+ );
37156
+ }
37157
+ #toRgb(src, srcOffset, dest, destOffset, scale) {
37158
+ const A = MathClamp(src[srcOffset] * scale, 0, 1);
37159
+ const B = MathClamp(src[srcOffset + 1] * scale, 0, 1);
37160
+ const C = MathClamp(src[srcOffset + 2] * scale, 0, 1);
37161
+ const AGR = A === 1 ? 1 : A ** this.GR;
37162
+ const BGG = B === 1 ? 1 : B ** this.GG;
37163
+ const CGB = C === 1 ? 1 : C ** this.GB;
37164
+ const X = this.MXA * AGR + this.MXB * BGG + this.MXC * CGB;
37165
+ const Y = this.MYA * AGR + this.MYB * BGG + this.MYC * CGB;
37166
+ const Z = this.MZA * AGR + this.MZB * BGG + this.MZC * CGB;
37167
+ const XYZ = _CalRGBCS.#tempConvertMatrix1;
37168
+ XYZ[0] = X;
37169
+ XYZ[1] = Y;
37170
+ XYZ[2] = Z;
37171
+ const XYZ_Flat = _CalRGBCS.#tempConvertMatrix2;
37172
+ this.#normalizeWhitePointToFlat(this.whitePoint, XYZ, XYZ_Flat);
37173
+ const XYZ_Black = _CalRGBCS.#tempConvertMatrix1;
37174
+ this.#compensateBlackPoint(this.blackPoint, XYZ_Flat, XYZ_Black);
37175
+ const XYZ_D65 = _CalRGBCS.#tempConvertMatrix2;
37176
+ this.#normalizeWhitePointToD65(
37177
+ _CalRGBCS.#FLAT_WHITEPOINT_MATRIX,
37178
+ XYZ_Black,
37179
+ XYZ_D65
37180
+ );
37181
+ const SRGB = _CalRGBCS.#tempConvertMatrix1;
37182
+ this.#matrixProduct(_CalRGBCS.#SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB);
37183
+ dest[destOffset] = this.#sRGBTransferFunction(SRGB[0]) * 255;
37184
+ dest[destOffset + 1] = this.#sRGBTransferFunction(SRGB[1]) * 255;
37185
+ dest[destOffset + 2] = this.#sRGBTransferFunction(SRGB[2]) * 255;
37186
+ }
37187
+ getRgbItem(src, srcOffset, dest, destOffset) {
37188
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
37189
+ assert2(
37190
+ dest instanceof Uint8ClampedArray,
37191
+ 'CalRGBCS.getRgbItem: Unsupported "dest" type.'
37192
+ );
37193
+ }
37194
+ this.#toRgb(src, srcOffset, dest, destOffset, 1);
37195
+ }
37196
+ getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
37197
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
37198
+ assert2(
37199
+ dest instanceof Uint8ClampedArray,
37200
+ 'CalRGBCS.getRgbBuffer: Unsupported "dest" type.'
37201
+ );
37202
+ }
37203
+ const scale = 1 / ((1 << bits) - 1);
37204
+ for (let i = 0; i < count; ++i) {
37205
+ this.#toRgb(src, srcOffset, dest, destOffset, scale);
37206
+ srcOffset += 3;
37207
+ destOffset += 3 + alpha01;
37208
+ }
37209
+ }
37210
+ };
37211
+ LabCS = class extends ColorSpace {
37212
+ constructor(whitePoint, blackPoint, range) {
37213
+ super("Lab", 3);
37214
+ if (!whitePoint) {
37215
+ throw new FormatError(
37216
+ "WhitePoint missing - required for color space Lab"
37217
+ );
37218
+ }
37219
+ [this.XW, this.YW, this.ZW] = whitePoint;
37220
+ [this.amin, this.amax, this.bmin, this.bmax] = range || [
37221
+ -100,
37222
+ 100,
37223
+ -100,
37224
+ 100
37225
+ ];
37226
+ [this.XB, this.YB, this.ZB] = blackPoint || [0, 0, 0];
37227
+ if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
37228
+ throw new FormatError(
37229
+ "Invalid WhitePoint components, no fallback available"
37230
+ );
37231
+ }
37232
+ if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
37233
+ info("Invalid BlackPoint, falling back to default");
37234
+ this.XB = this.YB = this.ZB = 0;
37235
+ }
37236
+ if (this.amin > this.amax || this.bmin > this.bmax) {
37237
+ info("Invalid Range, falling back to defaults");
37238
+ this.amin = -100;
37239
+ this.amax = 100;
37240
+ this.bmin = -100;
37241
+ this.bmax = 100;
37242
+ }
37243
+ }
37244
+ // Function g(x) from spec
37245
+ #fn_g(x) {
37246
+ return x >= 6 / 29 ? x ** 3 : 108 / 841 * (x - 4 / 29);
37247
+ }
37248
+ #decode(value, high1, low2, high2) {
37249
+ return low2 + value * (high2 - low2) / high1;
37250
+ }
37251
+ // If decoding is needed maxVal should be 2^bits per component - 1.
37252
+ #toRgb(src, srcOffset, maxVal, dest, destOffset) {
37253
+ let Ls = src[srcOffset];
37254
+ let as = src[srcOffset + 1];
37255
+ let bs = src[srcOffset + 2];
37256
+ if (maxVal !== false) {
37257
+ Ls = this.#decode(Ls, maxVal, 0, 100);
37258
+ as = this.#decode(as, maxVal, this.amin, this.amax);
37259
+ bs = this.#decode(bs, maxVal, this.bmin, this.bmax);
37260
+ }
37261
+ if (as > this.amax) {
37262
+ as = this.amax;
37263
+ } else if (as < this.amin) {
37264
+ as = this.amin;
37265
+ }
37266
+ if (bs > this.bmax) {
37267
+ bs = this.bmax;
37268
+ } else if (bs < this.bmin) {
37269
+ bs = this.bmin;
37270
+ }
37271
+ const M = (Ls + 16) / 116;
37272
+ const L = M + as / 500;
37273
+ const N = M - bs / 200;
37274
+ const X = this.XW * this.#fn_g(L);
37275
+ const Y = this.YW * this.#fn_g(M);
37276
+ const Z = this.ZW * this.#fn_g(N);
37277
+ let r, g, b;
37278
+ if (this.ZW < 1) {
37279
+ r = X * 3.1339 + Y * -1.617 + Z * -0.4906;
37280
+ g = X * -0.9785 + Y * 1.916 + Z * 0.0333;
37281
+ b = X * 0.072 + Y * -0.229 + Z * 1.4057;
37282
+ } else {
37283
+ r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
37284
+ g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
37285
+ b = X * 0.0557 + Y * -0.204 + Z * 1.057;
37286
+ }
37287
+ dest[destOffset] = Math.sqrt(r) * 255;
37288
+ dest[destOffset + 1] = Math.sqrt(g) * 255;
37289
+ dest[destOffset + 2] = Math.sqrt(b) * 255;
37290
+ }
37291
+ getRgbItem(src, srcOffset, dest, destOffset) {
37292
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
37293
+ assert2(
37294
+ dest instanceof Uint8ClampedArray,
37295
+ 'LabCS.getRgbItem: Unsupported "dest" type.'
37296
+ );
37297
+ }
37298
+ this.#toRgb(src, srcOffset, false, dest, destOffset);
37299
+ }
37300
+ getRgbBuffer(src, srcOffset, count, dest, destOffset, bits, alpha01) {
37301
+ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) {
37302
+ assert2(
37303
+ dest instanceof Uint8ClampedArray,
37304
+ 'LabCS.getRgbBuffer: Unsupported "dest" type.'
37305
+ );
37306
+ }
37307
+ const maxVal = (1 << bits) - 1;
37308
+ for (let i = 0; i < count; i++) {
37309
+ this.#toRgb(src, srcOffset, maxVal, dest, destOffset);
37310
+ srcOffset += 3;
37311
+ destOffset += 3 + alpha01;
37312
+ }
37313
+ }
37314
+ isDefaultDecode(decode, bpc) {
37315
+ return true;
37316
+ }
37317
+ get usesZeroToOneRange() {
37318
+ return shadow2(this, "usesZeroToOneRange", false);
37319
+ }
37320
+ };
37321
+ TOKEN = {
37322
+ // Structural tokens — not keyword operators
37323
+ number: 0,
37324
+ lbrace: 1,
37325
+ rbrace: 2,
37326
+ // Boolean literals
37327
+ true: 3,
37328
+ false: 4,
37329
+ // Arithmetic binary operators
37330
+ add: 5,
37331
+ sub: 6,
37332
+ mul: 7,
37333
+ div: 8,
37334
+ idiv: 9,
37335
+ mod: 10,
37336
+ exp: 11,
37337
+ // Comparison binary operators
37338
+ eq: 12,
37339
+ ne: 13,
37340
+ gt: 14,
37341
+ ge: 15,
37342
+ lt: 16,
37343
+ le: 17,
37344
+ // Bitwise / boolean binary operators
37345
+ and: 18,
37346
+ or: 19,
37347
+ xor: 20,
37348
+ bitshift: 21,
37349
+ // Unary arithmetic operators
37350
+ abs: 22,
37351
+ neg: 23,
37352
+ ceiling: 24,
37353
+ floor: 25,
37354
+ round: 26,
37355
+ truncate: 27,
37356
+ // Unary boolean / bitwise operator
37357
+ not: 28,
37358
+ // Mathematical functions — unary
37359
+ sqrt: 29,
37360
+ sin: 30,
37361
+ cos: 31,
37362
+ ln: 32,
37363
+ log: 33,
37364
+ // Mathematical function — binary
37365
+ atan: 34,
37366
+ // Type conversion operators
37367
+ cvi: 35,
37368
+ cvr: 36,
37369
+ // Stack operators
37370
+ dup: 37,
37371
+ exch: 38,
37372
+ pop: 39,
37373
+ copy: 40,
37374
+ index: 41,
37375
+ roll: 42,
37376
+ // Control flow
37377
+ if: 43,
37378
+ ifelse: 44,
37379
+ // End of input
37380
+ eof: 45,
37381
+ // Synthetic: produced by the optimizer, never emitted by the lexer.
37382
+ min: 46,
37383
+ max: 47
37384
+ };
37385
+ Token = class {
37386
+ constructor(id, value = null) {
37387
+ this.id = id;
37388
+ this.value = value;
37389
+ }
37390
+ };
37391
+ Lexer = class _Lexer {
37392
+ // Singletons for every non-number token, built lazily on first construction.
37393
+ // Keyword operator tokens carry their name as `value`; structural tokens
37394
+ // (lbrace, rbrace, eof) carry null.
37395
+ static #singletons = null;
37396
+ static #operatorSingletons = null;
37397
+ static #initSingletons() {
37398
+ const singletons = /* @__PURE__ */ Object.create(null);
37399
+ const operatorSingletons = /* @__PURE__ */ Object.create(null);
37400
+ for (const [name, id] of Object.entries(TOKEN)) {
37401
+ if (name === "number") {
37402
+ continue;
37403
+ }
37404
+ const isOperator = id >= TOKEN.true && id <= TOKEN.ifelse;
37405
+ const token = new Token(id, isOperator ? name : null);
37406
+ singletons[name] = token;
37407
+ if (isOperator) {
37408
+ operatorSingletons[name] = token;
37409
+ }
37410
+ }
37411
+ this.#singletons = singletons;
37412
+ this.#operatorSingletons = operatorSingletons;
37413
+ }
37414
+ constructor(data) {
37415
+ if (!_Lexer.#singletons) {
37416
+ _Lexer.#initSingletons();
37417
+ }
37418
+ this.data = data;
37419
+ this.pos = 0;
37420
+ this.len = data.length;
37421
+ this._numberPattern = /[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/iy;
37422
+ this._identifierPattern = /[a-z]+/y;
37423
+ }
37424
+ // Skip a % comment, advancing past the next \n or \r (or to EOF).
37425
+ _skipComment() {
37426
+ const lf = this.data.indexOf("\n", this.pos);
37427
+ const cr = this.data.indexOf("\r", this.pos);
37428
+ const eol = Math.min(lf < 0 ? this.len : lf, cr < 0 ? this.len : cr);
37429
+ this.pos = Math.min(eol + 1, this.len);
37430
+ }
37431
+ _getNumber() {
37432
+ this._numberPattern.lastIndex = this.pos;
37433
+ const match = this._numberPattern.exec(this.data);
37434
+ if (!match) {
37435
+ return new Token(TOKEN.number, 0);
37436
+ }
37437
+ const number = parseFloat(match[0]);
37438
+ if (!Number.isFinite(number)) {
37439
+ return new Token(TOKEN.number, 0);
37440
+ }
37441
+ this.pos = this._numberPattern.lastIndex;
37442
+ return new Token(TOKEN.number, number);
37443
+ }
37444
+ _getOperator() {
37445
+ this._identifierPattern.lastIndex = this.pos;
37446
+ const match = this._identifierPattern.exec(this.data);
37447
+ if (!match) {
37448
+ return new Token(TOKEN.number, 0);
37449
+ }
37450
+ this.pos = this._identifierPattern.lastIndex;
37451
+ const op = match[0];
37452
+ const token = _Lexer.#operatorSingletons[op];
37453
+ return token ?? new Token(TOKEN.number, 0);
37454
+ }
37455
+ // Return the next token, or Lexer.#singletons.eof at end of input.
37456
+ next() {
37457
+ while (this.pos < this.len) {
37458
+ const ch3 = this.data.charCodeAt(this.pos++);
37459
+ switch (ch3) {
37460
+ // PostScript white-space characters (PDF32000 §7.2.2)
37461
+ case 0:
37462
+ case 9:
37463
+ case 10:
37464
+ case 12:
37465
+ case 13:
37466
+ case 32:
37467
+ break;
37468
+ case 37:
37469
+ this._skipComment();
37470
+ break;
37471
+ case 123:
37472
+ return _Lexer.#singletons.lbrace;
37473
+ case 125:
37474
+ return _Lexer.#singletons.rbrace;
37475
+ case 43:
37476
+ case 45:
37477
+ this.pos--;
37478
+ return this._getNumber();
37479
+ case 46:
37480
+ this.pos--;
37481
+ return this._getNumber();
37482
+ default:
37483
+ if (ch3 >= 48 && ch3 <= 57) {
37484
+ this.pos--;
37485
+ return this._getNumber();
37486
+ }
37487
+ if (ch3 >= 97 && ch3 <= 122) {
37488
+ this.pos--;
37489
+ return this._getOperator();
37490
+ }
37491
+ return new Token(TOKEN.number, 0);
37492
+ }
37493
+ }
37494
+ return _Lexer.#singletons.eof;
37495
+ }
37496
+ };
37497
+ PS_VALUE_TYPE = {
37498
+ numeric: 0,
37499
+ // known to be a number (f64 in Wasm)
37500
+ boolean: 1,
37501
+ // known to be a boolean (0.0 = false, 1.0 = true in f64)
37502
+ unknown: 2
37503
+ // indeterminate at compile time
37504
+ };
37505
+ PS_NODE = {
37506
+ // Parser AST node types (produced by Parser / parsePostScriptFunction)
37507
+ program: 0,
37508
+ block: 1,
37509
+ number: 2,
37510
+ operator: 3,
37511
+ if: 4,
37512
+ ifelse: 5,
37513
+ // Tree AST node types (produced by PSStackToTree)
37514
+ arg: 6,
37515
+ const: 7,
37516
+ unary: 8,
37517
+ binary: 9,
37518
+ ternary: 10
37519
+ };
37520
+ PsNode = class {
37521
+ constructor(type) {
37522
+ this.type = type;
37523
+ }
37524
+ };
37525
+ PsProgram = class extends PsNode {
37526
+ constructor(body) {
37527
+ super(PS_NODE.program);
37528
+ this.body = body;
37529
+ }
37530
+ };
37531
+ PsBlock = class extends PsNode {
37532
+ constructor(instructions) {
37533
+ super(PS_NODE.block);
37534
+ this.instructions = instructions;
37535
+ }
37536
+ };
37537
+ PsNumber = class extends PsNode {
37538
+ /** @param {number} value */
37539
+ constructor(value) {
37540
+ super(PS_NODE.number);
37541
+ this.value = value;
37542
+ }
37543
+ };
37544
+ PsOperator = class extends PsNode {
37545
+ /** @param {number} op — one of the TOKEN.* constants from lexer.js */
37546
+ constructor(op) {
37547
+ super(PS_NODE.operator);
37548
+ this.op = op;
37549
+ }
37550
+ };
37551
+ PsIf = class extends PsNode {
37552
+ /** @param {PsBlock} then */
37553
+ constructor(then) {
37554
+ super(PS_NODE.if);
37555
+ this.then = then;
37556
+ }
37557
+ };
37558
+ PsIfElse = class extends PsNode {
37559
+ /**
37560
+ * @param {PsBlock} then
37561
+ * @param {PsBlock} otherwise
37562
+ */
37563
+ constructor(then, otherwise) {
37564
+ super(PS_NODE.ifelse);
37565
+ this.then = then;
37566
+ this.otherwise = otherwise;
37567
+ }
37568
+ };
37569
+ PsArgNode = class extends PsNode {
37570
+ /** @param {number} index */
37571
+ constructor(index) {
37572
+ super(PS_NODE.arg);
37573
+ this.index = index;
37574
+ this.valueType = PS_VALUE_TYPE.numeric;
37575
+ }
37576
+ };
37577
+ PsConstNode = class extends PsNode {
37578
+ /** @param {number|boolean} value */
37579
+ constructor(value) {
37580
+ super(PS_NODE.const);
37581
+ this.value = value;
37582
+ this.valueType = typeof value === "boolean" ? PS_VALUE_TYPE.boolean : PS_VALUE_TYPE.numeric;
37583
+ }
37584
+ };
37585
+ PsUnaryNode = class extends PsNode {
37586
+ /**
37587
+ * @param {number} op — TOKEN.* constant
37588
+ * @param {PsNode} operand
37589
+ * @param {number} [valueType]
37590
+ */
37591
+ constructor(op, operand, valueType = PS_VALUE_TYPE.unknown) {
37592
+ super(PS_NODE.unary);
37593
+ this.op = op;
37594
+ this.operand = operand;
37595
+ this.valueType = valueType;
37596
+ }
37597
+ };
37598
+ PsBinaryNode = class extends PsNode {
37599
+ /**
37600
+ * @param {number} op — TOKEN.* constant
37601
+ * @param {PsNode} first — was on top of stack
37602
+ * @param {PsNode} second — was below top
37603
+ * @param {number} [valueType]
37604
+ */
37605
+ constructor(op, first, second, valueType = PS_VALUE_TYPE.unknown) {
37606
+ super(PS_NODE.binary);
37607
+ this.op = op;
37608
+ this.first = first;
37609
+ this.second = second;
37610
+ this.valueType = valueType;
37611
+ }
37612
+ };
37613
+ PsTernaryNode = class extends PsNode {
37614
+ /**
37615
+ * @param {PsNode} cond
37616
+ * @param {PsNode} then
37617
+ * @param {PsNode} otherwise
37618
+ * @param {number} [valueType]
37619
+ */
37620
+ constructor(cond, then, otherwise, valueType = PS_VALUE_TYPE.unknown) {
37621
+ super(PS_NODE.ternary);
37622
+ this.cond = cond;
37623
+ this.then = then;
37624
+ this.otherwise = otherwise;
37625
+ this.valueType = valueType;
37626
+ }
37627
+ };
37628
+ Parser = class _Parser {
37629
+ constructor(lexer) {
37630
+ this.lexer = lexer;
37631
+ this._token = null;
37632
+ }
37633
+ static _isRegularOperator(id) {
37634
+ return id >= TOKEN.true && id < TOKEN.if;
37635
+ }
37636
+ // Fetch the next token from the lexer.
37637
+ _advance() {
37638
+ this._token = this.lexer.next();
37639
+ }
37640
+ // Assert that the current token has the given id, consume it, and return it.
37641
+ _expect(id) {
37642
+ if (this._token.id !== id) {
37643
+ throw new FormatError(
37644
+ `PostScript function: expected token id ${id}, got ${this._token.id}.`
37645
+ );
37646
+ }
37647
+ const tok = this._token;
37648
+ this._advance();
37649
+ return tok;
37650
+ }
37651
+ /**
37652
+ * Parse the full Type 4 function body.
37653
+ *
37654
+ * Grammar (simplified):
37655
+ * program ::= '{' block '}'
37656
+ * block ::= instruction*
37657
+ * instruction ::= number
37658
+ * | operator (any PS_OPERATOR except if / ifelse)
37659
+ * | '{' block '}' 'if'
37660
+ * | '{' block '}' '{' block '}' 'ifelse'
37661
+ * @returns {PsProgram}
37662
+ */
37663
+ parse() {
37664
+ this._advance();
37665
+ this._expect(TOKEN.lbrace);
37666
+ const block = this._parseBlock();
37667
+ this._expect(TOKEN.rbrace);
37668
+ if (this._token.id !== TOKEN.eof) {
37669
+ warn2("PostScript function: unexpected content after closing brace.");
37670
+ }
37671
+ return new PsProgram(block);
37672
+ }
37673
+ _parseBlock() {
37674
+ const instructions = [];
37675
+ while (true) {
37676
+ const tok = this._token;
37677
+ switch (tok.id) {
37678
+ case TOKEN.number:
37679
+ instructions.push(new PsNumber(tok.value));
37680
+ this._advance();
37681
+ break;
37682
+ case TOKEN.lbrace: {
37683
+ this._advance();
37684
+ const thenBlock = this._parseBlock();
37685
+ this._expect(TOKEN.rbrace);
37686
+ if (this._token.id === TOKEN.if) {
37687
+ this._advance();
37688
+ instructions.push(new PsIf(thenBlock));
37689
+ } else if (this._token.id === TOKEN.lbrace) {
37690
+ this._advance();
37691
+ const elseBlock = this._parseBlock();
37692
+ this._expect(TOKEN.rbrace);
37693
+ this._expect(TOKEN.ifelse);
37694
+ instructions.push(new PsIfElse(thenBlock, elseBlock));
37695
+ } else {
37696
+ throw new FormatError(
37697
+ "PostScript function: a procedure block must be followed by 'if' or '{\u2026} ifelse'."
37698
+ );
37699
+ }
37700
+ break;
37701
+ }
37702
+ case TOKEN.rbrace:
37703
+ case TOKEN.eof:
37704
+ return new PsBlock(instructions);
37705
+ case TOKEN.if:
37706
+ case TOKEN.ifelse:
37707
+ throw new FormatError(
37708
+ `PostScript function: unexpected '${tok.value}' operator.`
37709
+ );
37710
+ default:
37711
+ if (_Parser._isRegularOperator(tok.id)) {
37712
+ instructions.push(new PsOperator(tok.id));
37713
+ this._advance();
37714
+ break;
37715
+ }
37716
+ throw new FormatError(
37717
+ `PostScript function: unexpected token id ${tok.id}.`
37718
+ );
37719
+ }
37720
+ }
37721
+ }
37722
+ };
37723
+ MAX_STACK_SIZE = 100;
37724
+ PSStackToTree = class _PSStackToTree {
37725
+ static #binaryOps = null;
37726
+ static #unaryOps = null;
37727
+ static #idempotentUnary = null;
37728
+ static #negatedComparison = null;
37729
+ static #init() {
37730
+ this.#binaryOps = /* @__PURE__ */ new Set([
37731
+ TOKEN.add,
37732
+ TOKEN.sub,
37733
+ TOKEN.mul,
37734
+ TOKEN.div,
37735
+ TOKEN.idiv,
37736
+ TOKEN.mod,
37737
+ TOKEN.exp,
37738
+ TOKEN.atan,
37739
+ TOKEN.eq,
37740
+ TOKEN.ne,
37741
+ TOKEN.gt,
37742
+ TOKEN.ge,
37743
+ TOKEN.lt,
37744
+ TOKEN.le,
37745
+ TOKEN.and,
37746
+ TOKEN.or,
37747
+ TOKEN.xor,
37748
+ TOKEN.bitshift
37749
+ ]);
37750
+ this.#unaryOps = /* @__PURE__ */ new Set([
37751
+ TOKEN.abs,
37752
+ TOKEN.neg,
37753
+ TOKEN.ceiling,
37754
+ TOKEN.floor,
37755
+ TOKEN.round,
37756
+ TOKEN.truncate,
37757
+ TOKEN.sqrt,
37758
+ TOKEN.sin,
37759
+ TOKEN.cos,
37760
+ TOKEN.ln,
37761
+ TOKEN.log,
37762
+ TOKEN.cvi,
37763
+ TOKEN.cvr,
37764
+ TOKEN.not
37765
+ ]);
37766
+ this.#idempotentUnary = /* @__PURE__ */ new Set([
37767
+ TOKEN.abs,
37768
+ TOKEN.ceiling,
37769
+ TOKEN.cvi,
37770
+ TOKEN.cvr,
37771
+ TOKEN.floor,
37772
+ TOKEN.round,
37773
+ TOKEN.truncate
37774
+ ]);
37775
+ this.#negatedComparison = /* @__PURE__ */ new Map([
37776
+ [TOKEN.eq, TOKEN.ne],
37777
+ [TOKEN.ne, TOKEN.eq],
37778
+ [TOKEN.lt, TOKEN.ge],
37779
+ [TOKEN.le, TOKEN.gt],
37780
+ [TOKEN.gt, TOKEN.le],
37781
+ [TOKEN.ge, TOKEN.lt]
37782
+ ]);
37783
+ }
37784
+ /**
37785
+ * @param {PsProgram} program
37786
+ * @param {number} numInputs — number of domain values placed on the stack
37787
+ * before the program runs (i.e. the length of the domain array / 2).
37788
+ * @returns {Array<PsNode>} — one tree node per output value.
37789
+ */
37790
+ evaluate(program, numInputs) {
37791
+ if (!_PSStackToTree.#binaryOps) {
37792
+ _PSStackToTree.#init();
37793
+ }
37794
+ this._failed = false;
37795
+ if (numInputs > MAX_STACK_SIZE) {
37796
+ return null;
37797
+ }
37798
+ const stack = [];
37799
+ for (let i = 0; i < numInputs; i++) {
37800
+ stack.push(new PsArgNode(i));
37801
+ }
37802
+ this._evalBlock(program.body, stack);
37803
+ if (this._failed) {
37804
+ return null;
37805
+ }
37806
+ _PSStackToTree.#markShared(stack);
37807
+ return stack;
37808
+ }
37809
+ // Set node.shared / sharedCount on non-atomic nodes referenced more than
37810
+ // once. arg/const are excluded — they are cheap to re-emit inline.
37811
+ static #markShared(outputs) {
37812
+ const refCount = /* @__PURE__ */ new Map();
37813
+ const visit = (node) => {
37814
+ if (!node || node.type === PS_NODE.arg || node.type === PS_NODE.const) {
37815
+ return;
37816
+ }
37817
+ const prev = refCount.get(node) ?? 0;
37818
+ refCount.set(node, prev + 1);
37819
+ if (prev > 0) {
37820
+ return;
37821
+ }
37822
+ switch (node.type) {
37823
+ case PS_NODE.unary:
37824
+ visit(node.operand);
37825
+ break;
37826
+ case PS_NODE.binary:
37827
+ visit(node.first);
37828
+ visit(node.second);
37829
+ break;
37830
+ case PS_NODE.ternary:
37831
+ visit(node.cond);
37832
+ visit(node.then);
37833
+ visit(node.otherwise);
37834
+ break;
37835
+ }
37836
+ };
37837
+ for (const output of outputs) {
37838
+ visit(output);
37839
+ }
37840
+ for (const [node, count] of refCount) {
37841
+ if (count > 1) {
37842
+ node.shared = true;
37843
+ node.sharedCount = count;
37844
+ }
37845
+ }
37846
+ }
37847
+ _evalBlock(block, stack) {
37848
+ this._evalBlockFrom(block.instructions, 0, stack);
37849
+ }
37850
+ /**
37851
+ * Core evaluation loop. Processes `instructions[startIdx…]` in order,
37852
+ * mutating `stack` as each instruction executes.
37853
+ *
37854
+ * When a `{ body } if` instruction grows the stack (the PostScript "early
37855
+ * exit / guard" idiom), the remaining instructions in the current array are
37856
+ * evaluated on **both** the true-branch stack and the false-branch stack,
37857
+ * then the two results are merged into PsTernaryNodes. This handles
37858
+ * patterns like:
37859
+ *
37860
+ * cond { pop R G B sentinel } if
37861
+ * … more guards …
37862
+ * sentinel 0 gt { defaultR defaultG defaultB } if
37863
+ */
37864
+ _evalBlockFrom(instructions, startIdx, stack) {
37865
+ for (let idx = startIdx; idx < instructions.length; idx++) {
37866
+ if (this._failed) {
37867
+ break;
37868
+ }
37869
+ const instr = instructions[idx];
37870
+ switch (instr.type) {
37871
+ case PS_NODE.number:
37872
+ stack.push(new PsConstNode(instr.value));
37873
+ if (stack.length > MAX_STACK_SIZE) {
37874
+ this._failed = true;
37875
+ }
37876
+ break;
37877
+ case PS_NODE.operator:
37878
+ this._evalOp(instr.op, stack);
37879
+ break;
37880
+ case PS_NODE.if: {
37881
+ if (stack.length < 1) {
37882
+ this._failed = true;
37883
+ break;
37884
+ }
37885
+ const cond = stack.pop();
37886
+ const saved = stack.slice();
37887
+ this._evalBlock(instr.then, stack);
37888
+ if (this._failed) {
37889
+ break;
37890
+ }
37891
+ if (stack.length === saved.length) {
37892
+ for (let i = 0; i < stack.length; i++) {
37893
+ if (stack[i] !== saved[i]) {
37894
+ stack[i] = this._makeTernary(cond, stack[i], saved[i]);
37895
+ }
37896
+ }
37897
+ } else if (stack.length > saved.length) {
37898
+ if (cond.type === PS_NODE.const) {
37899
+ if (!cond.value) {
37900
+ stack.length = 0;
37901
+ stack.push(...saved);
37902
+ }
37903
+ break;
37904
+ }
37905
+ const trueStack = stack.slice();
37906
+ this._evalBlockFrom(instructions, idx + 1, trueStack);
37907
+ if (this._failed) {
37908
+ break;
37909
+ }
37910
+ const falseStack = saved;
37911
+ this._evalBlockFrom(instructions, idx + 1, falseStack);
37912
+ if (this._failed) {
37913
+ break;
37914
+ }
37915
+ if (trueStack.length !== falseStack.length) {
37916
+ const zero2 = new PsConstNode(0);
37917
+ while (trueStack.length < falseStack.length) {
37918
+ trueStack.push(zero2);
37919
+ }
37920
+ while (falseStack.length < trueStack.length) {
37921
+ falseStack.push(zero2);
37922
+ }
37923
+ }
37924
+ stack.length = 0;
37925
+ for (let i = 0; i < trueStack.length; i++) {
37926
+ stack.push(this._makeTernary(cond, trueStack[i], falseStack[i]));
37927
+ }
37928
+ return;
37929
+ } else {
37930
+ this._failed = true;
37931
+ }
37932
+ break;
37933
+ }
37934
+ case PS_NODE.ifelse: {
37935
+ if (stack.length < 1) {
37936
+ this._failed = true;
37937
+ break;
37938
+ }
37939
+ const cond = stack.pop();
37940
+ const snapshot = stack.slice();
37941
+ const thenStack = snapshot.slice();
37942
+ this._evalBlock(instr.then, thenStack);
37943
+ if (this._failed) {
37944
+ break;
37945
+ }
37946
+ const elseStack = snapshot.slice();
37947
+ this._evalBlock(instr.otherwise, elseStack);
37948
+ if (this._failed) {
37949
+ break;
37950
+ }
37951
+ if (thenStack.length !== elseStack.length) {
37952
+ const zero2 = new PsConstNode(0);
37953
+ while (thenStack.length < elseStack.length) {
37954
+ thenStack.push(zero2);
37955
+ }
37956
+ while (elseStack.length < thenStack.length) {
37957
+ elseStack.push(zero2);
37958
+ }
37959
+ }
37960
+ stack.length = 0;
37961
+ for (let i = 0; i < thenStack.length; i++) {
37962
+ stack.push(this._makeTernary(cond, thenStack[i], elseStack[i]));
37963
+ }
37964
+ break;
37965
+ }
37966
+ }
37967
+ }
37968
+ }
37969
+ _evalOp(op, stack) {
37970
+ if (_PSStackToTree.#binaryOps.has(op)) {
37971
+ if (stack.length < 2) {
37972
+ this._failed = true;
37973
+ return;
37974
+ }
37975
+ const first = stack.pop();
37976
+ const second = stack.pop();
37977
+ stack.push(this._makeBinary(op, first, second));
37978
+ return;
37979
+ }
37980
+ if (_PSStackToTree.#unaryOps.has(op)) {
37981
+ if (stack.length < 1) {
37982
+ this._failed = true;
37983
+ return;
37984
+ }
37985
+ stack.push(this._makeUnary(op, stack.pop()));
37986
+ return;
37987
+ }
37988
+ switch (op) {
37989
+ case TOKEN.true:
37990
+ stack.push(new PsConstNode(true));
37991
+ if (stack.length > MAX_STACK_SIZE) {
37992
+ this._failed = true;
37993
+ }
37994
+ break;
37995
+ case TOKEN.false:
37996
+ stack.push(new PsConstNode(false));
37997
+ if (stack.length > MAX_STACK_SIZE) {
37998
+ this._failed = true;
37999
+ }
38000
+ break;
38001
+ case TOKEN.dup:
38002
+ if (stack.length < 1) {
38003
+ this._failed = true;
38004
+ break;
38005
+ }
38006
+ stack.push(stack.at(-1));
38007
+ if (stack.length > MAX_STACK_SIZE) {
38008
+ this._failed = true;
38009
+ }
38010
+ break;
38011
+ case TOKEN.exch: {
38012
+ if (stack.length < 2) {
38013
+ this._failed = true;
38014
+ break;
38015
+ }
38016
+ const a = stack.pop();
38017
+ const b = stack.pop();
38018
+ stack.push(a, b);
38019
+ break;
38020
+ }
38021
+ case TOKEN.pop:
38022
+ if (stack.length < 1) {
38023
+ this._failed = true;
38024
+ break;
38025
+ }
38026
+ stack.pop();
38027
+ break;
38028
+ case TOKEN.copy: {
38029
+ if (stack.length < 1) {
38030
+ this._failed = true;
38031
+ break;
38032
+ }
38033
+ const nNode = stack.pop();
38034
+ if (nNode.type === PS_NODE.const) {
38035
+ const n = nNode.value | 0;
38036
+ if (n === 0) {
38037
+ } else if (n < 0 || n > stack.length) {
38038
+ this._failed = true;
38039
+ } else {
38040
+ stack.push(...stack.slice(-n));
38041
+ if (stack.length > MAX_STACK_SIZE) {
38042
+ this._failed = true;
38043
+ }
38044
+ }
38045
+ } else {
38046
+ this._failed = true;
38047
+ }
38048
+ break;
38049
+ }
38050
+ case TOKEN.index: {
38051
+ if (stack.length < 1) {
38052
+ this._failed = true;
38053
+ break;
38054
+ }
38055
+ const nNode = stack.pop();
38056
+ if (nNode.type === PS_NODE.const) {
38057
+ const n = nNode.value | 0;
38058
+ if (n < 0 || n >= stack.length) {
38059
+ this._failed = true;
38060
+ } else {
38061
+ stack.push(stack.at(-n - 1));
38062
+ }
38063
+ } else {
38064
+ this._failed = true;
38065
+ }
38066
+ break;
38067
+ }
38068
+ case TOKEN.roll: {
38069
+ if (stack.length < 2) {
38070
+ this._failed = true;
38071
+ break;
38072
+ }
38073
+ const jNode = stack.pop();
38074
+ const nNode = stack.pop();
38075
+ if (nNode.type === PS_NODE.const && jNode.type === PS_NODE.const) {
38076
+ const n = nNode.value | 0;
38077
+ if (n === 0) {
38078
+ } else if (n < 0 || n > stack.length) {
38079
+ this._failed = true;
38080
+ } else {
38081
+ const j = ((jNode.value | 0) % n + n) % n;
38082
+ if (j > 0) {
38083
+ const slice = stack.splice(-n, n);
38084
+ stack.push(...slice.slice(n - j), ...slice.slice(0, n - j));
38085
+ }
38086
+ }
38087
+ } else {
38088
+ this._failed = true;
38089
+ }
38090
+ break;
38091
+ }
38092
+ default:
38093
+ this._failed = true;
38094
+ break;
38095
+ }
38096
+ }
38097
+ /**
38098
+ * Create a binary tree node, applying optimizations eagerly:
38099
+ *
38100
+ * 1. Constant folding — both operands are PsConstNode → fold to PsConstNode.
38101
+ * 2. Reflexive simplifications — x−x→0, x xor x→0, x eq x→true, etc.
38102
+ * 3. Algebraic simplifications with one known operand — identity elements
38103
+ * (x+0→x, x*1→x, …), absorbing elements (x*0→0, x and false→false, …),
38104
+ * and strength reductions (x*-1→neg(x), x^0.5→sqrt(x), x^2→x*x, …).
38105
+ *
38106
+ * Recall: `first` was on top of the stack (right operand for non-commutative
38107
+ * ops), `second` was below (left operand). So `a b sub` → second=a, first=b
38108
+ * → a − b.
38109
+ */
38110
+ _makeBinary(op, first, second) {
38111
+ if (first.type === PS_NODE.const && second.type === PS_NODE.const) {
38112
+ const v = _evalBinaryConst(op, second.value, first.value);
38113
+ if (v !== void 0) {
38114
+ return new PsConstNode(v);
38115
+ }
38116
+ }
38117
+ if (_nodesEqual(first, second)) {
38118
+ switch (op) {
38119
+ case TOKEN.sub:
38120
+ return new PsConstNode(0);
38121
+ // x − x → 0
38122
+ case TOKEN.xor:
38123
+ return new PsConstNode(
38124
+ /* eslint-disable unicorn/prefer-logical-operator-over-ternary */
38125
+ first.valueType === PS_VALUE_TYPE.boolean ? false : 0
38126
+ /* eslint-enable unicorn/prefer-logical-operator-over-ternary */
38127
+ );
38128
+ // TOKEN.mod, TOKEN.div, TOKEN.idiv are NOT simplified here:
38129
+ // x op x is undefined when x = 0, so we cannot fold without knowing
38130
+ // that x is non-zero.
38131
+ case TOKEN.and:
38132
+ case TOKEN.or:
38133
+ return first;
38134
+ // x and x → x; x or x → x
38135
+ case TOKEN.min:
38136
+ case TOKEN.max:
38137
+ return first;
38138
+ // min(x,x) → x; max(x,x) → x
38139
+ case TOKEN.eq:
38140
+ case TOKEN.ge:
38141
+ case TOKEN.le:
38142
+ return new PsConstNode(true);
38143
+ case TOKEN.ne:
38144
+ case TOKEN.gt:
38145
+ case TOKEN.lt:
38146
+ return new PsConstNode(false);
38147
+ }
38148
+ }
38149
+ if (first.type === PS_NODE.const) {
38150
+ const b = first.value;
38151
+ switch (op) {
38152
+ case TOKEN.add:
38153
+ if (b === 0) {
38154
+ return second;
38155
+ }
38156
+ break;
38157
+ case TOKEN.sub:
38158
+ if (b === 0) {
38159
+ return second;
38160
+ }
38161
+ break;
38162
+ case TOKEN.mul:
38163
+ if (b === 1) {
38164
+ return second;
38165
+ }
38166
+ if (b === 0) {
38167
+ return first;
38168
+ }
38169
+ if (b === -1) {
38170
+ return this._makeUnary(TOKEN.neg, second);
38171
+ }
38172
+ break;
38173
+ case TOKEN.div:
38174
+ if (b !== 0) {
38175
+ return this._makeBinary(TOKEN.mul, new PsConstNode(1 / b), second);
38176
+ }
38177
+ break;
38178
+ case TOKEN.idiv:
38179
+ if (b === 1) {
38180
+ return second;
38181
+ }
38182
+ break;
38183
+ case TOKEN.exp:
38184
+ if (b === 1) {
38185
+ return second;
38186
+ }
38187
+ if (b === -1) {
38188
+ return this._makeBinary(TOKEN.div, second, new PsConstNode(1));
38189
+ }
38190
+ if (b === 0.5) {
38191
+ return this._makeUnary(TOKEN.sqrt, second);
38192
+ }
38193
+ if (b === 0.25) {
38194
+ const sqrtOnce = this._makeUnary(TOKEN.sqrt, second);
38195
+ return this._makeUnary(TOKEN.sqrt, sqrtOnce);
38196
+ }
38197
+ if (b === 2) {
38198
+ return this._makeBinary(TOKEN.mul, second, second);
38199
+ }
38200
+ if (b === 3) {
38201
+ return this._makeBinary(
38202
+ TOKEN.mul,
38203
+ this._makeBinary(TOKEN.mul, second, second),
38204
+ second
38205
+ );
38206
+ }
38207
+ if (b === 4) {
38208
+ const square = this._makeBinary(TOKEN.mul, second, second);
38209
+ return this._makeBinary(TOKEN.mul, square, square);
38210
+ }
38211
+ if (b === 0) {
38212
+ return new PsConstNode(1);
38213
+ }
38214
+ break;
38215
+ case TOKEN.and:
38216
+ if (b === true) {
38217
+ return second;
38218
+ }
38219
+ if (b === false) {
38220
+ return first;
38221
+ }
38222
+ break;
38223
+ case TOKEN.or:
38224
+ if (b === false) {
38225
+ return second;
38226
+ }
38227
+ if (b === true) {
38228
+ return first;
38229
+ }
38230
+ break;
38231
+ case TOKEN.min:
38232
+ if (second.type === PS_NODE.binary && second.op === TOKEN.max && second.first.type === PS_NODE.const && second.first.value >= b) {
38233
+ return first;
38234
+ }
38235
+ break;
38236
+ case TOKEN.max:
38237
+ if (second.type === PS_NODE.binary && second.op === TOKEN.min && second.first.type === PS_NODE.const && second.first.value <= b) {
38238
+ return first;
38239
+ }
38240
+ break;
38241
+ }
38242
+ }
38243
+ if (second.type === PS_NODE.const) {
38244
+ const a = second.value;
38245
+ switch (op) {
38246
+ case TOKEN.add:
38247
+ if (a === 0) {
38248
+ return first;
38249
+ }
38250
+ break;
38251
+ case TOKEN.sub:
38252
+ if (a === 0) {
38253
+ return this._makeUnary(TOKEN.neg, first);
38254
+ }
38255
+ break;
38256
+ case TOKEN.mul:
38257
+ if (a === 1) {
38258
+ return first;
38259
+ }
38260
+ if (a === 0) {
38261
+ return second;
38262
+ }
38263
+ if (a === -1) {
38264
+ return this._makeUnary(TOKEN.neg, first);
38265
+ }
38266
+ break;
38267
+ case TOKEN.and:
38268
+ if (a === true) {
38269
+ return first;
38270
+ }
38271
+ if (a === false) {
38272
+ return second;
38273
+ }
38274
+ break;
38275
+ case TOKEN.or:
38276
+ if (a === false) {
38277
+ return first;
38278
+ }
38279
+ if (a === true) {
38280
+ return second;
38281
+ }
38282
+ break;
38283
+ }
38284
+ }
38285
+ return new PsBinaryNode(
38286
+ op,
38287
+ first,
38288
+ second,
38289
+ _binaryValueType(op, first.valueType, second.valueType)
38290
+ );
38291
+ }
38292
+ /**
38293
+ * Create a unary tree node, applying optimizations eagerly:
38294
+ *
38295
+ * 1. Constant folding.
38296
+ * 2. not(comparison) → negated comparison: not(a eq b) → a ne b, etc.
38297
+ * 3. neg(a − b) → b − a.
38298
+ * 4. Double-negation: neg(neg(x)) → x, not(not(x)) → x.
38299
+ * 5. abs(neg(x)) → abs(x).
38300
+ * 6. Idempotent: f(f(x)) → f(x) for abs, ceiling, floor, round, etc.
38301
+ */
38302
+ _makeUnary(op, operand) {
38303
+ if (operand.type === PS_NODE.const) {
38304
+ const v = _evalUnaryConst(op, operand.value);
38305
+ if (v !== void 0) {
38306
+ return new PsConstNode(v);
38307
+ }
38308
+ }
38309
+ if (op === TOKEN.not && operand.type === PS_NODE.binary) {
38310
+ const negated = _PSStackToTree.#negatedComparison.get(operand.op);
38311
+ if (negated !== void 0) {
38312
+ return new PsBinaryNode(
38313
+ negated,
38314
+ operand.first,
38315
+ operand.second,
38316
+ PS_VALUE_TYPE.boolean
38317
+ );
38318
+ }
38319
+ }
38320
+ if (op === TOKEN.neg && operand.type === PS_NODE.binary && operand.op === TOKEN.sub) {
38321
+ return this._makeBinary(TOKEN.sub, operand.second, operand.first);
38322
+ }
38323
+ if (operand.type === PS_NODE.unary) {
38324
+ if (op === TOKEN.neg && operand.op === TOKEN.neg || op === TOKEN.not && operand.op === TOKEN.not) {
38325
+ return operand.operand;
38326
+ }
38327
+ if (op === TOKEN.abs && operand.op === TOKEN.neg) {
38328
+ return this._makeUnary(TOKEN.abs, operand.operand);
38329
+ }
38330
+ if (_PSStackToTree.#idempotentUnary.has(op) && op === operand.op) {
38331
+ return operand;
38332
+ }
38333
+ }
38334
+ return new PsUnaryNode(op, operand, _unaryValueType(op, operand.valueType));
38335
+ }
38336
+ /**
38337
+ * Create a ternary node, applying optimizations eagerly:
38338
+ *
38339
+ * 1. Constant condition — fold to the live branch.
38340
+ * 2. Identical branches — the condition is irrelevant, return either branch.
38341
+ * 3. Boolean branch constants — `cond ? true : false` → cond,
38342
+ * `cond ? false : true` → not(cond).
38343
+ * 4. Ternary → branchless min/max when the condition compares two numeric
38344
+ * expressions that are also the two branches.
38345
+ */
38346
+ _makeTernary(cond, then, otherwise) {
38347
+ if (cond.type === PS_NODE.const) {
38348
+ return cond.value ? then : otherwise;
38349
+ }
38350
+ if (_nodesEqual(then, otherwise)) {
38351
+ return then;
38352
+ }
38353
+ if (then.type === PS_NODE.const && otherwise.type === PS_NODE.const) {
38354
+ if (then.value === true && otherwise.value === false) {
38355
+ return cond;
38356
+ }
38357
+ if (then.value === false && otherwise.value === true) {
38358
+ return this._makeUnary(TOKEN.not, cond);
38359
+ }
38360
+ }
38361
+ if (cond.type === PS_NODE.binary) {
38362
+ const { op: cop, first: cf, second: cs } = cond;
38363
+ if (cop === TOKEN.gt || cop === TOKEN.ge) {
38364
+ if (_nodesEqual(then, cf) && _nodesEqual(otherwise, cs)) {
38365
+ return this._makeBinary(TOKEN.min, cf, cs);
38366
+ }
38367
+ if (_nodesEqual(then, cs) && _nodesEqual(otherwise, cf)) {
38368
+ return this._makeBinary(TOKEN.max, cf, cs);
38369
+ }
38370
+ } else if (cop === TOKEN.lt || cop === TOKEN.le) {
38371
+ if (_nodesEqual(then, cf) && _nodesEqual(otherwise, cs)) {
38372
+ return this._makeBinary(TOKEN.max, cf, cs);
38373
+ }
38374
+ if (_nodesEqual(then, cs) && _nodesEqual(otherwise, cf)) {
38375
+ return this._makeBinary(TOKEN.min, cf, cs);
38376
+ }
38377
+ }
38378
+ }
38379
+ return new PsTernaryNode(
38380
+ cond,
38381
+ then,
38382
+ otherwise,
38383
+ then.valueType === otherwise.valueType ? then.valueType : PS_VALUE_TYPE.unknown
38384
+ );
38385
+ }
38386
+ };
38387
+ OP = {
38388
+ ARG: 0,
38389
+ // [ARG, idx]
38390
+ CONST: 1,
38391
+ // [CONST, val]
38392
+ STORE: 2,
38393
+ // [STORE, slot, min, max] clamp(pop()) → mem[slot]
38394
+ IF: 3,
38395
+ // [IF, target] jump when top-of-stack === 0
38396
+ JUMP: 4,
38397
+ // [JUMP, target] unconditional
38398
+ ABS: 5,
38399
+ NEG: 6,
38400
+ CEIL: 7,
38401
+ FLOOR: 8,
38402
+ ROUND: 9,
38403
+ // floor(x + 0.5)
38404
+ TRUNC: 10,
38405
+ NOT_B: 11,
38406
+ // boolean NOT
38407
+ NOT_N: 12,
38408
+ // bitwise NOT
38409
+ SQRT: 13,
38410
+ SIN: 14,
38411
+ // degrees in/out
38412
+ COS: 15,
38413
+ LN: 16,
38414
+ LOG10: 17,
38415
+ CVI: 18,
38416
+ SHIFT: 19,
38417
+ // [SHIFT, amount] +ve = left, −ve = right
38418
+ // Binary ops: second below, first on top; result = second OP first.
38419
+ ADD: 20,
38420
+ SUB: 21,
38421
+ MUL: 22,
38422
+ DIV: 23,
38423
+ // 0 when divisor is 0
38424
+ IDIV: 24,
38425
+ // 0 when divisor is 0
38426
+ MOD: 25,
38427
+ // 0 when divisor is 0
38428
+ POW: 26,
38429
+ EQ: 27,
38430
+ NE: 28,
38431
+ GT: 29,
38432
+ GE: 30,
38433
+ LT: 31,
38434
+ LE: 32,
38435
+ AND: 33,
38436
+ OR: 34,
38437
+ XOR: 35,
38438
+ ATAN: 36,
38439
+ // atan2(second, first) → degrees [0, 360)
38440
+ MIN: 37,
38441
+ MAX: 38,
38442
+ TEE_TMP: 39,
38443
+ // [TEE_TMP, slot] peek top of stack → tmp[slot], leave on stack
38444
+ LOAD_TMP: 40
38445
+ // [LOAD_TMP, slot] push tmp[slot]
38446
+ };
38447
+ _DEG_TO_RAD = Math.PI / 180;
38448
+ _RAD_TO_DEG = 180 / Math.PI;
38449
+ PsJsCompiler = class {
38450
+ // Safe because JS is single-threaded.
38451
+ static #stack = new Float64Array(64);
38452
+ static #tmp = new Float64Array(64);
38453
+ constructor(domain, range) {
38454
+ this.nIn = domain.length >> 1;
38455
+ this.nOut = range.length >> 1;
38456
+ this.range = range;
38457
+ this.ir = [];
38458
+ this._tmpMap = /* @__PURE__ */ new Map();
38459
+ this._nextTmp = 0;
38460
+ }
38461
+ _compileNode(node) {
38462
+ if (node.shared) {
38463
+ const cached = this._tmpMap.get(node);
38464
+ if (cached !== void 0) {
38465
+ this.ir.push(OP.LOAD_TMP, cached);
38466
+ return true;
38467
+ }
38468
+ if (!this._compileNodeImpl(node)) {
38469
+ return false;
38470
+ }
38471
+ const slot = this._nextTmp++;
38472
+ this._tmpMap.set(node, slot);
38473
+ this.ir.push(OP.TEE_TMP, slot);
38474
+ return true;
38475
+ }
38476
+ return this._compileNodeImpl(node);
38477
+ }
38478
+ _compileNodeImpl(node) {
38479
+ switch (node.type) {
38480
+ case PS_NODE.arg:
38481
+ this.ir.push(OP.ARG, node.index);
38482
+ return true;
38483
+ case PS_NODE.const: {
38484
+ const v = node.value;
38485
+ this.ir.push(OP.CONST, typeof v === "boolean" ? Number(v) : v);
38486
+ return true;
38487
+ }
38488
+ case PS_NODE.unary:
38489
+ return this._compileUnary(node);
38490
+ case PS_NODE.binary:
38491
+ return this._compileBinary(node);
38492
+ case PS_NODE.ternary:
38493
+ return this._compileTernary(node);
38494
+ default:
38495
+ return false;
38496
+ }
38497
+ }
38498
+ _compileUnary(node) {
38499
+ const { op, operand, valueType } = node;
38500
+ if (op === TOKEN.cvr) {
38501
+ return this._compileNode(operand);
38502
+ }
38503
+ if (!this._compileNode(operand)) {
38504
+ return false;
38505
+ }
38506
+ switch (op) {
38507
+ case TOKEN.abs:
38508
+ this.ir.push(OP.ABS);
38509
+ break;
38510
+ case TOKEN.neg:
38511
+ this.ir.push(OP.NEG);
38512
+ break;
38513
+ case TOKEN.ceiling:
38514
+ this.ir.push(OP.CEIL);
38515
+ break;
38516
+ case TOKEN.floor:
38517
+ this.ir.push(OP.FLOOR);
38518
+ break;
38519
+ case TOKEN.round:
38520
+ this.ir.push(OP.ROUND);
38521
+ break;
38522
+ case TOKEN.truncate:
38523
+ this.ir.push(OP.TRUNC);
38524
+ break;
38525
+ case TOKEN.sqrt:
38526
+ this.ir.push(OP.SQRT);
38527
+ break;
38528
+ case TOKEN.sin:
38529
+ this.ir.push(OP.SIN);
38530
+ break;
38531
+ case TOKEN.cos:
38532
+ this.ir.push(OP.COS);
38533
+ break;
38534
+ case TOKEN.ln:
38535
+ this.ir.push(OP.LN);
38536
+ break;
38537
+ case TOKEN.log:
38538
+ this.ir.push(OP.LOG10);
38539
+ break;
38540
+ case TOKEN.cvi:
38541
+ this.ir.push(OP.CVI);
38542
+ break;
38543
+ case TOKEN.not:
38544
+ if (valueType === PS_VALUE_TYPE.boolean) {
38545
+ this.ir.push(OP.NOT_B);
38546
+ } else if (valueType === PS_VALUE_TYPE.numeric) {
38547
+ this.ir.push(OP.NOT_N);
38548
+ } else {
38549
+ return false;
38550
+ }
38551
+ break;
38552
+ default:
38553
+ return false;
38554
+ }
38555
+ return true;
38556
+ }
38557
+ _compileBinary(node) {
38558
+ const { op, first, second } = node;
38559
+ if (op === TOKEN.bitshift) {
38560
+ if (first.type !== PS_NODE.const || !Number.isInteger(first.value) || !this._compileNode(second)) {
38561
+ return false;
38562
+ }
38563
+ this.ir.push(OP.SHIFT, first.value);
38564
+ return true;
38565
+ }
38566
+ if (!this._compileNode(second) || !this._compileNode(first)) {
38567
+ return false;
38568
+ }
38569
+ switch (op) {
38570
+ case TOKEN.add:
38571
+ this.ir.push(OP.ADD);
38572
+ break;
38573
+ case TOKEN.sub:
38574
+ this.ir.push(OP.SUB);
38575
+ break;
38576
+ case TOKEN.mul:
38577
+ this.ir.push(OP.MUL);
38578
+ break;
38579
+ case TOKEN.div:
38580
+ this.ir.push(OP.DIV);
38581
+ break;
38582
+ case TOKEN.idiv:
38583
+ this.ir.push(OP.IDIV);
38584
+ break;
38585
+ case TOKEN.mod:
38586
+ this.ir.push(OP.MOD);
38587
+ break;
38588
+ case TOKEN.exp:
38589
+ this.ir.push(OP.POW);
38590
+ break;
38591
+ case TOKEN.eq:
38592
+ this.ir.push(OP.EQ);
38593
+ break;
38594
+ case TOKEN.ne:
38595
+ this.ir.push(OP.NE);
38596
+ break;
38597
+ case TOKEN.gt:
38598
+ this.ir.push(OP.GT);
38599
+ break;
38600
+ case TOKEN.ge:
38601
+ this.ir.push(OP.GE);
38602
+ break;
38603
+ case TOKEN.lt:
38604
+ this.ir.push(OP.LT);
38605
+ break;
38606
+ case TOKEN.le:
38607
+ this.ir.push(OP.LE);
38608
+ break;
38609
+ case TOKEN.and:
38610
+ this.ir.push(OP.AND);
38611
+ break;
38612
+ case TOKEN.or:
38613
+ this.ir.push(OP.OR);
38614
+ break;
38615
+ case TOKEN.xor:
38616
+ this.ir.push(OP.XOR);
38617
+ break;
38618
+ case TOKEN.atan:
38619
+ this.ir.push(OP.ATAN);
38620
+ break;
38621
+ case TOKEN.min:
38622
+ this.ir.push(OP.MIN);
38623
+ break;
38624
+ case TOKEN.max:
38625
+ this.ir.push(OP.MAX);
38626
+ break;
38627
+ default:
38628
+ return false;
38629
+ }
38630
+ return true;
38631
+ }
38632
+ _compileTernary(node) {
38633
+ if (!this._compileNode(node.cond)) {
38634
+ return false;
38635
+ }
38636
+ this.ir.push(OP.IF, 0);
38637
+ const ifPatch = this.ir.length - 1;
38638
+ if (!this._compileNode(node.then)) {
38639
+ return false;
38640
+ }
38641
+ this.ir.push(OP.JUMP, 0);
38642
+ const jumpPatch = this.ir.length - 1;
38643
+ this.ir[ifPatch] = this.ir.length;
38644
+ if (!this._compileNode(node.otherwise)) {
38645
+ return false;
38646
+ }
38647
+ this.ir[jumpPatch] = this.ir.length;
38648
+ return true;
38649
+ }
38650
+ compile(program) {
38651
+ const outputs = new PSStackToTree().evaluate(program, this.nIn);
38652
+ if (!outputs || outputs.length < this.nOut) {
38653
+ return null;
38654
+ }
38655
+ for (let i = 0; i < this.nOut; i++) {
38656
+ if (!this._compileNode(outputs[i])) {
38657
+ return null;
38658
+ }
38659
+ const min = this.range[i * 2];
38660
+ const max = this.range[i * 2 + 1];
38661
+ this.ir.push(OP.STORE, i, min, max);
38662
+ }
38663
+ return new Float64Array(this.ir);
38664
+ }
38665
+ static execute(ir, src, srcOffset, dest, destOffset) {
38666
+ let ip = 0, sp = 0;
38667
+ const n = ir.length;
38668
+ const stack = this.#stack;
38669
+ const tmp = this.#tmp;
38670
+ while (ip < n) {
38671
+ switch (ir[ip++] | 0) {
38672
+ case OP.ARG:
38673
+ stack[sp++] = src[srcOffset + (ir[ip++] | 0)];
38674
+ break;
38675
+ case OP.CONST:
38676
+ stack[sp++] = ir[ip++];
38677
+ break;
38678
+ case OP.STORE: {
38679
+ const slot = ir[ip++] | 0;
38680
+ const min = ir[ip++];
38681
+ const max = ir[ip++];
38682
+ dest[destOffset + slot] = MathClamp(stack[--sp], min, max);
38683
+ break;
38684
+ }
38685
+ case OP.IF: {
38686
+ const tgt = ir[ip++];
38687
+ if (stack[--sp] === 0) {
38688
+ ip = tgt;
38689
+ }
38690
+ break;
38691
+ }
38692
+ case OP.JUMP:
38693
+ ip = ir[ip];
38694
+ break;
38695
+ case OP.ABS:
38696
+ stack[sp - 1] = Math.abs(stack[sp - 1]);
38697
+ break;
38698
+ case OP.NEG:
38699
+ stack[sp - 1] = -stack[sp - 1];
38700
+ break;
38701
+ case OP.CEIL:
38702
+ stack[sp - 1] = Math.ceil(stack[sp - 1]);
38703
+ break;
38704
+ case OP.FLOOR:
38705
+ stack[sp - 1] = Math.floor(stack[sp - 1]);
38706
+ break;
38707
+ case OP.ROUND:
38708
+ stack[sp - 1] = Math.floor(stack[sp - 1] + 0.5);
38709
+ break;
38710
+ case OP.TRUNC:
38711
+ stack[sp - 1] = Math.trunc(stack[sp - 1]);
38712
+ break;
38713
+ case OP.NOT_B:
38714
+ stack[sp - 1] = stack[sp - 1] !== 0 ? 0 : 1;
38715
+ break;
38716
+ case OP.NOT_N:
38717
+ stack[sp - 1] = ~(stack[sp - 1] | 0);
38718
+ break;
38719
+ case OP.SQRT:
38720
+ stack[sp - 1] = Math.sqrt(stack[sp - 1]);
38721
+ break;
38722
+ case OP.SIN:
38723
+ stack[sp - 1] = Math.sin(stack[sp - 1] % 360 * _DEG_TO_RAD);
38724
+ break;
38725
+ case OP.COS:
38726
+ stack[sp - 1] = Math.cos(stack[sp - 1] % 360 * _DEG_TO_RAD);
38727
+ break;
38728
+ case OP.LN:
38729
+ stack[sp - 1] = Math.log(stack[sp - 1]);
38730
+ break;
38731
+ case OP.LOG10:
38732
+ stack[sp - 1] = Math.log10(stack[sp - 1]);
38733
+ break;
38734
+ case OP.CVI:
38735
+ stack[sp - 1] = Math.trunc(stack[sp - 1]) | 0;
38736
+ break;
38737
+ case OP.SHIFT: {
38738
+ const amt = ir[ip++];
38739
+ const v = stack[sp - 1] | 0;
38740
+ if (amt > 0) {
38741
+ stack[sp - 1] = v << amt;
38742
+ } else if (amt < 0) {
38743
+ stack[sp - 1] = v >> -amt;
38744
+ } else {
38745
+ stack[sp - 1] = v;
38746
+ }
38747
+ break;
38748
+ }
38749
+ case OP.ADD: {
38750
+ const b = stack[--sp];
38751
+ stack[sp - 1] += b;
38752
+ break;
38753
+ }
38754
+ case OP.SUB: {
38755
+ const b = stack[--sp];
38756
+ stack[sp - 1] -= b;
38757
+ break;
38758
+ }
38759
+ case OP.MUL: {
38760
+ const b = stack[--sp];
38761
+ stack[sp - 1] *= b;
38762
+ break;
38763
+ }
38764
+ case OP.DIV: {
38765
+ const b = stack[--sp];
38766
+ stack[sp - 1] = b !== 0 ? stack[sp - 1] / b : 0;
38767
+ break;
38768
+ }
38769
+ case OP.IDIV: {
38770
+ const b = stack[--sp];
38771
+ stack[sp - 1] = b !== 0 ? Math.trunc(stack[sp - 1] / b) : 0;
38772
+ break;
38773
+ }
38774
+ case OP.MOD: {
38775
+ const b = stack[--sp];
38776
+ stack[sp - 1] = b !== 0 ? stack[sp - 1] % b : 0;
38777
+ break;
38778
+ }
38779
+ case OP.POW: {
38780
+ const b = stack[--sp];
38781
+ stack[sp - 1] **= b;
38782
+ break;
38783
+ }
38784
+ case OP.EQ: {
38785
+ const b = stack[--sp];
38786
+ stack[sp - 1] = stack[sp - 1] === b ? 1 : 0;
38787
+ break;
38788
+ }
38789
+ case OP.NE: {
38790
+ const b = stack[--sp];
38791
+ stack[sp - 1] = stack[sp - 1] !== b ? 1 : 0;
38792
+ break;
38793
+ }
38794
+ case OP.GT: {
38795
+ const b = stack[--sp];
38796
+ stack[sp - 1] = stack[sp - 1] > b ? 1 : 0;
38797
+ break;
38798
+ }
38799
+ case OP.GE: {
38800
+ const b = stack[--sp];
38801
+ stack[sp - 1] = stack[sp - 1] >= b ? 1 : 0;
38802
+ break;
38803
+ }
38804
+ case OP.LT: {
38805
+ const b = stack[--sp];
38806
+ stack[sp - 1] = stack[sp - 1] < b ? 1 : 0;
38807
+ break;
38808
+ }
38809
+ case OP.LE: {
38810
+ const b = stack[--sp];
38811
+ stack[sp - 1] = stack[sp - 1] <= b ? 1 : 0;
38812
+ break;
38813
+ }
38814
+ case OP.AND: {
38815
+ const b = stack[--sp] | 0;
38816
+ stack[sp - 1] = (stack[sp - 1] | 0) & b;
38817
+ break;
38818
+ }
38819
+ case OP.OR: {
38820
+ const b = stack[--sp] | 0;
38821
+ stack[sp - 1] = stack[sp - 1] | 0 | b;
38822
+ break;
38823
+ }
38824
+ case OP.XOR: {
38825
+ const b = stack[--sp] | 0;
38826
+ stack[sp - 1] = (stack[sp - 1] | 0) ^ b;
38827
+ break;
38828
+ }
38829
+ case OP.ATAN: {
38830
+ const b = stack[--sp];
38831
+ const deg = Math.atan2(stack[sp - 1], b) * _RAD_TO_DEG;
38832
+ stack[sp - 1] = deg < 0 ? deg + 360 : deg;
38833
+ break;
38834
+ }
38835
+ case OP.MIN: {
38836
+ const b = stack[--sp];
38837
+ stack[sp - 1] = Math.min(stack[sp - 1], b);
38838
+ break;
38839
+ }
38840
+ case OP.MAX: {
38841
+ const b = stack[--sp];
38842
+ stack[sp - 1] = Math.max(stack[sp - 1], b);
38843
+ break;
38844
+ }
38845
+ case OP.TEE_TMP:
38846
+ tmp[ir[ip++] | 0] = stack[sp - 1];
38847
+ break;
38848
+ case OP.LOAD_TMP:
38849
+ stack[sp++] = tmp[ir[ip++] | 0];
38850
+ break;
38851
+ }
38852
+ }
38853
+ }
38854
+ };
38855
+ PSStackBasedInterpreter = class {
38856
+ // Safe: JS is single-threaded.
38857
+ static #stack = new Float64Array(100);
38858
+ static #sp = 0;
38859
+ static #push(v) {
38860
+ if (this.#sp < this.#stack.length) {
38861
+ this.#stack[this.#sp++] = v;
38862
+ }
38863
+ }
38864
+ static #execOp(op) {
38865
+ const stack = this.#stack;
38866
+ switch (op) {
38867
+ case TOKEN.true:
38868
+ this.#push(1);
38869
+ break;
38870
+ case TOKEN.false:
38871
+ this.#push(0);
38872
+ break;
38873
+ case TOKEN.abs:
38874
+ stack[this.#sp - 1] = Math.abs(stack[this.#sp - 1]);
38875
+ break;
38876
+ case TOKEN.neg:
38877
+ stack[this.#sp - 1] = -stack[this.#sp - 1];
38878
+ break;
38879
+ case TOKEN.ceiling:
38880
+ stack[this.#sp - 1] = Math.ceil(stack[this.#sp - 1]);
38881
+ break;
38882
+ case TOKEN.floor:
38883
+ stack[this.#sp - 1] = Math.floor(stack[this.#sp - 1]);
38884
+ break;
38885
+ case TOKEN.round:
38886
+ stack[this.#sp - 1] = Math.floor(stack[this.#sp - 1] + 0.5);
38887
+ break;
38888
+ case TOKEN.truncate:
38889
+ stack[this.#sp - 1] = Math.trunc(stack[this.#sp - 1]);
38890
+ break;
38891
+ case TOKEN.sqrt:
38892
+ stack[this.#sp - 1] = Math.sqrt(stack[this.#sp - 1]);
38893
+ break;
38894
+ case TOKEN.sin:
38895
+ stack[this.#sp - 1] = Math.sin(
38896
+ stack[this.#sp - 1] % 360 * _DEG_TO_RAD
38897
+ );
38898
+ break;
38899
+ case TOKEN.cos:
38900
+ stack[this.#sp - 1] = Math.cos(
38901
+ stack[this.#sp - 1] % 360 * _DEG_TO_RAD
38902
+ );
38903
+ break;
38904
+ case TOKEN.ln:
38905
+ stack[this.#sp - 1] = Math.log(stack[this.#sp - 1]);
38906
+ break;
38907
+ case TOKEN.log:
38908
+ stack[this.#sp - 1] = Math.log10(stack[this.#sp - 1]);
38909
+ break;
38910
+ case TOKEN.cvi:
38911
+ stack[this.#sp - 1] = Math.trunc(stack[this.#sp - 1]) | 0;
38912
+ break;
38913
+ case TOKEN.cvr:
38914
+ break;
38915
+ // values are already f64
38916
+ case TOKEN.not: {
38917
+ const v = stack[this.#sp - 1];
38918
+ stack[this.#sp - 1] = v === 0 || v === 1 ? 1 - v : ~(v | 0);
38919
+ break;
38920
+ }
38921
+ case TOKEN.add: {
38922
+ const b = stack[--this.#sp];
38923
+ stack[this.#sp - 1] += b;
38924
+ break;
38925
+ }
38926
+ case TOKEN.sub: {
38927
+ const b = stack[--this.#sp];
38928
+ stack[this.#sp - 1] -= b;
38929
+ break;
38930
+ }
38931
+ case TOKEN.mul: {
38932
+ const b = stack[--this.#sp];
38933
+ stack[this.#sp - 1] *= b;
38934
+ break;
38935
+ }
38936
+ case TOKEN.div: {
38937
+ const b = stack[--this.#sp];
38938
+ stack[this.#sp - 1] = b !== 0 ? stack[this.#sp - 1] / b : 0;
38939
+ break;
38940
+ }
38941
+ case TOKEN.idiv: {
38942
+ const b = stack[--this.#sp];
38943
+ stack[this.#sp - 1] = b !== 0 ? Math.trunc(stack[this.#sp - 1] / b) : 0;
38944
+ break;
38945
+ }
38946
+ case TOKEN.mod: {
38947
+ const b = stack[--this.#sp];
38948
+ stack[this.#sp - 1] = b !== 0 ? stack[this.#sp - 1] % b : 0;
38949
+ break;
38950
+ }
38951
+ case TOKEN.exp: {
38952
+ const b = stack[--this.#sp];
38953
+ stack[this.#sp - 1] **= b;
38954
+ break;
38955
+ }
38956
+ case TOKEN.atan: {
38957
+ const dx = stack[--this.#sp];
38958
+ const deg = Math.atan2(stack[this.#sp - 1], dx) * _RAD_TO_DEG;
38959
+ stack[this.#sp - 1] = deg < 0 ? deg + 360 : deg;
38960
+ break;
38961
+ }
38962
+ case TOKEN.eq: {
38963
+ const b = stack[--this.#sp];
38964
+ stack[this.#sp - 1] = stack[this.#sp - 1] === b ? 1 : 0;
38965
+ break;
38966
+ }
38967
+ case TOKEN.ne: {
38968
+ const b = stack[--this.#sp];
38969
+ stack[this.#sp - 1] = stack[this.#sp - 1] !== b ? 1 : 0;
38970
+ break;
38971
+ }
38972
+ case TOKEN.gt: {
38973
+ const b = stack[--this.#sp];
38974
+ stack[this.#sp - 1] = stack[this.#sp - 1] > b ? 1 : 0;
38975
+ break;
38976
+ }
38977
+ case TOKEN.ge: {
38978
+ const b = stack[--this.#sp];
38979
+ stack[this.#sp - 1] = stack[this.#sp - 1] >= b ? 1 : 0;
38980
+ break;
38981
+ }
38982
+ case TOKEN.lt: {
38983
+ const b = stack[--this.#sp];
38984
+ stack[this.#sp - 1] = stack[this.#sp - 1] < b ? 1 : 0;
38985
+ break;
38986
+ }
38987
+ case TOKEN.le: {
38988
+ const b = stack[--this.#sp];
38989
+ stack[this.#sp - 1] = stack[this.#sp - 1] <= b ? 1 : 0;
38990
+ break;
38991
+ }
38992
+ case TOKEN.and: {
38993
+ const b = stack[--this.#sp] | 0;
38994
+ stack[this.#sp - 1] = (stack[this.#sp - 1] | 0) & b;
38995
+ break;
38996
+ }
38997
+ case TOKEN.or: {
38998
+ const b = stack[--this.#sp] | 0;
38999
+ stack[this.#sp - 1] = stack[this.#sp - 1] | 0 | b;
39000
+ break;
39001
+ }
39002
+ case TOKEN.xor: {
39003
+ const b = stack[--this.#sp] | 0;
39004
+ stack[this.#sp - 1] = (stack[this.#sp - 1] | 0) ^ b;
39005
+ break;
39006
+ }
39007
+ case TOKEN.bitshift: {
39008
+ const amt = stack[--this.#sp] | 0;
39009
+ const v = stack[this.#sp - 1] | 0;
39010
+ stack[this.#sp - 1] = amt > 0 ? v << amt : v >> -amt;
39011
+ break;
39012
+ }
39013
+ case TOKEN.min: {
39014
+ const b = stack[--this.#sp];
39015
+ stack[this.#sp - 1] = Math.min(stack[this.#sp - 1], b);
39016
+ break;
39017
+ }
39018
+ case TOKEN.max: {
39019
+ const b = stack[--this.#sp];
39020
+ stack[this.#sp - 1] = Math.max(stack[this.#sp - 1], b);
39021
+ break;
39022
+ }
39023
+ case TOKEN.dup:
39024
+ this.#push(stack[this.#sp - 1]);
39025
+ break;
39026
+ case TOKEN.exch: {
39027
+ const a = stack[--this.#sp];
39028
+ const b = stack[--this.#sp];
39029
+ this.#push(a);
39030
+ this.#push(b);
39031
+ break;
39032
+ }
39033
+ case TOKEN.pop:
39034
+ this.#sp--;
39035
+ break;
39036
+ case TOKEN.copy: {
39037
+ const n = Math.trunc(stack[--this.#sp]);
39038
+ const base = this.#sp - n;
39039
+ for (let k = 0; k < n; k++) {
39040
+ this.#push(stack[base + k]);
39041
+ }
39042
+ break;
39043
+ }
39044
+ case TOKEN.index: {
39045
+ const i = Math.trunc(stack[--this.#sp]);
39046
+ this.#push(stack[this.#sp - 1 - i]);
39047
+ break;
39048
+ }
39049
+ case TOKEN.roll: {
39050
+ const j = Math.trunc(stack[--this.#sp]);
39051
+ const n = Math.trunc(stack[--this.#sp]);
39052
+ if (n > 1 && j !== 0) {
39053
+ const mod = (j % n + n) % n;
39054
+ if (mod !== 0) {
39055
+ const base = this.#sp - n;
39056
+ const sub = stack.slice(base, this.#sp);
39057
+ for (let k = 0; k < n; k++) {
39058
+ stack[base + k] = sub[(k - mod + n) % n];
39059
+ }
39060
+ }
39061
+ }
39062
+ break;
39063
+ }
39064
+ }
39065
+ }
39066
+ static #execBlock(instructions) {
39067
+ for (const instr of instructions) {
39068
+ switch (instr.type) {
39069
+ case PS_NODE.number:
39070
+ this.#push(instr.value);
39071
+ break;
39072
+ case PS_NODE.operator:
39073
+ this.#execOp(instr.op);
39074
+ break;
39075
+ case PS_NODE.if:
39076
+ if (this.#stack[--this.#sp] !== 0) {
39077
+ this.#execBlock(instr.then.instructions);
39078
+ }
39079
+ break;
39080
+ case PS_NODE.ifelse:
39081
+ if (this.#stack[--this.#sp] !== 0) {
39082
+ this.#execBlock(instr.then.instructions);
39083
+ } else {
39084
+ this.#execBlock(instr.otherwise.instructions);
39085
+ }
39086
+ break;
39087
+ }
39088
+ }
39089
+ }
39090
+ /**
39091
+ * @param {import("./ast.js").PsProgram} program
39092
+ * @param {number[]} domain – flat [min0,max0, …]
39093
+ * @param {number[]} range – flat [min0,max0, …]
39094
+ * @returns {Function} – `(src, srcOffset, dest, destOffset) => void`
39095
+ */
39096
+ static build(program, domain, range) {
39097
+ const nIn = domain.length >> 1;
39098
+ const nOut = range.length >> 1;
39099
+ const { instructions } = program.body;
39100
+ return (src, srcOffset, dest, destOffset) => {
39101
+ this.#sp = 0;
39102
+ for (let i = 0; i < nIn; i++) {
39103
+ this.#push(src[srcOffset + i]);
39104
+ }
39105
+ this.#execBlock(instructions);
39106
+ const base = this.#sp - nOut;
39107
+ for (let i = 0; i < nOut; i++) {
39108
+ const v = base + i >= 0 ? this.#stack[base + i] : 0;
39109
+ dest[destOffset + i] = MathClamp(v, range[i * 2], range[i * 2 + 1]);
39110
+ }
39111
+ };
39112
+ }
39113
+ };
36797
39114
  PdfError = class extends Error {
36798
39115
  constructor(code, message) {
36799
39116
  super(message);
@@ -40840,6 +43157,9 @@ var init_dist = __esm({
40840
43157
  __webpack_exports__VerbosityLevel = __webpack_exports__.VerbosityLevel;
40841
43158
  __webpack_exports__getVerbosityLevel = __webpack_exports__.getVerbosityLevel;
40842
43159
  __webpack_exports__setVerbosityLevel = __webpack_exports__.setVerbosityLevel;
43160
+ cmykColorSpace = new DeviceCmykCS();
43161
+ cmykColorSpace2 = new DeviceCmykCS();
43162
+ postScriptFunctions = /* @__PURE__ */ new WeakMap();
40843
43163
  ACROFORM_FONT_ALIAS_MAP = {
40844
43164
  Helv: "Helvetica",
40845
43165
  HeBo: "Helvetica-Bold",
@@ -40919,7 +43239,7 @@ var init_dist = __esm({
40919
43239
  return [n0.value, n1.value, n2.value, n3.value];
40920
43240
  }
40921
43241
  }
40922
- return [0, 0, 612, 792];
43242
+ return key === "MediaBox" ? [0, 0, 612, 792] : this.resolveBox("MediaBox");
40923
43243
  }
40924
43244
  getMediaBox() {
40925
43245
  return this.resolveBox("MediaBox");
@@ -41592,16 +43912,19 @@ var init_dist = __esm({
41592
43912
  });
41593
43913
  }
41594
43914
  }
41595
- return evaluateContentStreamToDisplayList({
43915
+ const mediaBox = this.getMediaBox(), cropBox = this.getCropBox();
43916
+ const originX = Math.min(mediaBox[0], mediaBox[2]), originY = Math.min(mediaBox[1], mediaBox[3]);
43917
+ return { ...evaluateContentStreamToDisplayList({
41596
43918
  pageIndex: this.index,
41597
43919
  width,
41598
43920
  height,
43921
+ origin: [originX, originY],
41599
43922
  rotation: this.getRotation(),
41600
43923
  nodes: baseNodes,
41601
43924
  cosDoc: this.cosDoc,
41602
43925
  resourcesDict: evalResourcesDict,
41603
43926
  annotations: extractPageAnnotations(this.cosDoc, this.pageDict)
41604
- });
43927
+ }), cropBox: [cropBox[0] - originX, cropBox[1] - originY, cropBox[2] - originX, cropBox[3] - originY] };
41605
43928
  }
41606
43929
  extractPage(options) {
41607
43930
  const dl = this.evaluateDisplayList();
@@ -41619,10 +43942,10 @@ var init_dist = __esm({
41619
43942
  return extractTablesFromDisplayList(this.evaluateDisplayList());
41620
43943
  }
41621
43944
  renderToBitmap(options) {
41622
- return renderDisplayListToBitmap(this.evaluateDisplayList(), options);
43945
+ return renderDisplayListToBitmap(this.evaluateDisplayList({ hideAnnotations: options?.hideAnnotations }), options);
41623
43946
  }
41624
43947
  renderToPng(options) {
41625
- return renderDisplayListToPng(this.evaluateDisplayList(), options);
43948
+ return renderDisplayListToPng(this.evaluateDisplayList({ hideAnnotations: options?.hideAnnotations }), options);
41626
43949
  }
41627
43950
  };
41628
43951
  MAX_STROKE_VERTICES = 1e6;