@poe-platform/safe-bash 0.1.766 → 0.1.768

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.
@@ -146879,16 +146879,13 @@ async function lotusFormula(bytes, format2, group, row, column, sheetIndex, shee
146879
146879
  at++;
146880
146880
  if (op === 8 && name.startsWith("$")) name = name.slice(1);
146881
146881
  const range3 = names2?.get(name);
146882
- if (!range3) {
146883
- const external = lotusExternalVariable(name);
146884
- if (external !== void 0) stack.push(external);
146885
- else {
146882
+ const external = range3 ? void 0 : lotusExternalVariable(name);
146883
+ if (external !== void 0) stack.push(external);
146884
+ else {
146885
+ if (!range3)
146886
146886
  await context.diagnostic?.({ code: "lotus", severity: "warning", message: `Unknown Lotus named reference '${name}'.` });
146887
- stack.push("#NAME?");
146888
- }
146889
- } else {
146890
- const fixedSheet = range3.first.sheet !== sheetIndex || range3.last.sheet !== sheetIndex;
146891
- stack.push(`@name.${op === 7 ? "relative" : "absolute"}${fixedSheet ? ".fixed-sheet" : ""}[0,0,0]:` + quoteFormulaString(name, '"', gnumericGrammar));
146887
+ const fixedSheet = range3 && (range3.first.sheet !== sheetIndex || range3.last.sheet !== sheetIndex);
146888
+ stack.push(name ? `@name.${op === 7 ? "relative" : "absolute"}${fixedSheet ? ".fixed-sheet" : ""}[0,0,0]:` + quoteFormulaString(name, '"', gnumericGrammar) : "#NAME?");
146892
146889
  }
146893
146890
  } else if (modern && op >= 9 && op <= 11) {
146894
146891
  const length = op === 9 ? 4 : op === 10 ? 5 : 11;
@@ -209405,8 +209402,9 @@ function evaluateContentStreamToDisplayList(params) {
209405
209402
  const st = curState();
209406
209403
  const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
209407
209404
  const groupType = group ? params.cosDoc.resolve(dictGet(group, "S")) : void 0;
209408
- const isolated = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
209409
- const isolate = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && isolated?.kind === "boolean" && isolated.value;
209405
+ const isolation = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
209406
+ const isolated = isolation?.kind === "boolean" && isolation.value;
209407
+ const compositeGroup = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && (isolated || st.fillAlpha !== 1 || !!st.softMask || st.blendMode !== "Normal" && st.blendMode !== "Compatible");
209410
209408
  const formStreamBytes = params.cosDoc.decodeStream(form);
209411
209409
  const formNodes = parseContentStream(formStreamBytes);
209412
209410
  const formResDict = params.cosDoc.resolveDict(dictGet(form.dict, "Resources")) ?? activeResources;
@@ -209424,8 +209422,8 @@ function evaluateContentStreamToDisplayList(params) {
209424
209422
  const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
209425
209423
  nextCtm = multiplyMatrices(formMat, nextCtm);
209426
209424
  }
209427
- let nextClip = !isolate && st.clipRect ? [...st.clipRect] : void 0;
209428
- let nextClipPaths = isolate ? void 0 : st.clipPaths;
209425
+ let nextClip = !compositeGroup && st.clipRect ? [...st.clipRect] : void 0;
209426
+ let nextClipPaths = compositeGroup ? void 0 : st.clipPaths;
209429
209427
  const bboxArr = params.cosDoc.resolveArray(dictGet(form.dict, "BBox"));
209430
209428
  if (bboxArr && bboxArr.items.length >= 4) {
209431
209429
  const bn = (idx, fb = 0) => {
@@ -209459,7 +209457,7 @@ function evaluateContentStreamToDisplayList(params) {
209459
209457
  const parentOperations = capturedOperations;
209460
209458
  const children8 = [];
209461
209459
  const nextState = { ...st, ctm: nextCtm };
209462
- if (isolate) {
209460
+ if (compositeGroup) {
209463
209461
  capturedOperations = children8;
209464
209462
  nextState.fillAlpha = nextState.strokeAlpha = 1;
209465
209463
  nextState.blendMode = "Normal";
@@ -209477,7 +209475,7 @@ function evaluateContentStreamToDisplayList(params) {
209477
209475
  stateStack.pop();
209478
209476
  capturedOperations = parentOperations;
209479
209477
  }
209480
- if (isolate) emit({ kind: "group", value: { operations: children8, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
209478
+ if (compositeGroup) emit({ kind: "group", value: { operations: children8, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
209481
209479
  };
209482
209480
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
209483
209481
  for (const node3 of nodes) {
@@ -213455,6 +213453,9 @@ function renderSoftMask(mask, displayList, scale2) {
213455
213453
  }
213456
213454
  return bitmap;
213457
213455
  }
213456
+ function hasBlendModes(operations) {
213457
+ return operations.some((operation) => !!operation.value.blendMode && operation.value.blendMode !== "Normal" && operation.value.blendMode !== "Compatible" || operation.kind === "group" && hasBlendModes(operation.value.operations));
213458
+ }
213458
213459
  function renderDisplayListToBitmap(displayList, options = {}) {
213459
213460
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
213460
213461
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -213463,11 +213464,13 @@ function renderDisplayListToBitmap(displayList, options = {}) {
213463
213464
  const width2 = Math.max(1, Math.round(displayList.width * scale2));
213464
213465
  const height = Math.max(1, Math.round(displayList.height * scale2));
213465
213466
  const rgba = new Uint8Array(width2 * height * 4);
213467
+ const deferBackground = !options.transparent && hasBlendModes(paintOperations(displayList));
213468
+ const transparent = options.transparent || deferBackground;
213466
213469
  const bg = options.background ?? { r: 1, g: 1, b: 1 };
213467
- const bgR = options.transparent ? 0 : Math.round(bg.r * 255);
213468
- const bgG = options.transparent ? 0 : Math.round(bg.g * 255);
213469
- const bgB = options.transparent ? 0 : Math.round(bg.b * 255);
213470
- const bgA = options.transparent ? 0 : 255;
213470
+ const bgR = transparent ? 0 : Math.round(bg.r * 255);
213471
+ const bgG = transparent ? 0 : Math.round(bg.g * 255);
213472
+ const bgB = transparent ? 0 : Math.round(bg.b * 255);
213473
+ const bgA = transparent ? 0 : 255;
213471
213474
  for (let i = 0; i < width2 * height; i++) {
213472
213475
  rgba[i * 4] = bgR;
213473
213476
  rgba[i * 4 + 1] = bgG;
@@ -213644,6 +213647,15 @@ function renderDisplayListToBitmap(displayList, options = {}) {
213644
213647
  }
213645
213648
  }
213646
213649
  }
213650
+ if (deferBackground) {
213651
+ for (let i = 0; i < rgba.length; i += 4) {
213652
+ const alpha = rgba[i + 3] / 255;
213653
+ rgba[i] = Math.round(rgba[i] * alpha + bg.r * 255 * (1 - alpha));
213654
+ rgba[i + 1] = Math.round(rgba[i + 1] * alpha + bg.g * 255 * (1 - alpha));
213655
+ rgba[i + 2] = Math.round(rgba[i + 2] * alpha + bg.b * 255 * (1 - alpha));
213656
+ rgba[i + 3] = 255;
213657
+ }
213658
+ }
213647
213659
  let result2 = { width: width2, height, data: rgba };
213648
213660
  if (Math.abs(scaleX - scaleY) > 1e-6) {
213649
213661
  const targetW = Math.max(1, Math.round(displayList.width * scaleX));
@@ -11936,8 +11936,9 @@ function evaluateContentStreamToDisplayList(params) {
11936
11936
  const st = curState();
11937
11937
  const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
11938
11938
  const groupType = group ? params.cosDoc.resolve(dictGet(group, "S")) : void 0;
11939
- const isolated = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
11940
- const isolate = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && isolated?.kind === "boolean" && isolated.value;
11939
+ const isolation = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
11940
+ const isolated = isolation?.kind === "boolean" && isolation.value;
11941
+ const compositeGroup = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && (isolated || st.fillAlpha !== 1 || !!st.softMask || st.blendMode !== "Normal" && st.blendMode !== "Compatible");
11941
11942
  const formStreamBytes = params.cosDoc.decodeStream(form);
11942
11943
  const formNodes = parseContentStream(formStreamBytes);
11943
11944
  const formResDict = params.cosDoc.resolveDict(dictGet(form.dict, "Resources")) ?? activeResources;
@@ -11955,8 +11956,8 @@ function evaluateContentStreamToDisplayList(params) {
11955
11956
  const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
11956
11957
  nextCtm = multiplyMatrices(formMat, nextCtm);
11957
11958
  }
11958
- let nextClip = !isolate && st.clipRect ? [...st.clipRect] : void 0;
11959
- let nextClipPaths = isolate ? void 0 : st.clipPaths;
11959
+ let nextClip = !compositeGroup && st.clipRect ? [...st.clipRect] : void 0;
11960
+ let nextClipPaths = compositeGroup ? void 0 : st.clipPaths;
11960
11961
  const bboxArr = params.cosDoc.resolveArray(dictGet(form.dict, "BBox"));
11961
11962
  if (bboxArr && bboxArr.items.length >= 4) {
11962
11963
  const bn = (idx, fb = 0) => {
@@ -11990,7 +11991,7 @@ function evaluateContentStreamToDisplayList(params) {
11990
11991
  const parentOperations = capturedOperations;
11991
11992
  const children = [];
11992
11993
  const nextState = { ...st, ctm: nextCtm };
11993
- if (isolate) {
11994
+ if (compositeGroup) {
11994
11995
  capturedOperations = children;
11995
11996
  nextState.fillAlpha = nextState.strokeAlpha = 1;
11996
11997
  nextState.blendMode = "Normal";
@@ -12008,7 +12009,7 @@ function evaluateContentStreamToDisplayList(params) {
12008
12009
  stateStack.pop();
12009
12010
  capturedOperations = parentOperations;
12010
12011
  }
12011
- if (isolate) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
12012
+ if (compositeGroup) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
12012
12013
  };
12013
12014
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
12014
12015
  for (const node of nodes) {
@@ -14888,6 +14889,9 @@ function renderSoftMask(mask, displayList, scale) {
14888
14889
  }
14889
14890
  return bitmap;
14890
14891
  }
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));
14894
+ }
14891
14895
  function renderDisplayListToBitmap(displayList, options = {}) {
14892
14896
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
14893
14897
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -14896,11 +14900,13 @@ function renderDisplayListToBitmap(displayList, options = {}) {
14896
14900
  const width = Math.max(1, Math.round(displayList.width * scale));
14897
14901
  const height = Math.max(1, Math.round(displayList.height * scale));
14898
14902
  const rgba = new Uint8Array(width * height * 4);
14903
+ const deferBackground = !options.transparent && hasBlendModes(paintOperations(displayList));
14904
+ const transparent = options.transparent || deferBackground;
14899
14905
  const bg = options.background ?? { r: 1, g: 1, b: 1 };
14900
- const bgR = options.transparent ? 0 : Math.round(bg.r * 255);
14901
- const bgG = options.transparent ? 0 : Math.round(bg.g * 255);
14902
- const bgB = options.transparent ? 0 : Math.round(bg.b * 255);
14903
- const bgA = options.transparent ? 0 : 255;
14906
+ const bgR = transparent ? 0 : Math.round(bg.r * 255);
14907
+ const bgG = transparent ? 0 : Math.round(bg.g * 255);
14908
+ const bgB = transparent ? 0 : Math.round(bg.b * 255);
14909
+ const bgA = transparent ? 0 : 255;
14904
14910
  for (let i = 0; i < width * height; i++) {
14905
14911
  rgba[i * 4] = bgR;
14906
14912
  rgba[i * 4 + 1] = bgG;
@@ -15077,6 +15083,15 @@ function renderDisplayListToBitmap(displayList, options = {}) {
15077
15083
  }
15078
15084
  }
15079
15085
  }
15086
+ if (deferBackground) {
15087
+ for (let i = 0; i < rgba.length; i += 4) {
15088
+ const alpha = rgba[i + 3] / 255;
15089
+ rgba[i] = Math.round(rgba[i] * alpha + bg.r * 255 * (1 - alpha));
15090
+ rgba[i + 1] = Math.round(rgba[i + 1] * alpha + bg.g * 255 * (1 - alpha));
15091
+ rgba[i + 2] = Math.round(rgba[i + 2] * alpha + bg.b * 255 * (1 - alpha));
15092
+ rgba[i + 3] = 255;
15093
+ }
15094
+ }
15080
15095
  let result = { width, height, data: rgba };
15081
15096
  if (Math.abs(scaleX - scaleY) > 1e-6) {
15082
15097
  const targetW = Math.max(1, Math.round(displayList.width * scaleX));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poe-platform/safe-bash",
3
- "version": "0.1.766",
3
+ "version": "0.1.768",
4
4
  "description": "Extensible virtual shell with pluggable filesystems and streaming commands",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -841,7 +841,7 @@
841
841
  "access": "public"
842
842
  },
843
843
  "dependencies": {
844
- "@poe-platform/safe-fs": "0.1.766",
844
+ "@poe-platform/safe-fs": "0.1.768",
845
845
  "pdf-lib": "1.17.1",
846
846
  "@noble/hashes": "2.4.0",
847
847
  "pako": "3.0.1",
@@ -399,6 +399,15 @@ in `src/fixtures/SOURCES.md`, and adds local alpha/transform/group tests plus
399
399
  the original issue17069 signature regression. Soft-mask evaluation is bounded
400
400
  by the existing eight-level Form limit; mask-only text is excluded from extraction.
401
401
 
402
+ Non-isolated transparency Forms follow `beginGroup`'s direct-paint eligibility
403
+ and intermediate-surface state reset. Bitmap and SVG exports follow
404
+ `beginDrawing` in keeping the viewer background outside page blend calculations.
405
+ `src/render/transparency-group.test.ts` adds local opacity/blend/mask cases and
406
+ ports the unchanged `transparency_group.pdf` and `bug1873345.pdf` equality
407
+ fixtures, with independently obtained reference pixels. Full non-isolated
408
+ backdrop compositing for groups with outer effects retains PDF.js's documented
409
+ limitation. Form contents remain vectors in SVG output.
410
+
402
411
  Malformed dictionary-key recovery follows PDF.js `Parser.getObj`, skipping
403
412
  stray non-Name tokens only in local repair mode. Damaged optional ToUnicode
404
413
  streams follow `PartialEvaluator.readToUnicode` error recovery while retaining