@poe-platform/safe-bash 0.1.761 → 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 (32) hide show
  1. package/dist/image-ast/index.browser.js +255 -62
  2. package/dist/image-ast/index.js +255 -62
  3. package/dist/pdf-ast/ast.d.ts +23 -0
  4. package/dist/pdf-ast/index.js +344 -98
  5. package/dist/safe-bash/command-chunks/{chunk-6VX5ZQL5.js → chunk-4XHONGIU.js} +2 -2
  6. package/dist/safe-bash/command-chunks/{chunk-OSMLVM7P.js → chunk-S3G2B4OX.js} +258 -62
  7. package/dist/safe-bash/command-chunks/{chunk-GR725WRX.js → chunk-S5EX6UP5.js} +1 -1
  8. package/dist/safe-bash/commands/csvcut/index.d.ts +1 -1
  9. package/dist/safe-bash/commands/csvcut/index.js +3 -1
  10. package/dist/safe-bash/commands/csvgrep/index.d.ts +1 -1
  11. package/dist/safe-bash/commands/csvgrep/index.js +3 -1
  12. package/dist/safe-bash/core.browser.js +8 -6
  13. package/dist/safe-bash/shell/runtime.js +5 -5
  14. package/dist/safe-bash-checksum-engine/index.d.ts +1 -1
  15. package/dist/safe-bash-checksum-engine/index.js +5 -1
  16. package/dist/safe-bash-command-ffmpeg/index.js +7942 -7853
  17. package/dist/safe-bash-command-gh/index.js +174 -105
  18. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  19. package/dist/safe-bash-command-pandoc/command.js +3 -3
  20. package/dist/safe-bash-command-pandoc/index.js +3 -3
  21. package/dist/safe-bash-command-pdfimages/index.js +255 -62
  22. package/dist/safe-bash-command-pdfinfo/index.js +342 -98
  23. package/dist/safe-bash-command-pdftk/index.js +255 -62
  24. package/dist/safe-bash-command-pdftoppm/index.js +342 -98
  25. package/dist/safe-bash-command-pdftotext/index.js +255 -62
  26. package/dist/safe-bash-command-qpdf/index.js +255 -62
  27. package/dist/safe-bash-command-sips/index.js +2 -2
  28. package/dist/safe-bash-command-soffice/index.js +1 -1
  29. package/dist/safe-bash-command-ssconvert/index.js +318 -65
  30. package/dist/safe-bash-command-wkhtmltopdf/index.js +255 -62
  31. package/package.json +2 -2
  32. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +23 -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);
@@ -46707,6 +46783,47 @@ function flattenCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
46707
46783
  points.push([x4, y4]);
46708
46784
  return points;
46709
46785
  }
46786
+ function sampleImageLinear(image, x, y, out) {
46787
+ x = Math.max(0, Math.min(image.width - 1, x));
46788
+ y = Math.max(0, Math.min(image.height - 1, y));
46789
+ const x0 = Math.floor(x), y0 = Math.floor(y);
46790
+ const fx = x - x0, fy = y - y0;
46791
+ out.fill(0);
46792
+ for (let j = 0; j < 2; j++) {
46793
+ for (let i = 0; i < 2; i++) {
46794
+ const offset = (Math.min(image.height - 1, y0 + j) * image.width + Math.min(image.width - 1, x0 + i)) * 4;
46795
+ const alpha = image.data[offset + 3] * (i ? fx : 1 - fx) * (j ? fy : 1 - fy);
46796
+ out[0] = out[0] + image.data[offset] * alpha;
46797
+ out[1] = out[1] + image.data[offset + 1] * alpha;
46798
+ out[2] = out[2] + image.data[offset + 2] * alpha;
46799
+ out[3] = out[3] + alpha;
46800
+ }
46801
+ }
46802
+ if (out[3] > 0) {
46803
+ out[0] = out[0] / out[3];
46804
+ out[1] = out[1] / out[3];
46805
+ out[2] = out[2] / out[3];
46806
+ }
46807
+ }
46808
+ function downscaleImage(image, widthScale, heightScale) {
46809
+ const sample = new Float64Array(4);
46810
+ while (widthScale > 2 && image.width > 1 || heightScale > 2 && image.height > 1) {
46811
+ const width = widthScale > 2 ? Math.ceil(image.width / 2) : image.width;
46812
+ const height = heightScale > 2 ? Math.ceil(image.height / 2) : image.height;
46813
+ const data = new Uint8Array(width * height * 4);
46814
+ for (let y = 0; y < height; y++) {
46815
+ for (let x = 0; x < width; x++) {
46816
+ sampleImageLinear(image, (x + 0.5) * image.width / width - 0.5, (y + 0.5) * image.height / height - 0.5, sample);
46817
+ const offset = (y * width + x) * 4;
46818
+ for (let c = 0; c < 4; c++) data[offset + c] = Math.round(sample[c]);
46819
+ }
46820
+ }
46821
+ widthScale /= image.width / width;
46822
+ heightScale /= image.height / height;
46823
+ image = { width, height, data };
46824
+ }
46825
+ return image;
46826
+ }
46710
46827
  function decodePng(pngBytes) {
46711
46828
  if (pngBytes.length < 24 || pngBytes[0] !== 137 || pngBytes[1] !== 80 || pngBytes[2] !== 78 || pngBytes[3] !== 71) {
46712
46829
  throw new Error("Invalid PNG signature");
@@ -47616,6 +47733,30 @@ function paintOperations(displayList) {
47616
47733
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
47617
47734
  ];
47618
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
+ }
47619
47760
  function renderDisplayListToBitmap(displayList, options = {}) {
47620
47761
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
47621
47762
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -47639,10 +47780,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47639
47780
  const aaTxt = options.antialiasText !== false;
47640
47781
  let cachedClips;
47641
47782
  let cachedClipMask;
47783
+ let cachedSoftMask;
47784
+ let cachedSoftMaskPixels;
47642
47785
  const imageClipMasks = /* @__PURE__ */ new Map();
47643
47786
  for (const original of paintOperations(displayList)) {
47644
47787
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
47645
- 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
+ }
47646
47805
  const clips = original.value.clipPaths;
47647
47806
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
47648
47807
  if (clips && !clipMask) {
@@ -47656,6 +47815,19 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47656
47815
  cachedClips = clips;
47657
47816
  cachedClipMask = clipMask;
47658
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
+ }
47659
47831
  const imageClips = original.value.clipImages;
47660
47832
  if (imageClips) {
47661
47833
  let imageMask = imageClipMasks.get(imageClips);
@@ -47759,6 +47931,17 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47759
47931
  const maxPx = Math.min(width - 1, clipMaxPx, Math.ceil(Math.max(...cornersPx)) - 1);
47760
47932
  const minPy = Math.max(0, clipMinPy, Math.floor(Math.min(...cornersPy)));
47761
47933
  const maxPy = Math.min(height - 1, clipMaxPy, Math.ceil(Math.max(...cornersPy)) - 1);
47934
+ if (minPx > maxPx || minPy > maxPy) continue;
47935
+ const source = downscaleImage(
47936
+ { width: img.width, height: img.height, data: img.decodedRgba },
47937
+ Math.hypot(d, c) * img.width / Math.abs(det * scale),
47938
+ Math.hypot(b, a) * img.height / Math.abs(det * scale)
47939
+ );
47940
+ const ax = a * scale / img.width, ay = b * scale / img.width;
47941
+ const bx = c * scale / img.height, by = d * scale / img.height;
47942
+ const s1 = ax * ax + ay * ay, s2 = bx * bx + by * by, cross = ax * bx + ay * by;
47943
+ const smooth = Math.fround((s1 + s2 + Math.hypot(s1 - s2, 2 * cross)) / 2) <= 1;
47944
+ const sample = new Float64Array(4);
47762
47945
  for (let py = minPy; py <= maxPy; py++) {
47763
47946
  const yPdf = displayList.height - (py + 0.5) / scale;
47764
47947
  if (img.clipRect && (yPdf < img.clipRect[1] || yPdf > img.clipRect[3])) continue;
@@ -47770,9 +47953,14 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47770
47953
  const u = (d * dxPdf - c * dyPdf) / det;
47771
47954
  const v = (-b * dxPdf + a * dyPdf) / det;
47772
47955
  if (u < 0 || u > 1 || v < 0 || v > 1) continue;
47773
- const sx = Math.min(img.width - 1, Math.max(0, Math.floor(u * img.width)));
47774
- const sy = Math.min(img.height - 1, Math.max(0, Math.floor((1 - v) * img.height)));
47775
- const sIdx = (sy * img.width + sx) * 4;
47956
+ if (smooth) {
47957
+ sampleImageLinear(source, u * source.width - 0.5, (1 - v) * source.height - 0.5, sample);
47958
+ } else {
47959
+ const sx = Math.min(source.width - 1, Math.max(0, Math.floor(u * source.width)));
47960
+ const sy = Math.min(source.height - 1, Math.max(0, Math.floor((1 - v) * source.height)));
47961
+ const sIdx = (sy * source.width + sx) * 4;
47962
+ for (let c2 = 0; c2 < 4; c2++) sample[c2] = source.data[sIdx + c2];
47963
+ }
47776
47964
  blendPixel(
47777
47965
  rgba,
47778
47966
  width,
@@ -47780,11 +47968,11 @@ function renderDisplayListToBitmap(displayList, options = {}) {
47780
47968
  px,
47781
47969
  py,
47782
47970
  {
47783
- r: img.decodedRgba[sIdx] / 255,
47784
- g: img.decodedRgba[sIdx + 1] / 255,
47785
- b: img.decodedRgba[sIdx + 2] / 255
47971
+ r: sample[0] / 255,
47972
+ g: sample[1] / 255,
47973
+ b: sample[2] / 255
47786
47974
  },
47787
- img.decodedRgba[sIdx + 3] / 255,
47975
+ sample[3] / 255,
47788
47976
  img.blendMode,
47789
47977
  clipMask
47790
47978
  );
@@ -62508,3 +62696,8 @@ export {
62508
62696
  * Adapted from PDFium third_party/agg23/agg_curves.cpp, curve4_div.
62509
62697
  * See THIRD_PARTY_NOTICES.md for the pinned revision and adaptations.
62510
62698
  */
62699
+ /*!
62700
+ * Staged image reduction adapted from Mozilla PDF.js CanvasGraphics._scaleImage.
62701
+ * Copyright 2012 Mozilla Foundation. Licensed under Apache-2.0.
62702
+ * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
62703
+ */
@@ -211,6 +211,13 @@ export interface PdfRgbColor {
211
211
  readonly g: number;
212
212
  readonly b: number;
213
213
  }
214
+ /** A transparency-group mask evaluated in page coordinates at the gs operator. */
215
+ export interface PdfSoftMask {
216
+ readonly subtype: "Alpha" | "Luminosity";
217
+ readonly operations: readonly PdfPaintOperation[];
218
+ readonly backdrop: PdfRgbColor;
219
+ readonly transferMap?: Uint8Array | undefined;
220
+ }
214
221
  export interface PdfPlacedGlyph {
215
222
  /** Glyph paint geometry, kept separate from page drawings for extraction. */
216
223
  readonly outline?: PdfEvaluatedPath | undefined;
@@ -229,6 +236,7 @@ export interface PdfPlacedGlyph {
229
236
  readonly blendMode?: string | undefined;
230
237
  readonly clipPaths?: readonly PdfClipPath[] | undefined;
231
238
  readonly clipImages?: readonly PdfEvaluatedImage[] | undefined;
239
+ readonly softMask?: PdfSoftMask | undefined;
232
240
  readonly clipRect?: readonly [number, number, number, number] | undefined;
233
241
  }
234
242
  export interface PdfEvaluatedPath {
@@ -248,6 +256,7 @@ export interface PdfEvaluatedPath {
248
256
  readonly isClip?: boolean | undefined;
249
257
  readonly clipPaths?: readonly PdfClipPath[] | undefined;
250
258
  readonly clipImages?: readonly PdfEvaluatedImage[] | undefined;
259
+ readonly softMask?: PdfSoftMask | undefined;
251
260
  readonly clipRect?: readonly [number, number, number, number] | undefined;
252
261
  }
253
262
  export interface PdfEvaluatedImage {
@@ -261,6 +270,7 @@ export interface PdfEvaluatedImage {
261
270
  readonly blendMode?: string | undefined;
262
271
  readonly clipPaths?: readonly PdfClipPath[] | undefined;
263
272
  readonly clipImages?: readonly PdfEvaluatedImage[] | undefined;
273
+ readonly softMask?: PdfSoftMask | undefined;
264
274
  readonly clipRect?: readonly [number, number, number, number] | undefined;
265
275
  }
266
276
  export interface PdfLinkAnnotation {
@@ -278,7 +288,20 @@ export type PdfPaintOperation = {
278
288
  } | {
279
289
  readonly kind: "glyph";
280
290
  readonly value: PdfPlacedGlyph;
291
+ } | {
292
+ readonly kind: "group";
293
+ readonly value: PdfPaintGroup;
281
294
  };
295
+ /** An isolated transparency Form, composited after painting its children. */
296
+ export interface PdfPaintGroup {
297
+ readonly operations: readonly PdfPaintOperation[];
298
+ readonly alpha: number;
299
+ readonly blendMode?: string | undefined;
300
+ readonly clipPaths?: readonly PdfClipPath[] | undefined;
301
+ readonly clipImages?: readonly PdfEvaluatedImage[] | undefined;
302
+ readonly clipRect?: readonly [number, number, number, number] | undefined;
303
+ readonly softMask?: PdfSoftMask | undefined;
304
+ }
282
305
  export interface PdfDisplayList {
283
306
  readonly pageIndex: number;
284
307
  readonly width: number;