@poe-platform/safe-bash 0.1.762 → 0.1.763

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 (28) hide show
  1. package/dist/image-ast/index.browser.js +186 -55
  2. package/dist/image-ast/index.js +186 -55
  3. package/dist/pdf-ast/ast.d.ts +23 -0
  4. package/dist/pdf-ast/index.js +273 -91
  5. package/dist/safe-bash/command-chunks/{chunk-D4GXXV65.js → chunk-4XHONGIU.js} +2 -2
  6. package/dist/safe-bash/command-chunks/{chunk-P3Q2QSCA.js → chunk-S3G2B4OX.js} +186 -55
  7. package/dist/safe-bash/command-chunks/{chunk-F7MJRXQ2.js → chunk-S5EX6UP5.js} +1 -1
  8. package/dist/safe-bash/core.browser.js +1 -1
  9. package/dist/safe-bash/shell/runtime.js +1 -1
  10. package/dist/safe-bash-checksum-engine/index.d.ts +1 -1
  11. package/dist/safe-bash-checksum-engine/index.js +5 -1
  12. package/dist/safe-bash-command-ffmpeg/index.js +7486 -7432
  13. package/dist/safe-bash-command-gh/index.js +174 -105
  14. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  15. package/dist/safe-bash-command-pandoc/command.js +3 -3
  16. package/dist/safe-bash-command-pandoc/index.js +3 -3
  17. package/dist/safe-bash-command-pdfimages/index.js +186 -55
  18. package/dist/safe-bash-command-pdfinfo/index.js +273 -91
  19. package/dist/safe-bash-command-pdftk/index.js +186 -55
  20. package/dist/safe-bash-command-pdftoppm/index.js +273 -91
  21. package/dist/safe-bash-command-pdftotext/index.js +186 -55
  22. package/dist/safe-bash-command-qpdf/index.js +186 -55
  23. package/dist/safe-bash-command-sips/index.js +2 -2
  24. package/dist/safe-bash-command-soffice/index.js +1 -1
  25. package/dist/safe-bash-command-ssconvert/index.js +249 -58
  26. package/dist/safe-bash-command-wkhtmltopdf/index.js +186 -55
  27. package/package.json +2 -2
  28. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +13 -0
@@ -43567,14 +43567,18 @@ function evaluateContentStreamToDisplayList(params) {
43567
43567
  const paths = [];
43568
43568
  const images = [];
43569
43569
  const operations = [];
43570
+ let capturedOperations;
43571
+ let insideSoftMask = false;
43570
43572
  const emit = (operation) => {
43571
- const { clipPaths, clipImages } = curState();
43572
- if (clipPaths || clipImages) operation = { ...operation, value: {
43573
+ const { clipPaths, clipImages, softMask } = curState();
43574
+ if (clipPaths || clipImages || softMask) operation = { ...operation, value: {
43573
43575
  ...operation.value,
43574
43576
  ...clipPaths ? { clipPaths } : {},
43575
- ...clipImages ? { clipImages } : {}
43577
+ ...clipImages ? { clipImages } : {},
43578
+ ...softMask ? { softMask } : {}
43576
43579
  } };
43577
- operations.push(operation);
43580
+ (capturedOperations ?? operations).push(operation);
43581
+ if (insideSoftMask) return;
43578
43582
  switch (operation.kind) {
43579
43583
  case "path":
43580
43584
  paths.push(operation.value);
@@ -43680,7 +43684,7 @@ function evaluateContentStreamToDisplayList(params) {
43680
43684
  );
43681
43685
  return { r: kClamp(r), g: kClamp(g), b: kClamp(b) };
43682
43686
  };
43683
- const applyStateOperator = (st, operator, ops, activeResources) => {
43687
+ const applyStateOperator = (st, operator, ops, activeResources, activeFonts, depth) => {
43684
43688
  const num = (i, fb = 0) => ops[i]?.kind === "number" ? ops[i].value : fb;
43685
43689
  if (operator === "cm") {
43686
43690
  const m = [num(0, 1), num(1, 0), num(2, 0), num(3, 1), num(4, 0), num(5, 0)];
@@ -43763,6 +43767,46 @@ function evaluateContentStreamToDisplayList(params) {
43763
43767
  const extDict = params.cosDoc.resolveDict(dictGet(activeResources, "ExtGState"));
43764
43768
  const gsDict = extDict ? params.cosDoc.resolveDict(dictGet(extDict, ops[0].decoded)) : void 0;
43765
43769
  if (gsDict) {
43770
+ const mask = params.cosDoc.resolve(dictGet(gsDict, "SMask"));
43771
+ if (mask?.kind === "name" && mask.decoded === "None") {
43772
+ st.softMask = void 0;
43773
+ } else if (mask?.kind === "dict") {
43774
+ const subtype = params.cosDoc.resolve(dictGet(mask, "S"));
43775
+ const form = params.cosDoc.resolve(dictGet(mask, "G"));
43776
+ if (form?.kind === "stream" && subtype?.kind === "name" && (subtype.decoded === "Alpha" || subtype.decoded === "Luminosity")) {
43777
+ if (depth >= 8) throw new PdfError("E_LIMIT", "Soft-mask nesting exceeds the form depth limit");
43778
+ const parentOperations = capturedOperations;
43779
+ const parentInsideSoftMask = insideSoftMask;
43780
+ const savedTextState = { pendingTextClip, hasTextClip, activeTm, activeTlm };
43781
+ const captured = [];
43782
+ capturedOperations = captured;
43783
+ insideSoftMask = true;
43784
+ const maskState = { ...st, softMask: void 0, fillAlpha: 1, strokeAlpha: 1, blendMode: "Normal" };
43785
+ delete maskState.clipPaths;
43786
+ delete maskState.clipImages;
43787
+ delete maskState.clipRect;
43788
+ stateStack.push(maskState);
43789
+ try {
43790
+ paintForm(form, activeResources, activeFonts, depth, void 0, void 0, true);
43791
+ } finally {
43792
+ stateStack.pop();
43793
+ capturedOperations = parentOperations;
43794
+ insideSoftMask = parentInsideSoftMask;
43795
+ ({ pendingTextClip, hasTextClip, activeTm, activeTlm } = savedTextState);
43796
+ }
43797
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
43798
+ const colorSpace = group ? dictGet(group, "CS") : void 0;
43799
+ const bc = params.cosDoc.resolveArray(dictGet(mask, "BC"));
43800
+ const components2 = bc?.items.map((item) => {
43801
+ const value = params.cosDoc.resolve(item);
43802
+ return value?.kind === "number" ? value.value : 0;
43803
+ });
43804
+ const [r, g, b] = components2 ? convertColorSpaceComponentsToRgb(params.cosDoc, colorSpace, "DeviceRGB", components2, activeResources) : [0, 0, 0];
43805
+ const transfer = params.cosDoc.resolve(dictGet(mask, "TR"));
43806
+ const transferMap = transfer?.kind === "dict" || transfer?.kind === "stream" ? Uint8Array.from({ length: 256 }, (_, i) => Math.floor(kClamp(Math.fround(evalShadingFunctionToComponents(params.cosDoc, transfer, Math.fround(i / 255))[0] ?? 0)) * 255)) : void 0;
43807
+ st.softMask = { subtype: subtype.decoded, operations: captured, backdrop: { r, g, b }, transferMap };
43808
+ }
43809
+ }
43766
43810
  const bmNode = params.cosDoc.resolve(dictGet(gsDict, "BM"));
43767
43811
  if (bmNode?.kind === "name") {
43768
43812
  st.blendMode = bmNode.decoded === "Compatible" ? "Normal" : bmNode.decoded;
@@ -43849,6 +43893,84 @@ function evaluateContentStreamToDisplayList(params) {
43849
43893
  ] }], void 0, void 0, resources, activeFonts, depth);
43850
43894
  stateStack.pop();
43851
43895
  };
43896
+ const paintForm = (form, activeResources, activeFonts, depth, mcid, actualText, maskGroup = false) => {
43897
+ const st = curState();
43898
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
43899
+ const groupType = group ? params.cosDoc.resolve(dictGet(group, "S")) : void 0;
43900
+ const isolated = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
43901
+ const isolate = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && isolated?.kind === "boolean" && isolated.value;
43902
+ const formStreamBytes = params.cosDoc.decodeStream(form);
43903
+ const formNodes = parseContentStream(formStreamBytes);
43904
+ const formResDict = params.cosDoc.resolveDict(dictGet(form.dict, "Resources")) ?? activeResources;
43905
+ const formFonts = new Map(activeFonts);
43906
+ for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
43907
+ formFonts.set(k, v);
43908
+ }
43909
+ let nextCtm = [...st.ctm];
43910
+ const matArr = params.cosDoc.resolveArray(dictGet(form.dict, "Matrix"));
43911
+ if (matArr && matArr.items.length >= 6) {
43912
+ const mn = (idx, fb = 0) => {
43913
+ const resolved = params.cosDoc.resolve(matArr.items[idx]);
43914
+ return resolved?.kind === "number" ? resolved.value : fb;
43915
+ };
43916
+ const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
43917
+ nextCtm = multiplyMatrices(formMat, nextCtm);
43918
+ }
43919
+ let nextClip = !isolate && st.clipRect ? [...st.clipRect] : void 0;
43920
+ let nextClipPaths = isolate ? void 0 : st.clipPaths;
43921
+ const bboxArr = params.cosDoc.resolveArray(dictGet(form.dict, "BBox"));
43922
+ if (bboxArr && bboxArr.items.length >= 4) {
43923
+ const bn = (idx, fb = 0) => {
43924
+ const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
43925
+ return resolved?.kind === "number" ? resolved.value : fb;
43926
+ };
43927
+ const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
43928
+ const pts = [
43929
+ transformPoint(nextCtm, bx0, by0),
43930
+ transformPoint(nextCtm, bx1, by0),
43931
+ transformPoint(nextCtm, bx1, by1),
43932
+ transformPoint(nextCtm, bx0, by1)
43933
+ ];
43934
+ nextClipPaths = [...nextClipPaths ?? [], [
43935
+ ...pts.map(([x, y], index) => ({ kind: index === 0 ? "move" : "line", x, y })),
43936
+ { kind: "close" }
43937
+ ]];
43938
+ const fMinX = Math.min(...pts.map((p) => p[0]));
43939
+ const fMinY = Math.min(...pts.map((p) => p[1]));
43940
+ const fMaxX = Math.max(...pts.map((p) => p[0]));
43941
+ const fMaxY = Math.max(...pts.map((p) => p[1]));
43942
+ if (fMaxX > fMinX && fMaxY > fMinY) {
43943
+ nextClip = nextClip ? [
43944
+ Math.max(nextClip[0], fMinX),
43945
+ Math.max(nextClip[1], fMinY),
43946
+ Math.min(nextClip[2], fMaxX),
43947
+ Math.min(nextClip[3], fMaxY)
43948
+ ] : [fMinX, fMinY, fMaxX, fMaxY];
43949
+ }
43950
+ }
43951
+ const parentOperations = capturedOperations;
43952
+ const children = [];
43953
+ const nextState = { ...st, ctm: nextCtm };
43954
+ if (isolate) {
43955
+ capturedOperations = children;
43956
+ nextState.fillAlpha = nextState.strokeAlpha = 1;
43957
+ nextState.blendMode = "Normal";
43958
+ nextState.softMask = void 0;
43959
+ delete nextState.clipImages;
43960
+ delete nextState.clipPaths;
43961
+ delete nextState.clipRect;
43962
+ }
43963
+ if (nextClip) nextState.clipRect = nextClip;
43964
+ if (nextClipPaths) nextState.clipPaths = nextClipPaths;
43965
+ stateStack.push(nextState);
43966
+ try {
43967
+ walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
43968
+ } finally {
43969
+ stateStack.pop();
43970
+ capturedOperations = parentOperations;
43971
+ }
43972
+ if (isolate) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
43973
+ };
43852
43974
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
43853
43975
  for (const node of nodes) {
43854
43976
  switch (node.kind) {
@@ -43893,7 +44015,7 @@ function evaluateContentStreamToDisplayList(params) {
43893
44015
  break;
43894
44016
  }
43895
44017
  case "state-op": {
43896
- applyStateOperator(curState(), node.operator, node.operands, activeResources);
44018
+ applyStateOperator(curState(), node.operator, node.operands, activeResources, activeFonts, depth);
43897
44019
  break;
43898
44020
  }
43899
44021
  case "path-op": {
@@ -44179,53 +44301,7 @@ function evaluateContentStreamToDisplayList(params) {
44179
44301
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
44180
44302
  }, patternMask, activeResources, activeFonts, depth);
44181
44303
  } else if (sub === "Form" && depth < 8) {
44182
- const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
44183
- const formNodes = parseContentStream(formStreamBytes);
44184
- const formResDict = params.cosDoc.resolveDict(dictGet(xobjNode.dict, "Resources")) ?? activeResources;
44185
- const formFonts = new Map(activeFonts);
44186
- for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
44187
- formFonts.set(k, v);
44188
- }
44189
- let nextCtm = [...st.ctm];
44190
- const matArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "Matrix"));
44191
- if (matArr && matArr.items.length >= 6) {
44192
- const mn = (idx, fb = 0) => {
44193
- const resolved = params.cosDoc.resolve(matArr.items[idx]);
44194
- return resolved?.kind === "number" ? resolved.value : fb;
44195
- };
44196
- const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
44197
- nextCtm = multiplyMatrices(formMat, nextCtm);
44198
- }
44199
- let nextClip = st.clipRect ? [...st.clipRect] : void 0;
44200
- const bboxArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "BBox"));
44201
- if (bboxArr && bboxArr.items.length >= 4) {
44202
- const bn = (idx, fb = 0) => {
44203
- const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
44204
- return resolved?.kind === "number" ? resolved.value : fb;
44205
- };
44206
- const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
44207
- const pts = [
44208
- transformPoint(nextCtm, bx0, by0),
44209
- transformPoint(nextCtm, bx1, by0),
44210
- transformPoint(nextCtm, bx0, by1),
44211
- transformPoint(nextCtm, bx1, by1)
44212
- ];
44213
- const fMinX = Math.min(...pts.map((p) => p[0]));
44214
- const fMinY = Math.min(...pts.map((p) => p[1]));
44215
- const fMaxX = Math.max(...pts.map((p) => p[0]));
44216
- const fMaxY = Math.max(...pts.map((p) => p[1]));
44217
- if (fMaxX > fMinX && fMaxY > fMinY) {
44218
- nextClip = nextClip ? [
44219
- Math.max(nextClip[0], fMinX),
44220
- Math.max(nextClip[1], fMinY),
44221
- Math.min(nextClip[2], fMaxX),
44222
- Math.min(nextClip[3], fMaxY)
44223
- ] : [fMinX, fMinY, fMaxX, fMaxY];
44224
- }
44225
- }
44226
- stateStack.push({ ...st, ctm: nextCtm, ...nextClip ? { clipRect: nextClip } : {} });
44227
- walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
44228
- if (stateStack.length > 1) stateStack.pop();
44304
+ paintForm(xobjNode, activeResources, activeFonts, depth, mcid, actualText);
44229
44305
  }
44230
44306
  }
44231
44307
  }
@@ -44444,7 +44520,7 @@ function evaluateContentStreamToDisplayList(params) {
44444
44520
  st.textRenderMode = cmd.mode;
44445
44521
  break;
44446
44522
  case "state-op":
44447
- applyStateOperator(st, cmd.operator, cmd.operands, activeResources);
44523
+ applyStateOperator(st, cmd.operator, cmd.operands, activeResources, activeFonts, depth);
44448
44524
  break;
44449
44525
  case "show-text":
44450
44526
  emitTokenBytes(cmd.token.bytes);
@@ -47657,6 +47733,30 @@ function paintOperations(displayList) {
47657
47733
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
47658
47734
  ];
47659
47735
  }
47736
+ function renderSoftMask(mask, displayList, scale) {
47737
+ const bitmap = renderDisplayListToBitmap({
47738
+ ...displayList,
47739
+ rotation: 0,
47740
+ glyphs: [],
47741
+ paths: [],
47742
+ images: [],
47743
+ operations: mask.operations
47744
+ }, { scale, transparent: true });
47745
+ const { data } = bitmap;
47746
+ for (let i = 0; i < data.length; i += 4) {
47747
+ let value = data[i + 3];
47748
+ if (mask.subtype === "Luminosity") {
47749
+ const alpha = value / 255;
47750
+ const r = Math.round(data[i] * alpha + mask.backdrop.r * 255 * (1 - alpha));
47751
+ const g = Math.round(data[i + 1] * alpha + mask.backdrop.g * 255 * (1 - alpha));
47752
+ const b = Math.round(data[i + 2] * alpha + mask.backdrop.b * 255 * (1 - alpha));
47753
+ value = Math.round(pdfLum(r, g, b));
47754
+ }
47755
+ data[i] = data[i + 1] = data[i + 2] = 0;
47756
+ data[i + 3] = mask.transferMap?.[value] ?? value;
47757
+ }
47758
+ return bitmap;
47759
+ }
47660
47760
  function renderDisplayListToBitmap(displayList, options = {}) {
47661
47761
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
47662
47762
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -47680,10 +47780,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47680
47780
  const aaTxt = options.antialiasText !== false;
47681
47781
  let cachedClips;
47682
47782
  let cachedClipMask;
47783
+ let cachedSoftMask;
47784
+ let cachedSoftMaskPixels;
47683
47785
  const imageClipMasks = /* @__PURE__ */ new Map();
47684
47786
  for (const original of paintOperations(displayList)) {
47685
47787
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
47686
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
47788
+ let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
47789
+ if (operation.kind === "group") {
47790
+ const group = operation.value;
47791
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
47792
+ for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
47793
+ operation = { kind: "image", value: {
47794
+ name: "TransparencyGroup",
47795
+ width: bitmap.width,
47796
+ height: bitmap.height,
47797
+ decodedRgba: bitmap.data,
47798
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
47799
+ colorSpace: "DeviceRGB",
47800
+ bitsPerComponent: 8,
47801
+ blendMode: group.blendMode,
47802
+ clipRect: group.clipRect
47803
+ } };
47804
+ }
47687
47805
  const clips = original.value.clipPaths;
47688
47806
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
47689
47807
  if (clips && !clipMask) {
@@ -47697,6 +47815,19 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47697
47815
  cachedClips = clips;
47698
47816
  cachedClipMask = clipMask;
47699
47817
  }
47818
+ const softMask = original.value.softMask;
47819
+ if (softMask) {
47820
+ if (softMask !== cachedSoftMask) {
47821
+ cachedSoftMaskPixels = renderSoftMask(softMask, displayList, scale).data;
47822
+ cachedSoftMask = softMask;
47823
+ }
47824
+ if (clipMask) {
47825
+ clipMask = clipMask.slice();
47826
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * cachedSoftMaskPixels[i] / 255);
47827
+ } else {
47828
+ clipMask = cachedSoftMaskPixels;
47829
+ }
47830
+ }
47700
47831
  const imageClips = original.value.clipImages;
47701
47832
  if (imageClips) {
47702
47833
  let imageMask = imageClipMasks.get(imageClips);
@@ -43567,14 +43567,18 @@ function evaluateContentStreamToDisplayList(params) {
43567
43567
  const paths = [];
43568
43568
  const images = [];
43569
43569
  const operations = [];
43570
+ let capturedOperations;
43571
+ let insideSoftMask = false;
43570
43572
  const emit = (operation) => {
43571
- const { clipPaths, clipImages } = curState();
43572
- if (clipPaths || clipImages) operation = { ...operation, value: {
43573
+ const { clipPaths, clipImages, softMask } = curState();
43574
+ if (clipPaths || clipImages || softMask) operation = { ...operation, value: {
43573
43575
  ...operation.value,
43574
43576
  ...clipPaths ? { clipPaths } : {},
43575
- ...clipImages ? { clipImages } : {}
43577
+ ...clipImages ? { clipImages } : {},
43578
+ ...softMask ? { softMask } : {}
43576
43579
  } };
43577
- operations.push(operation);
43580
+ (capturedOperations ?? operations).push(operation);
43581
+ if (insideSoftMask) return;
43578
43582
  switch (operation.kind) {
43579
43583
  case "path":
43580
43584
  paths.push(operation.value);
@@ -43680,7 +43684,7 @@ function evaluateContentStreamToDisplayList(params) {
43680
43684
  );
43681
43685
  return { r: kClamp(r), g: kClamp(g), b: kClamp(b) };
43682
43686
  };
43683
- const applyStateOperator = (st, operator, ops, activeResources) => {
43687
+ const applyStateOperator = (st, operator, ops, activeResources, activeFonts, depth) => {
43684
43688
  const num = (i, fb = 0) => ops[i]?.kind === "number" ? ops[i].value : fb;
43685
43689
  if (operator === "cm") {
43686
43690
  const m = [num(0, 1), num(1, 0), num(2, 0), num(3, 1), num(4, 0), num(5, 0)];
@@ -43763,6 +43767,46 @@ function evaluateContentStreamToDisplayList(params) {
43763
43767
  const extDict = params.cosDoc.resolveDict(dictGet(activeResources, "ExtGState"));
43764
43768
  const gsDict = extDict ? params.cosDoc.resolveDict(dictGet(extDict, ops[0].decoded)) : void 0;
43765
43769
  if (gsDict) {
43770
+ const mask = params.cosDoc.resolve(dictGet(gsDict, "SMask"));
43771
+ if (mask?.kind === "name" && mask.decoded === "None") {
43772
+ st.softMask = void 0;
43773
+ } else if (mask?.kind === "dict") {
43774
+ const subtype = params.cosDoc.resolve(dictGet(mask, "S"));
43775
+ const form = params.cosDoc.resolve(dictGet(mask, "G"));
43776
+ if (form?.kind === "stream" && subtype?.kind === "name" && (subtype.decoded === "Alpha" || subtype.decoded === "Luminosity")) {
43777
+ if (depth >= 8) throw new PdfError("E_LIMIT", "Soft-mask nesting exceeds the form depth limit");
43778
+ const parentOperations = capturedOperations;
43779
+ const parentInsideSoftMask = insideSoftMask;
43780
+ const savedTextState = { pendingTextClip, hasTextClip, activeTm, activeTlm };
43781
+ const captured = [];
43782
+ capturedOperations = captured;
43783
+ insideSoftMask = true;
43784
+ const maskState = { ...st, softMask: void 0, fillAlpha: 1, strokeAlpha: 1, blendMode: "Normal" };
43785
+ delete maskState.clipPaths;
43786
+ delete maskState.clipImages;
43787
+ delete maskState.clipRect;
43788
+ stateStack.push(maskState);
43789
+ try {
43790
+ paintForm(form, activeResources, activeFonts, depth, void 0, void 0, true);
43791
+ } finally {
43792
+ stateStack.pop();
43793
+ capturedOperations = parentOperations;
43794
+ insideSoftMask = parentInsideSoftMask;
43795
+ ({ pendingTextClip, hasTextClip, activeTm, activeTlm } = savedTextState);
43796
+ }
43797
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
43798
+ const colorSpace = group ? dictGet(group, "CS") : void 0;
43799
+ const bc = params.cosDoc.resolveArray(dictGet(mask, "BC"));
43800
+ const components2 = bc?.items.map((item) => {
43801
+ const value = params.cosDoc.resolve(item);
43802
+ return value?.kind === "number" ? value.value : 0;
43803
+ });
43804
+ const [r, g, b] = components2 ? convertColorSpaceComponentsToRgb(params.cosDoc, colorSpace, "DeviceRGB", components2, activeResources) : [0, 0, 0];
43805
+ const transfer = params.cosDoc.resolve(dictGet(mask, "TR"));
43806
+ const transferMap = transfer?.kind === "dict" || transfer?.kind === "stream" ? Uint8Array.from({ length: 256 }, (_, i) => Math.floor(kClamp(Math.fround(evalShadingFunctionToComponents(params.cosDoc, transfer, Math.fround(i / 255))[0] ?? 0)) * 255)) : void 0;
43807
+ st.softMask = { subtype: subtype.decoded, operations: captured, backdrop: { r, g, b }, transferMap };
43808
+ }
43809
+ }
43766
43810
  const bmNode = params.cosDoc.resolve(dictGet(gsDict, "BM"));
43767
43811
  if (bmNode?.kind === "name") {
43768
43812
  st.blendMode = bmNode.decoded === "Compatible" ? "Normal" : bmNode.decoded;
@@ -43849,6 +43893,84 @@ function evaluateContentStreamToDisplayList(params) {
43849
43893
  ] }], void 0, void 0, resources, activeFonts, depth);
43850
43894
  stateStack.pop();
43851
43895
  };
43896
+ const paintForm = (form, activeResources, activeFonts, depth, mcid, actualText, maskGroup = false) => {
43897
+ const st = curState();
43898
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
43899
+ const groupType = group ? params.cosDoc.resolve(dictGet(group, "S")) : void 0;
43900
+ const isolated = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
43901
+ const isolate = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && isolated?.kind === "boolean" && isolated.value;
43902
+ const formStreamBytes = params.cosDoc.decodeStream(form);
43903
+ const formNodes = parseContentStream(formStreamBytes);
43904
+ const formResDict = params.cosDoc.resolveDict(dictGet(form.dict, "Resources")) ?? activeResources;
43905
+ const formFonts = new Map(activeFonts);
43906
+ for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
43907
+ formFonts.set(k, v);
43908
+ }
43909
+ let nextCtm = [...st.ctm];
43910
+ const matArr = params.cosDoc.resolveArray(dictGet(form.dict, "Matrix"));
43911
+ if (matArr && matArr.items.length >= 6) {
43912
+ const mn = (idx, fb = 0) => {
43913
+ const resolved = params.cosDoc.resolve(matArr.items[idx]);
43914
+ return resolved?.kind === "number" ? resolved.value : fb;
43915
+ };
43916
+ const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
43917
+ nextCtm = multiplyMatrices(formMat, nextCtm);
43918
+ }
43919
+ let nextClip = !isolate && st.clipRect ? [...st.clipRect] : void 0;
43920
+ let nextClipPaths = isolate ? void 0 : st.clipPaths;
43921
+ const bboxArr = params.cosDoc.resolveArray(dictGet(form.dict, "BBox"));
43922
+ if (bboxArr && bboxArr.items.length >= 4) {
43923
+ const bn = (idx, fb = 0) => {
43924
+ const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
43925
+ return resolved?.kind === "number" ? resolved.value : fb;
43926
+ };
43927
+ const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
43928
+ const pts = [
43929
+ transformPoint(nextCtm, bx0, by0),
43930
+ transformPoint(nextCtm, bx1, by0),
43931
+ transformPoint(nextCtm, bx1, by1),
43932
+ transformPoint(nextCtm, bx0, by1)
43933
+ ];
43934
+ nextClipPaths = [...nextClipPaths ?? [], [
43935
+ ...pts.map(([x, y], index) => ({ kind: index === 0 ? "move" : "line", x, y })),
43936
+ { kind: "close" }
43937
+ ]];
43938
+ const fMinX = Math.min(...pts.map((p) => p[0]));
43939
+ const fMinY = Math.min(...pts.map((p) => p[1]));
43940
+ const fMaxX = Math.max(...pts.map((p) => p[0]));
43941
+ const fMaxY = Math.max(...pts.map((p) => p[1]));
43942
+ if (fMaxX > fMinX && fMaxY > fMinY) {
43943
+ nextClip = nextClip ? [
43944
+ Math.max(nextClip[0], fMinX),
43945
+ Math.max(nextClip[1], fMinY),
43946
+ Math.min(nextClip[2], fMaxX),
43947
+ Math.min(nextClip[3], fMaxY)
43948
+ ] : [fMinX, fMinY, fMaxX, fMaxY];
43949
+ }
43950
+ }
43951
+ const parentOperations = capturedOperations;
43952
+ const children = [];
43953
+ const nextState = { ...st, ctm: nextCtm };
43954
+ if (isolate) {
43955
+ capturedOperations = children;
43956
+ nextState.fillAlpha = nextState.strokeAlpha = 1;
43957
+ nextState.blendMode = "Normal";
43958
+ nextState.softMask = void 0;
43959
+ delete nextState.clipImages;
43960
+ delete nextState.clipPaths;
43961
+ delete nextState.clipRect;
43962
+ }
43963
+ if (nextClip) nextState.clipRect = nextClip;
43964
+ if (nextClipPaths) nextState.clipPaths = nextClipPaths;
43965
+ stateStack.push(nextState);
43966
+ try {
43967
+ walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
43968
+ } finally {
43969
+ stateStack.pop();
43970
+ capturedOperations = parentOperations;
43971
+ }
43972
+ if (isolate) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
43973
+ };
43852
43974
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
43853
43975
  for (const node of nodes) {
43854
43976
  switch (node.kind) {
@@ -43893,7 +44015,7 @@ function evaluateContentStreamToDisplayList(params) {
43893
44015
  break;
43894
44016
  }
43895
44017
  case "state-op": {
43896
- applyStateOperator(curState(), node.operator, node.operands, activeResources);
44018
+ applyStateOperator(curState(), node.operator, node.operands, activeResources, activeFonts, depth);
43897
44019
  break;
43898
44020
  }
43899
44021
  case "path-op": {
@@ -44179,53 +44301,7 @@ function evaluateContentStreamToDisplayList(params) {
44179
44301
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
44180
44302
  }, patternMask, activeResources, activeFonts, depth);
44181
44303
  } else if (sub === "Form" && depth < 8) {
44182
- const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
44183
- const formNodes = parseContentStream(formStreamBytes);
44184
- const formResDict = params.cosDoc.resolveDict(dictGet(xobjNode.dict, "Resources")) ?? activeResources;
44185
- const formFonts = new Map(activeFonts);
44186
- for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
44187
- formFonts.set(k, v);
44188
- }
44189
- let nextCtm = [...st.ctm];
44190
- const matArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "Matrix"));
44191
- if (matArr && matArr.items.length >= 6) {
44192
- const mn = (idx, fb = 0) => {
44193
- const resolved = params.cosDoc.resolve(matArr.items[idx]);
44194
- return resolved?.kind === "number" ? resolved.value : fb;
44195
- };
44196
- const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
44197
- nextCtm = multiplyMatrices(formMat, nextCtm);
44198
- }
44199
- let nextClip = st.clipRect ? [...st.clipRect] : void 0;
44200
- const bboxArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "BBox"));
44201
- if (bboxArr && bboxArr.items.length >= 4) {
44202
- const bn = (idx, fb = 0) => {
44203
- const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
44204
- return resolved?.kind === "number" ? resolved.value : fb;
44205
- };
44206
- const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
44207
- const pts = [
44208
- transformPoint(nextCtm, bx0, by0),
44209
- transformPoint(nextCtm, bx1, by0),
44210
- transformPoint(nextCtm, bx0, by1),
44211
- transformPoint(nextCtm, bx1, by1)
44212
- ];
44213
- const fMinX = Math.min(...pts.map((p) => p[0]));
44214
- const fMinY = Math.min(...pts.map((p) => p[1]));
44215
- const fMaxX = Math.max(...pts.map((p) => p[0]));
44216
- const fMaxY = Math.max(...pts.map((p) => p[1]));
44217
- if (fMaxX > fMinX && fMaxY > fMinY) {
44218
- nextClip = nextClip ? [
44219
- Math.max(nextClip[0], fMinX),
44220
- Math.max(nextClip[1], fMinY),
44221
- Math.min(nextClip[2], fMaxX),
44222
- Math.min(nextClip[3], fMaxY)
44223
- ] : [fMinX, fMinY, fMaxX, fMaxY];
44224
- }
44225
- }
44226
- stateStack.push({ ...st, ctm: nextCtm, ...nextClip ? { clipRect: nextClip } : {} });
44227
- walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
44228
- if (stateStack.length > 1) stateStack.pop();
44304
+ paintForm(xobjNode, activeResources, activeFonts, depth, mcid, actualText);
44229
44305
  }
44230
44306
  }
44231
44307
  }
@@ -44444,7 +44520,7 @@ function evaluateContentStreamToDisplayList(params) {
44444
44520
  st.textRenderMode = cmd.mode;
44445
44521
  break;
44446
44522
  case "state-op":
44447
- applyStateOperator(st, cmd.operator, cmd.operands, activeResources);
44523
+ applyStateOperator(st, cmd.operator, cmd.operands, activeResources, activeFonts, depth);
44448
44524
  break;
44449
44525
  case "show-text":
44450
44526
  emitTokenBytes(cmd.token.bytes);
@@ -47657,6 +47733,30 @@ function paintOperations(displayList) {
47657
47733
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
47658
47734
  ];
47659
47735
  }
47736
+ function renderSoftMask(mask, displayList, scale) {
47737
+ const bitmap = renderDisplayListToBitmap({
47738
+ ...displayList,
47739
+ rotation: 0,
47740
+ glyphs: [],
47741
+ paths: [],
47742
+ images: [],
47743
+ operations: mask.operations
47744
+ }, { scale, transparent: true });
47745
+ const { data } = bitmap;
47746
+ for (let i = 0; i < data.length; i += 4) {
47747
+ let value = data[i + 3];
47748
+ if (mask.subtype === "Luminosity") {
47749
+ const alpha = value / 255;
47750
+ const r = Math.round(data[i] * alpha + mask.backdrop.r * 255 * (1 - alpha));
47751
+ const g = Math.round(data[i + 1] * alpha + mask.backdrop.g * 255 * (1 - alpha));
47752
+ const b = Math.round(data[i + 2] * alpha + mask.backdrop.b * 255 * (1 - alpha));
47753
+ value = Math.round(pdfLum(r, g, b));
47754
+ }
47755
+ data[i] = data[i + 1] = data[i + 2] = 0;
47756
+ data[i + 3] = mask.transferMap?.[value] ?? value;
47757
+ }
47758
+ return bitmap;
47759
+ }
47660
47760
  function renderDisplayListToBitmap(displayList, options = {}) {
47661
47761
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
47662
47762
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -47680,10 +47780,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47680
47780
  const aaTxt = options.antialiasText !== false;
47681
47781
  let cachedClips;
47682
47782
  let cachedClipMask;
47783
+ let cachedSoftMask;
47784
+ let cachedSoftMaskPixels;
47683
47785
  const imageClipMasks = /* @__PURE__ */ new Map();
47684
47786
  for (const original of paintOperations(displayList)) {
47685
47787
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
47686
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
47788
+ let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
47789
+ if (operation.kind === "group") {
47790
+ const group = operation.value;
47791
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
47792
+ for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
47793
+ operation = { kind: "image", value: {
47794
+ name: "TransparencyGroup",
47795
+ width: bitmap.width,
47796
+ height: bitmap.height,
47797
+ decodedRgba: bitmap.data,
47798
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
47799
+ colorSpace: "DeviceRGB",
47800
+ bitsPerComponent: 8,
47801
+ blendMode: group.blendMode,
47802
+ clipRect: group.clipRect
47803
+ } };
47804
+ }
47687
47805
  const clips = original.value.clipPaths;
47688
47806
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
47689
47807
  if (clips && !clipMask) {
@@ -47697,6 +47815,19 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47697
47815
  cachedClips = clips;
47698
47816
  cachedClipMask = clipMask;
47699
47817
  }
47818
+ const softMask = original.value.softMask;
47819
+ if (softMask) {
47820
+ if (softMask !== cachedSoftMask) {
47821
+ cachedSoftMaskPixels = renderSoftMask(softMask, displayList, scale).data;
47822
+ cachedSoftMask = softMask;
47823
+ }
47824
+ if (clipMask) {
47825
+ clipMask = clipMask.slice();
47826
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * cachedSoftMaskPixels[i] / 255);
47827
+ } else {
47828
+ clipMask = cachedSoftMaskPixels;
47829
+ }
47830
+ }
47700
47831
  const imageClips = original.value.clipImages;
47701
47832
  if (imageClips) {
47702
47833
  let imageMask = imageClipMasks.get(imageClips);