@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
@@ -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;
@@ -36281,14 +36281,18 @@ function evaluateContentStreamToDisplayList(params) {
36281
36281
  const paths = [];
36282
36282
  const images = [];
36283
36283
  const operations = [];
36284
+ let capturedOperations;
36285
+ let insideSoftMask = false;
36284
36286
  const emit = (operation) => {
36285
- const { clipPaths, clipImages } = curState();
36286
- if (clipPaths || clipImages) operation = { ...operation, value: {
36287
+ const { clipPaths, clipImages, softMask } = curState();
36288
+ if (clipPaths || clipImages || softMask) operation = { ...operation, value: {
36287
36289
  ...operation.value,
36288
36290
  ...clipPaths ? { clipPaths } : {},
36289
- ...clipImages ? { clipImages } : {}
36291
+ ...clipImages ? { clipImages } : {},
36292
+ ...softMask ? { softMask } : {}
36290
36293
  } };
36291
- operations.push(operation);
36294
+ (capturedOperations ?? operations).push(operation);
36295
+ if (insideSoftMask) return;
36292
36296
  switch (operation.kind) {
36293
36297
  case "path":
36294
36298
  paths.push(operation.value);
@@ -36394,7 +36398,7 @@ function evaluateContentStreamToDisplayList(params) {
36394
36398
  );
36395
36399
  return { r: kClamp(r), g: kClamp(g), b: kClamp(b) };
36396
36400
  };
36397
- const applyStateOperator = (st, operator, ops, activeResources) => {
36401
+ const applyStateOperator = (st, operator, ops, activeResources, activeFonts, depth) => {
36398
36402
  const num = (i, fb = 0) => ops[i]?.kind === "number" ? ops[i].value : fb;
36399
36403
  if (operator === "cm") {
36400
36404
  const m = [num(0, 1), num(1, 0), num(2, 0), num(3, 1), num(4, 0), num(5, 0)];
@@ -36477,6 +36481,46 @@ function evaluateContentStreamToDisplayList(params) {
36477
36481
  const extDict = params.cosDoc.resolveDict(dictGet(activeResources, "ExtGState"));
36478
36482
  const gsDict = extDict ? params.cosDoc.resolveDict(dictGet(extDict, ops[0].decoded)) : void 0;
36479
36483
  if (gsDict) {
36484
+ const mask = params.cosDoc.resolve(dictGet(gsDict, "SMask"));
36485
+ if (mask?.kind === "name" && mask.decoded === "None") {
36486
+ st.softMask = void 0;
36487
+ } else if (mask?.kind === "dict") {
36488
+ const subtype = params.cosDoc.resolve(dictGet(mask, "S"));
36489
+ const form = params.cosDoc.resolve(dictGet(mask, "G"));
36490
+ if (form?.kind === "stream" && subtype?.kind === "name" && (subtype.decoded === "Alpha" || subtype.decoded === "Luminosity")) {
36491
+ if (depth >= 8) throw new PdfError("E_LIMIT", "Soft-mask nesting exceeds the form depth limit");
36492
+ const parentOperations = capturedOperations;
36493
+ const parentInsideSoftMask = insideSoftMask;
36494
+ const savedTextState = { pendingTextClip, hasTextClip, activeTm, activeTlm };
36495
+ const captured = [];
36496
+ capturedOperations = captured;
36497
+ insideSoftMask = true;
36498
+ const maskState = { ...st, softMask: void 0, fillAlpha: 1, strokeAlpha: 1, blendMode: "Normal" };
36499
+ delete maskState.clipPaths;
36500
+ delete maskState.clipImages;
36501
+ delete maskState.clipRect;
36502
+ stateStack.push(maskState);
36503
+ try {
36504
+ paintForm(form, activeResources, activeFonts, depth, void 0, void 0, true);
36505
+ } finally {
36506
+ stateStack.pop();
36507
+ capturedOperations = parentOperations;
36508
+ insideSoftMask = parentInsideSoftMask;
36509
+ ({ pendingTextClip, hasTextClip, activeTm, activeTlm } = savedTextState);
36510
+ }
36511
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
36512
+ const colorSpace = group ? dictGet(group, "CS") : void 0;
36513
+ const bc = params.cosDoc.resolveArray(dictGet(mask, "BC"));
36514
+ const components = bc?.items.map((item) => {
36515
+ const value = params.cosDoc.resolve(item);
36516
+ return value?.kind === "number" ? value.value : 0;
36517
+ });
36518
+ const [r, g, b] = components ? convertColorSpaceComponentsToRgb(params.cosDoc, colorSpace, "DeviceRGB", components, activeResources) : [0, 0, 0];
36519
+ const transfer = params.cosDoc.resolve(dictGet(mask, "TR"));
36520
+ 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;
36521
+ st.softMask = { subtype: subtype.decoded, operations: captured, backdrop: { r, g, b }, transferMap };
36522
+ }
36523
+ }
36480
36524
  const bmNode = params.cosDoc.resolve(dictGet(gsDict, "BM"));
36481
36525
  if (bmNode?.kind === "name") {
36482
36526
  st.blendMode = bmNode.decoded === "Compatible" ? "Normal" : bmNode.decoded;
@@ -36563,6 +36607,84 @@ function evaluateContentStreamToDisplayList(params) {
36563
36607
  ] }], void 0, void 0, resources, activeFonts, depth);
36564
36608
  stateStack.pop();
36565
36609
  };
36610
+ const paintForm = (form, activeResources, activeFonts, depth, mcid, actualText, maskGroup = false) => {
36611
+ const st = curState();
36612
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
36613
+ const groupType = group ? params.cosDoc.resolve(dictGet(group, "S")) : void 0;
36614
+ const isolated = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
36615
+ const isolate = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && isolated?.kind === "boolean" && isolated.value;
36616
+ const formStreamBytes = params.cosDoc.decodeStream(form);
36617
+ const formNodes = parseContentStream(formStreamBytes);
36618
+ const formResDict = params.cosDoc.resolveDict(dictGet(form.dict, "Resources")) ?? activeResources;
36619
+ const formFonts = new Map(activeFonts);
36620
+ for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
36621
+ formFonts.set(k, v);
36622
+ }
36623
+ let nextCtm = [...st.ctm];
36624
+ const matArr = params.cosDoc.resolveArray(dictGet(form.dict, "Matrix"));
36625
+ if (matArr && matArr.items.length >= 6) {
36626
+ const mn = (idx, fb = 0) => {
36627
+ const resolved = params.cosDoc.resolve(matArr.items[idx]);
36628
+ return resolved?.kind === "number" ? resolved.value : fb;
36629
+ };
36630
+ const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
36631
+ nextCtm = multiplyMatrices(formMat, nextCtm);
36632
+ }
36633
+ let nextClip = !isolate && st.clipRect ? [...st.clipRect] : void 0;
36634
+ let nextClipPaths = isolate ? void 0 : st.clipPaths;
36635
+ const bboxArr = params.cosDoc.resolveArray(dictGet(form.dict, "BBox"));
36636
+ if (bboxArr && bboxArr.items.length >= 4) {
36637
+ const bn = (idx, fb = 0) => {
36638
+ const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
36639
+ return resolved?.kind === "number" ? resolved.value : fb;
36640
+ };
36641
+ const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
36642
+ const pts = [
36643
+ transformPoint(nextCtm, bx0, by0),
36644
+ transformPoint(nextCtm, bx1, by0),
36645
+ transformPoint(nextCtm, bx1, by1),
36646
+ transformPoint(nextCtm, bx0, by1)
36647
+ ];
36648
+ nextClipPaths = [...nextClipPaths ?? [], [
36649
+ ...pts.map(([x, y], index) => ({ kind: index === 0 ? "move" : "line", x, y })),
36650
+ { kind: "close" }
36651
+ ]];
36652
+ const fMinX = Math.min(...pts.map((p) => p[0]));
36653
+ const fMinY = Math.min(...pts.map((p) => p[1]));
36654
+ const fMaxX = Math.max(...pts.map((p) => p[0]));
36655
+ const fMaxY = Math.max(...pts.map((p) => p[1]));
36656
+ if (fMaxX > fMinX && fMaxY > fMinY) {
36657
+ nextClip = nextClip ? [
36658
+ Math.max(nextClip[0], fMinX),
36659
+ Math.max(nextClip[1], fMinY),
36660
+ Math.min(nextClip[2], fMaxX),
36661
+ Math.min(nextClip[3], fMaxY)
36662
+ ] : [fMinX, fMinY, fMaxX, fMaxY];
36663
+ }
36664
+ }
36665
+ const parentOperations = capturedOperations;
36666
+ const children = [];
36667
+ const nextState = { ...st, ctm: nextCtm };
36668
+ if (isolate) {
36669
+ capturedOperations = children;
36670
+ nextState.fillAlpha = nextState.strokeAlpha = 1;
36671
+ nextState.blendMode = "Normal";
36672
+ nextState.softMask = void 0;
36673
+ delete nextState.clipImages;
36674
+ delete nextState.clipPaths;
36675
+ delete nextState.clipRect;
36676
+ }
36677
+ if (nextClip) nextState.clipRect = nextClip;
36678
+ if (nextClipPaths) nextState.clipPaths = nextClipPaths;
36679
+ stateStack.push(nextState);
36680
+ try {
36681
+ walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
36682
+ } finally {
36683
+ stateStack.pop();
36684
+ capturedOperations = parentOperations;
36685
+ }
36686
+ if (isolate) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
36687
+ };
36566
36688
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
36567
36689
  for (const node of nodes) {
36568
36690
  switch (node.kind) {
@@ -36607,7 +36729,7 @@ function evaluateContentStreamToDisplayList(params) {
36607
36729
  break;
36608
36730
  }
36609
36731
  case "state-op": {
36610
- applyStateOperator(curState(), node.operator, node.operands, activeResources);
36732
+ applyStateOperator(curState(), node.operator, node.operands, activeResources, activeFonts, depth);
36611
36733
  break;
36612
36734
  }
36613
36735
  case "path-op": {
@@ -36893,53 +37015,7 @@ function evaluateContentStreamToDisplayList(params) {
36893
37015
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36894
37016
  }, patternMask, activeResources, activeFonts, depth);
36895
37017
  } else if (sub === "Form" && depth < 8) {
36896
- const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36897
- const formNodes = parseContentStream(formStreamBytes);
36898
- const formResDict = params.cosDoc.resolveDict(dictGet(xobjNode.dict, "Resources")) ?? activeResources;
36899
- const formFonts = new Map(activeFonts);
36900
- for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
36901
- formFonts.set(k, v);
36902
- }
36903
- let nextCtm = [...st.ctm];
36904
- const matArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "Matrix"));
36905
- if (matArr && matArr.items.length >= 6) {
36906
- const mn = (idx, fb = 0) => {
36907
- const resolved = params.cosDoc.resolve(matArr.items[idx]);
36908
- return resolved?.kind === "number" ? resolved.value : fb;
36909
- };
36910
- const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
36911
- nextCtm = multiplyMatrices(formMat, nextCtm);
36912
- }
36913
- let nextClip = st.clipRect ? [...st.clipRect] : void 0;
36914
- const bboxArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "BBox"));
36915
- if (bboxArr && bboxArr.items.length >= 4) {
36916
- const bn = (idx, fb = 0) => {
36917
- const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
36918
- return resolved?.kind === "number" ? resolved.value : fb;
36919
- };
36920
- const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
36921
- const pts = [
36922
- transformPoint(nextCtm, bx0, by0),
36923
- transformPoint(nextCtm, bx1, by0),
36924
- transformPoint(nextCtm, bx0, by1),
36925
- transformPoint(nextCtm, bx1, by1)
36926
- ];
36927
- const fMinX = Math.min(...pts.map((p) => p[0]));
36928
- const fMinY = Math.min(...pts.map((p) => p[1]));
36929
- const fMaxX = Math.max(...pts.map((p) => p[0]));
36930
- const fMaxY = Math.max(...pts.map((p) => p[1]));
36931
- if (fMaxX > fMinX && fMaxY > fMinY) {
36932
- nextClip = nextClip ? [
36933
- Math.max(nextClip[0], fMinX),
36934
- Math.max(nextClip[1], fMinY),
36935
- Math.min(nextClip[2], fMaxX),
36936
- Math.min(nextClip[3], fMaxY)
36937
- ] : [fMinX, fMinY, fMaxX, fMaxY];
36938
- }
36939
- }
36940
- stateStack.push({ ...st, ctm: nextCtm, ...nextClip ? { clipRect: nextClip } : {} });
36941
- walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
36942
- if (stateStack.length > 1) stateStack.pop();
37018
+ paintForm(xobjNode, activeResources, activeFonts, depth, mcid, actualText);
36943
37019
  }
36944
37020
  }
36945
37021
  }
@@ -37158,7 +37234,7 @@ function evaluateContentStreamToDisplayList(params) {
37158
37234
  st.textRenderMode = cmd.mode;
37159
37235
  break;
37160
37236
  case "state-op":
37161
- applyStateOperator(st, cmd.operator, cmd.operands, activeResources);
37237
+ applyStateOperator(st, cmd.operator, cmd.operands, activeResources, activeFonts, depth);
37162
37238
  break;
37163
37239
  case "show-text":
37164
37240
  emitTokenBytes(cmd.token.bytes);
@@ -41462,6 +41538,30 @@ function paintOperations(displayList) {
41462
41538
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
41463
41539
  ];
41464
41540
  }
41541
+ function renderSoftMask(mask, displayList, scale) {
41542
+ const bitmap = renderDisplayListToBitmap({
41543
+ ...displayList,
41544
+ rotation: 0,
41545
+ glyphs: [],
41546
+ paths: [],
41547
+ images: [],
41548
+ operations: mask.operations
41549
+ }, { scale, transparent: true });
41550
+ const { data } = bitmap;
41551
+ for (let i = 0; i < data.length; i += 4) {
41552
+ let value = data[i + 3];
41553
+ if (mask.subtype === "Luminosity") {
41554
+ const alpha = value / 255;
41555
+ const r = Math.round(data[i] * alpha + mask.backdrop.r * 255 * (1 - alpha));
41556
+ const g = Math.round(data[i + 1] * alpha + mask.backdrop.g * 255 * (1 - alpha));
41557
+ const b = Math.round(data[i + 2] * alpha + mask.backdrop.b * 255 * (1 - alpha));
41558
+ value = Math.round(pdfLum(r, g, b));
41559
+ }
41560
+ data[i] = data[i + 1] = data[i + 2] = 0;
41561
+ data[i + 3] = mask.transferMap?.[value] ?? value;
41562
+ }
41563
+ return bitmap;
41564
+ }
41465
41565
  function renderDisplayListToBitmap(displayList, options = {}) {
41466
41566
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
41467
41567
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -41485,10 +41585,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
41485
41585
  const aaTxt = options.antialiasText !== false;
41486
41586
  let cachedClips;
41487
41587
  let cachedClipMask;
41588
+ let cachedSoftMask;
41589
+ let cachedSoftMaskPixels;
41488
41590
  const imageClipMasks = /* @__PURE__ */ new Map();
41489
41591
  for (const original of paintOperations(displayList)) {
41490
41592
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
41491
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
41593
+ let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
41594
+ if (operation.kind === "group") {
41595
+ const group = operation.value;
41596
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
41597
+ for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
41598
+ operation = { kind: "image", value: {
41599
+ name: "TransparencyGroup",
41600
+ width: bitmap.width,
41601
+ height: bitmap.height,
41602
+ decodedRgba: bitmap.data,
41603
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
41604
+ colorSpace: "DeviceRGB",
41605
+ bitsPerComponent: 8,
41606
+ blendMode: group.blendMode,
41607
+ clipRect: group.clipRect
41608
+ } };
41609
+ }
41492
41610
  const clips = original.value.clipPaths;
41493
41611
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
41494
41612
  if (clips && !clipMask) {
@@ -41502,6 +41620,19 @@ function renderDisplayListToBitmap(displayList, options = {}) {
41502
41620
  cachedClips = clips;
41503
41621
  cachedClipMask = clipMask;
41504
41622
  }
41623
+ const softMask = original.value.softMask;
41624
+ if (softMask) {
41625
+ if (softMask !== cachedSoftMask) {
41626
+ cachedSoftMaskPixels = renderSoftMask(softMask, displayList, scale).data;
41627
+ cachedSoftMask = softMask;
41628
+ }
41629
+ if (clipMask) {
41630
+ clipMask = clipMask.slice();
41631
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * cachedSoftMaskPixels[i] / 255);
41632
+ } else {
41633
+ clipMask = cachedSoftMaskPixels;
41634
+ }
41635
+ }
41505
41636
  const imageClips = original.value.clipImages;
41506
41637
  if (imageClips) {
41507
41638
  let imageMask = imageClipMasks.get(imageClips);
@@ -41683,6 +41814,27 @@ function renderDisplayListToPng(displayList, options = {}) {
41683
41814
  const bmp = renderDisplayListToBitmap(displayList, options);
41684
41815
  return encodeRgbaToPng(bmp.width, bmp.height, bmp.data);
41685
41816
  }
41817
+ function pdfBlendModeToCss(mode) {
41818
+ if (!mode || mode === "Normal" || mode === "Compatible") return void 0;
41819
+ const map = {
41820
+ Multiply: "multiply",
41821
+ Screen: "screen",
41822
+ Overlay: "overlay",
41823
+ Darken: "darken",
41824
+ Lighten: "lighten",
41825
+ ColorDodge: "color-dodge",
41826
+ ColorBurn: "color-burn",
41827
+ HardLight: "hard-light",
41828
+ SoftLight: "soft-light",
41829
+ Difference: "difference",
41830
+ Exclusion: "exclusion",
41831
+ Hue: "hue",
41832
+ Saturation: "saturation",
41833
+ Color: "color",
41834
+ Luminosity: "luminosity"
41835
+ };
41836
+ return map[mode];
41837
+ }
41686
41838
  function escapeXmlText(str) {
41687
41839
  let valid = "";
41688
41840
  for (const char of str) {
@@ -41744,44 +41896,74 @@ function renderDisplayListToSvg(displayList, options = {}) {
41744
41896
  parts.push(`<g transform="matrix(${a} ${b} ${-c} ${-d} ${e + c * displayList.height} ${f + d * displayList.height})">`);
41745
41897
  }
41746
41898
  let clipId = 0;
41747
- for (const original of paintOperations(displayList)) {
41748
- if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
41749
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
41750
- const clips = original.value.clipPaths ?? [];
41751
- const imageClips = original.value.clipImages ?? [];
41752
- for (const clip of clips) {
41753
- const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
41754
- const id = `text-clip-${clipId++}`;
41755
- const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
41756
- parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
41757
- }
41758
- for (const image of imageClips) {
41759
- const id = `image-clip-${clipId++}`;
41760
- parts.push(`<defs><mask id="${id}" maskUnits="userSpaceOnUse" x="0" y="0" width="${displayList.width}" height="${displayList.height}" style="mask-type:alpha">${svgImage(image, displayList.height)}</mask></defs><g mask="url(#${id})">`);
41761
- }
41762
- if (operation.kind === "path") {
41763
- const p = operation.value;
41764
- const pathData = svgPathData(p.segments, displayList.height);
41765
- if (pathData) {
41766
- const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
41767
- const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
41768
- const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
41769
- const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
41770
- const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
41771
- const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
41772
- const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
41773
- const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
41774
- const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
41775
- const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
41776
- const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
41777
- const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
41778
- parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
41899
+ const softMaskIds = /* @__PURE__ */ new Map();
41900
+ const appendOperations = (operations) => {
41901
+ for (const original of operations) {
41902
+ if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
41903
+ const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
41904
+ const clips = original.value.clipPaths ?? [];
41905
+ const imageClips = original.value.clipImages ?? [];
41906
+ const blend = pdfBlendModeToCss(original.value.blendMode);
41907
+ if (blend) parts.push(`<g style="mix-blend-mode:${blend}">`);
41908
+ const softMask = original.value.softMask;
41909
+ if (softMask) {
41910
+ let id = softMaskIds.get(softMask);
41911
+ if (!id) {
41912
+ id = `soft-mask-${clipId++}`;
41913
+ softMaskIds.set(softMask, id);
41914
+ const bitmap = renderSoftMask(softMask, displayList, Math.max(scaleX, scaleY));
41915
+ const image = {
41916
+ name: id,
41917
+ width: bitmap.width,
41918
+ height: bitmap.height,
41919
+ decodedRgba: bitmap.data,
41920
+ matrix: [displayList.width, 0, 0, displayList.height, 0, 0],
41921
+ colorSpace: "DeviceGray",
41922
+ bitsPerComponent: 8
41923
+ };
41924
+ parts.push(`<defs><mask id="${id}" maskUnits="userSpaceOnUse" x="0" y="0" width="${displayList.width}" height="${displayList.height}" style="mask-type:alpha">${svgImage(image, displayList.height)}</mask></defs>`);
41925
+ }
41926
+ parts.push(`<g mask="url(#${id})">`);
41779
41927
  }
41780
- } else if (operation.kind === "image") {
41781
- parts.push(` ${svgImage(operation.value, displayList.height)}`);
41928
+ for (const clip of clips) {
41929
+ const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
41930
+ const id = `text-clip-${clipId++}`;
41931
+ const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
41932
+ parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
41933
+ }
41934
+ for (const image of imageClips) {
41935
+ const id = `image-clip-${clipId++}`;
41936
+ parts.push(`<defs><mask id="${id}" maskUnits="userSpaceOnUse" x="0" y="0" width="${displayList.width}" height="${displayList.height}" style="mask-type:alpha">${svgImage(image, displayList.height)}</mask></defs><g mask="url(#${id})">`);
41937
+ }
41938
+ if (operation.kind === "group") {
41939
+ parts.push(`<g opacity="${operation.value.alpha}" style="isolation:isolate">`);
41940
+ appendOperations(operation.value.operations);
41941
+ parts.push("</g>");
41942
+ } else if (operation.kind === "path") {
41943
+ const p = operation.value;
41944
+ const pathData = svgPathData(p.segments, displayList.height);
41945
+ if (pathData) {
41946
+ const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
41947
+ const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
41948
+ const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
41949
+ const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
41950
+ const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
41951
+ const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
41952
+ const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
41953
+ const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
41954
+ const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
41955
+ const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
41956
+ const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
41957
+ const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
41958
+ parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
41959
+ }
41960
+ } else if (operation.kind === "image") {
41961
+ parts.push(` ${svgImage(operation.value, displayList.height)}`);
41962
+ }
41963
+ for (let i = 0; i < clips.length + imageClips.length + (softMask ? 1 : 0) + (blend ? 1 : 0); i++) parts.push("</g>");
41782
41964
  }
41783
- for (let i = 0; i < clips.length + imageClips.length; i++) parts.push("</g>");
41784
- }
41965
+ };
41966
+ appendOperations(paintOperations(displayList));
41785
41967
  if (displayList.rotation) parts.push("</g>");
41786
41968
  parts.push("</svg>\n");
41787
41969
  return parts.join("\n");
@@ -48,11 +48,11 @@ import {
48
48
  trimImage,
49
49
  unflattenImage,
50
50
  unpremultiplyRgbaImage
51
- } from "./chunk-F7MJRXQ2.js";
51
+ } from "./chunk-S5EX6UP5.js";
52
52
  import {
53
53
  PdfDocument,
54
54
  encodePng
55
- } from "./chunk-P3Q2QSCA.js";
55
+ } from "./chunk-S3G2B4OX.js";
56
56
  import {
57
57
  createLuaFilterCapability
58
58
  } from "./chunk-Y2KHC6TZ.js";