@poe-platform/safe-bash 0.1.757 → 0.1.759

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 (59) hide show
  1. package/dist/image-ast/index.browser.js +87 -24
  2. package/dist/image-ast/index.js +87 -24
  3. package/dist/pdf-ast/ast.d.ts +3 -0
  4. package/dist/pdf-ast/index.js +103 -41
  5. package/dist/safe-bash/chunks/{chunk-WNWIBBJZ.js → chunk-AYPUGSOV.js} +7 -1
  6. package/dist/safe-bash/command-chunks/{chunk-F3J5ZLKF.js → chunk-522TDVLS.js} +1 -1
  7. package/dist/safe-bash/command-chunks/{chunk-VFS2MDAB.js → chunk-6YLD37NH.js} +2 -2
  8. package/dist/safe-bash/command-chunks/{chunk-YI3GKJ7Q.js → chunk-766IWMTB.js} +2 -2
  9. package/dist/safe-bash/command-chunks/{chunk-WI35236J.js → chunk-7JA44PVV.js} +1 -1
  10. package/dist/safe-bash/command-chunks/{chunk-H2FQA4OU.js → chunk-BAUGDXLZ.js} +87 -25
  11. package/dist/safe-bash/command-chunks/{chunk-KSH2F6RG.js → chunk-CUFCNL6G.js} +1 -1
  12. package/dist/safe-bash/command-chunks/{chunk-KBBI4CSU.js → chunk-HVEAK3OS.js} +2 -2
  13. package/dist/safe-bash/command-chunks/{chunk-S4MLIYSN.js → chunk-J2NPH7DO.js} +4 -0
  14. package/dist/safe-bash/command-chunks/{chunk-4F6PG2OT.js → chunk-YJWWRCIG.js} +8 -8
  15. package/dist/safe-bash/commands/python/index.browser.js +1 -1
  16. package/dist/safe-bash/commands/python/shell-capability.js +10 -2
  17. package/dist/safe-bash/core.browser.js +1 -1
  18. package/dist/safe-bash-command-column/column.js +3 -3
  19. package/dist/safe-bash-command-column/index.js +3 -3
  20. package/dist/safe-bash-command-column/layout.js +2 -2
  21. package/dist/safe-bash-command-factor/command.js +2 -2
  22. package/dist/safe-bash-command-factor/index.js +2 -2
  23. package/dist/safe-bash-command-ffmpeg/index.js +6300 -6265
  24. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  25. package/dist/safe-bash-command-pandoc/command.js +3 -3
  26. package/dist/safe-bash-command-pandoc/index.js +3 -3
  27. package/dist/safe-bash-command-pdfimages/index.js +87 -24
  28. package/dist/safe-bash-command-pdfinfo/index.js +103 -41
  29. package/dist/safe-bash-command-pdftk/index.js +87 -24
  30. package/dist/safe-bash-command-pdftoppm/index.js +103 -41
  31. package/dist/safe-bash-command-pdftotext/index.js +87 -24
  32. package/dist/safe-bash-command-qpdf/index.js +87 -24
  33. package/dist/safe-bash-command-sips/index.js +2 -2
  34. package/dist/safe-bash-command-soffice/index.js +2 -2
  35. package/dist/safe-bash-command-ssconvert/command-bindings.d.ts +18 -0
  36. package/dist/safe-bash-command-ssconvert/command.d.ts +5 -14
  37. package/dist/safe-bash-command-ssconvert/commands.d.ts +6 -0
  38. package/dist/safe-bash-command-ssconvert/commands.js +871 -0
  39. package/dist/safe-bash-command-ssconvert/core.js +1 -1
  40. package/dist/safe-bash-command-ssconvert/index.js +306 -236
  41. package/dist/safe-bash-command-wkhtmltopdf/index.js +88 -24
  42. package/dist/safe-bash-command-yq/index.js +4 -4
  43. package/dist/safe-bash-compression-engine/files.js +2 -2
  44. package/dist/safe-bash-compression-engine/operand.js +4 -4
  45. package/dist/safe-bash-markdown-engine/commonmark-blocks.js +4 -4
  46. package/dist/safe-bash-markdown-engine/commonmark-inlines.js +4 -4
  47. package/dist/safe-bash-markdown-engine/commonmark-syntax.js +2 -2
  48. package/dist/safe-bash-markdown-engine/gfm-syntax.js +3 -3
  49. package/dist/safe-bash-markdown-engine/index.js +7 -7
  50. package/dist/safe-bash-query-engine/index.js +5 -5
  51. package/dist/safe-bash-query-engine/interpreter.js +4 -4
  52. package/dist/safe-bash-query-engine/query-core.js +5 -5
  53. package/package.json +6 -2
  54. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +30 -0
  55. package/dist/safe-bash/command-chunks/{chunk-OQVIJMBY.js → chunk-7HINP7ZK.js} +4 -4
  56. package/dist/safe-bash/command-chunks/{chunk-XAYEDOV5.js → chunk-CG4JSOK2.js} +3 -3
  57. package/dist/safe-bash/command-chunks/{chunk-YIK4ZYQ4.js → chunk-DC52GWRK.js} +9 -9
  58. package/dist/safe-bash/command-chunks/{chunk-TOTZFBDT.js → chunk-TKACIO4X.js} +4 -4
  59. package/dist/safe-bash/command-chunks/{chunk-VTWKS4RM.js → chunk-WF2LSKMI.js} +3 -3
@@ -656,6 +656,7 @@ var messages_default = {
656
656
  "-5": "buffer error",
657
657
  "-6": "incompatible version"
658
658
  };
659
+ var Z_BUF_ERROR = -5;
659
660
  var MAX_MEM_LEVEL = 9;
660
661
  var HEAP_SIZE = 573;
661
662
  var MIN_MATCH = 3;
@@ -22741,22 +22742,31 @@ function decodeFlate(bytes, parms, maxDecodedBytes = DEFAULT_MAX_DECODED_BYTES)
22741
22742
  inflated = new BoundedFlateStream(bytes, maxDecodedBytes).getBytes();
22742
22743
  } catch (error) {
22743
22744
  if (error instanceof PdfError && error.code === "E_LIMIT") throw error;
22745
+ const wrapped = bytes[0] === 31 && bytes[1] === 139 || bytes.length >= 2 && (bytes[0] & 15) === 8 && bytes[0] >>> 4 <= 7 && (bytes[0] << 8 | bytes[1]) % 31 === 0;
22744
22746
  const decoder = new Inflate({
22745
- raw: !(bytes[0] === 31 && bytes[1] === 139),
22747
+ raw: !wrapped,
22746
22748
  chunkSize: Math.max(1, Math.min(64 * 1024, maxDecodedBytes + 1))
22747
22749
  });
22750
+ const chunks = [];
22748
22751
  let length = 0;
22749
22752
  decoder.onData = (chunk) => {
22750
22753
  length += chunk.length;
22751
22754
  if (length > maxDecodedBytes) {
22752
22755
  throw new PdfError("E_LIMIT", "FlateDecode output exceeds maximum decoded byte budget");
22753
22756
  }
22754
- decoder.chunks.push(chunk);
22757
+ chunks.push(chunk);
22755
22758
  };
22756
- if (!decoder.push(bytes, true) || decoder.err || !decoder.ended) {
22759
+ const complete = decoder.push(bytes, true);
22760
+ const truncated = wrapped && decoder.err === Z_BUF_ERROR && length > 0;
22761
+ if ((!complete || decoder.err || !decoder.ended) && !truncated) {
22757
22762
  throw new PdfError("E_CAPABILITY", "Invalid FlateDecode compressed stream");
22758
22763
  }
22759
- inflated = decoder.result;
22764
+ inflated = new Uint8Array(length);
22765
+ let offset = 0;
22766
+ for (const chunk of chunks) {
22767
+ inflated.set(chunk, offset);
22768
+ offset += chunk.length;
22769
+ }
22760
22770
  }
22761
22771
  return applyPredictor(inflated, parms);
22762
22772
  }
@@ -25468,7 +25478,7 @@ var ParsedCosDocument = class {
25468
25478
  return void 0;
25469
25479
  }
25470
25480
  };
25471
- function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false) {
25481
+ function parseNodeFromLexer(lexer, bytes, maxDepth, repair = false) {
25472
25482
  const stack = [];
25473
25483
  while (true) {
25474
25484
  const tok = lexer.nextToken();
@@ -25477,7 +25487,7 @@ function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false)
25477
25487
  if (!parent) return void 0;
25478
25488
  throw new PdfError("E_PARSE", parent.kind === "array" ? "Unterminated PDF array" : "Unterminated PDF dictionary");
25479
25489
  }
25480
- if (!parent && recoverEmptyObject && tok.kind === "keyword" && tok.value === "endobj") {
25490
+ if (!parent && repair && tok.kind === "keyword" && tok.value === "endobj") {
25481
25491
  return { kind: "null", span: tok.span };
25482
25492
  }
25483
25493
  let node;
@@ -25492,6 +25502,7 @@ function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false)
25492
25502
  parent.key = { kind: "name", rawBytes: tok.rawBytes, decoded: tok.decoded, span: tok.span };
25493
25503
  continue;
25494
25504
  } else {
25505
+ if (repair) continue;
25495
25506
  throw new PdfError("E_PARSE", `Expected dictionary key /Name, got ${tok.kind}`);
25496
25507
  }
25497
25508
  } else {
@@ -25660,7 +25671,7 @@ function parseHeaderVersion(bytes) {
25660
25671
  }
25661
25672
  return head.slice(idx + 5, idx + 8);
25662
25673
  }
25663
- function parseObjectAtOffset(bytes, offset, maxRecursionDepth, recoverEmptyObject = false) {
25674
+ function parseObjectAtOffset(bytes, offset, maxRecursionDepth, repair = false) {
25664
25675
  const lexer = new CosByteLexer(bytes, offset);
25665
25676
  const objNumTok = lexer.nextToken();
25666
25677
  const genNumTok = lexer.nextToken();
@@ -25668,7 +25679,7 @@ function parseObjectAtOffset(bytes, offset, maxRecursionDepth, recoverEmptyObjec
25668
25679
  if (objNumTok?.kind !== "number" || genNumTok?.kind !== "number" || objKwTok?.kind !== "keyword" || objKwTok.value !== "obj") {
25669
25680
  throw new PdfError("E_PARSE", `Malformed indirect object header at byte offset ${offset}`);
25670
25681
  }
25671
- const value = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, recoverEmptyObject);
25682
+ const value = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, repair);
25672
25683
  if (!value) {
25673
25684
  throw new PdfError("E_PARSE", `Empty indirect object ${objNumTok.value} at offset ${offset}`);
25674
25685
  }
@@ -25857,7 +25868,7 @@ function repairScanCosDocument(bytes, maxObjects, maxRecursionDepth) {
25857
25868
  try {
25858
25869
  const token = lexer.nextToken();
25859
25870
  if (token?.kind === "keyword" && token.value === "trailer") {
25860
- const trailer = parseNodeFromLexer(lexer, bytes, maxRecursionDepth);
25871
+ const trailer = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, true);
25861
25872
  if (trailer?.kind === "dict") trailers.push(trailer);
25862
25873
  pos = lexer.offset;
25863
25874
  continue;
@@ -25913,7 +25924,7 @@ function unpackRecoveredObjects(objects, maxObjects, maxDecompressedBytes, maxRe
25913
25924
  const t = dictGet(obj.value.dict, "Type");
25914
25925
  if (t?.kind === "name" && t.decoded === "ObjStm") {
25915
25926
  try {
25916
- for (const [unpackedNum, unpackedVal] of unpackObjectStream(obj.value, maxDecompressedBytes, maxRecursionDepth).entries()) {
25927
+ for (const [unpackedNum, unpackedVal] of unpackObjectStream(obj.value, maxDecompressedBytes, maxRecursionDepth, true).entries()) {
25917
25928
  if (!objects.has(unpackedNum)) {
25918
25929
  objects.set(unpackedNum, {
25919
25930
  objectNumber: unpackedNum,
@@ -25949,7 +25960,7 @@ function recoveredReferences(objects) {
25949
25960
  }
25950
25961
  return { ...rootRef ? { rootRef } : {}, ...infoRef ? { infoRef } : {} };
25951
25962
  }
25952
- function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth) {
25963
+ function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth, repair = false) {
25953
25964
  const nNode = dictGet(streamObj.dict, "N");
25954
25965
  const firstNode = dictGet(streamObj.dict, "First");
25955
25966
  if (nNode?.kind !== "number" || firstNode?.kind !== "number") {
@@ -25969,7 +25980,7 @@ function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth)
25969
25980
  for (const pair of pairs) {
25970
25981
  try {
25971
25982
  const valLexer = new CosByteLexer(decoded, firstNode.value + pair.relativeOffset);
25972
- const node = parseNodeFromLexer(valLexer, decoded, maxRecursionDepth);
25983
+ const node = parseNodeFromLexer(valLexer, decoded, maxRecursionDepth, repair);
25973
25984
  if (node) {
25974
25985
  result.set(pair.objectNumber, node);
25975
25986
  }
@@ -26152,7 +26163,7 @@ function parseCosDocument(bytes, options = {}) {
26152
26163
  if (!unpacked) {
26153
26164
  const stmObj = objects.get(entry.objectStreamNumber)?.value;
26154
26165
  if (stmObj?.kind === "stream") {
26155
- unpacked = unpackObjectStream(stmObj, maxDecompressedBytes, maxRecursionDepth);
26166
+ unpacked = unpackObjectStream(stmObj, maxDecompressedBytes, maxRecursionDepth, recovery === "repair");
26156
26167
  objStmCache.set(entry.objectStreamNumber, unpacked);
26157
26168
  }
26158
26169
  }
@@ -34969,7 +34980,11 @@ function resolvePageFonts(doc, resourcesDict) {
34969
34980
  let cmap;
34970
34981
  const toUniNode = doc.resolve(dictGet(fObj, "ToUnicode"));
34971
34982
  if (toUniNode?.kind === "stream") {
34972
- cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34983
+ try {
34984
+ cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34985
+ } catch (error) {
34986
+ if (error instanceof PdfError && error.code === "E_LIMIT") throw error;
34987
+ }
34973
34988
  }
34974
34989
  const encNode = doc.resolve(dictGet(fObj, "Encoding"));
34975
34990
  if (encNode?.kind === "dict") {
@@ -34985,7 +35000,7 @@ function resolvePageFonts(doc, resourcesDict) {
34985
35000
  const glyphNames = buildFontEncodingGlyphNamesMap(encNode);
34986
35001
  const widths = /* @__PURE__ */ new Map();
34987
35002
  let defaultWidth = 556;
34988
- const isTwoByteCid = subtype === "Type0" || Boolean(cmap?.isTwoByte);
35003
+ const isTwoByteCid = subtype === "Type0";
34989
35004
  let fontMatrix;
34990
35005
  let charProcs;
34991
35006
  let fontResources;
@@ -36093,8 +36108,12 @@ function evaluateContentStreamToDisplayList(params) {
36093
36108
  const images = [];
36094
36109
  const operations = [];
36095
36110
  const emit = (operation) => {
36096
- const clipPaths = curState().clipPaths;
36097
- if (clipPaths) operation = { ...operation, value: { ...operation.value, clipPaths } };
36111
+ const { clipPaths, clipImages } = curState();
36112
+ if (clipPaths || clipImages) operation = { ...operation, value: {
36113
+ ...operation.value,
36114
+ ...clipPaths ? { clipPaths } : {},
36115
+ ...clipImages ? { clipImages } : {}
36116
+ } };
36098
36117
  operations.push(operation);
36099
36118
  switch (operation.kind) {
36100
36119
  case "path":
@@ -36358,6 +36377,18 @@ function evaluateContentStreamToDisplayList(params) {
36358
36377
  let hasTextClip = false;
36359
36378
  let activeTm = [1, 0, 0, 1, 0, 0];
36360
36379
  let activeTlm = [1, 0, 0, 1, 0, 0];
36380
+ const paintImage = (image, patternMask, resources, activeFonts, depth) => {
36381
+ if (!patternMask) {
36382
+ emit({ kind: "image", value: image });
36383
+ return;
36384
+ }
36385
+ const st = curState();
36386
+ stateStack.push({ ...st, clipImages: [...st.clipImages ?? [], image] });
36387
+ walkNodes([{ kind: "path-op", paint: "f", segments: [
36388
+ { kind: "rect", x: 0, y: 0, width: 1, height: 1 }
36389
+ ] }], void 0, void 0, resources, activeFonts, depth);
36390
+ stateStack.pop();
36391
+ };
36361
36392
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
36362
36393
  for (const node of nodes) {
36363
36394
  switch (node.kind) {
@@ -36541,7 +36572,8 @@ function evaluateContentStreamToDisplayList(params) {
36541
36572
  st.fillAlpha,
36542
36573
  "PatternShading_" + st.fillPatternName,
36543
36574
  patClip,
36544
- shading?.kind === "stream" ? shading : void 0
36575
+ shading?.kind === "stream" ? shading : void 0,
36576
+ st.blendMode
36545
36577
  );
36546
36578
  if (shImg) {
36547
36579
  emit({ kind: "image", value: shImg });
@@ -36650,18 +36682,20 @@ function evaluateContentStreamToDisplayList(params) {
36650
36682
  const subNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "Subtype"));
36651
36683
  const sub = subNode?.kind === "name" ? subNode.decoded : "";
36652
36684
  if (sub === "Image") {
36685
+ const maskNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "ImageMask"));
36686
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36653
36687
  const decoded = decodeXObjectImageToRgba(
36654
36688
  params.cosDoc,
36655
36689
  xobjNode,
36656
36690
  activeResources,
36657
- {
36691
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36658
36692
  r: st.fillColor.r,
36659
36693
  g: st.fillColor.g,
36660
36694
  b: st.fillColor.b,
36661
36695
  alpha: st.fillAlpha
36662
36696
  }
36663
36697
  );
36664
- emit({ kind: "image", value: {
36698
+ paintImage({
36665
36699
  name: node.name,
36666
36700
  matrix: [...st.ctm],
36667
36701
  width: decoded.width,
@@ -36671,7 +36705,7 @@ function evaluateContentStreamToDisplayList(params) {
36671
36705
  decodedRgba: decoded.rgba,
36672
36706
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36673
36707
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36674
- } });
36708
+ }, patternMask, activeResources, activeFonts, depth);
36675
36709
  } else if (sub === "Form" && depth < 8) {
36676
36710
  const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36677
36711
  const formNodes = parseContentStream(formStreamBytes);
@@ -36727,19 +36761,22 @@ function evaluateContentStreamToDisplayList(params) {
36727
36761
  }
36728
36762
  case "inline-image": {
36729
36763
  const st = curState();
36764
+ const maskEntry = dictGet(node.dict, "ImageMask") ?? dictGet(node.dict, "IM");
36765
+ const maskNode = params.cosDoc ? params.cosDoc.resolve(maskEntry) : maskEntry;
36766
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36730
36767
  const decoded = decodeInlineImageNodeToRgba(
36731
36768
  params.cosDoc,
36732
36769
  node.dict,
36733
36770
  node.data,
36734
36771
  activeResources,
36735
- {
36772
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36736
36773
  r: st.fillColor.r,
36737
36774
  g: st.fillColor.g,
36738
36775
  b: st.fillColor.b,
36739
36776
  alpha: st.fillAlpha
36740
36777
  }
36741
36778
  );
36742
- emit({ kind: "image", value: {
36779
+ paintImage({
36743
36780
  name: "InlineImage",
36744
36781
  matrix: [...st.ctm],
36745
36782
  width: decoded.width,
@@ -36749,7 +36786,7 @@ function evaluateContentStreamToDisplayList(params) {
36749
36786
  decodedRgba: decoded.rgba,
36750
36787
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36751
36788
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36752
- } });
36789
+ }, patternMask, activeResources, activeFonts, depth);
36753
36790
  break;
36754
36791
  }
36755
36792
  case "text-object": {
@@ -40495,6 +40532,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40495
40532
  const aaVec = options.antialiasVector !== false;
40496
40533
  const aaTxt = options.antialiasText !== false;
40497
40534
  const clipMasks = /* @__PURE__ */ new Map();
40535
+ const imageClipMasks = /* @__PURE__ */ new Map();
40498
40536
  for (const original of paintOperations(displayList)) {
40499
40537
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40500
40538
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
@@ -40509,6 +40547,31 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40509
40547
  }
40510
40548
  clipMasks.set(clips, clipMask);
40511
40549
  }
40550
+ const imageClips = original.value.clipImages;
40551
+ if (imageClips) {
40552
+ let imageMask = imageClipMasks.get(imageClips);
40553
+ if (!imageMask) {
40554
+ imageMask = new Uint8Array(width * height * 4).fill(255);
40555
+ for (const image of imageClips) {
40556
+ const layer = renderDisplayListToBitmap({
40557
+ ...displayList,
40558
+ rotation: 0,
40559
+ paths: [],
40560
+ glyphs: [],
40561
+ images: [image],
40562
+ operations: [{ kind: "image", value: image }]
40563
+ }, { scale, transparent: true }).data;
40564
+ for (let i = 3; i < layer.length; i += 4) imageMask[i] = Math.round(imageMask[i] * layer[i] / 255);
40565
+ }
40566
+ imageClipMasks.set(imageClips, imageMask);
40567
+ }
40568
+ if (clipMask) {
40569
+ clipMask = clipMask.slice();
40570
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * imageMask[i] / 255);
40571
+ } else {
40572
+ clipMask = imageMask;
40573
+ }
40574
+ }
40512
40575
  if (operation.kind === "path") {
40513
40576
  const path = operation.value;
40514
40577
  if (path.fillColor) {
@@ -40657,6 +40720,15 @@ function escapeXmlText(str) {
40657
40720
  }
40658
40721
  return encodeToXmlString(valid);
40659
40722
  }
40723
+ function svgImage(image, pageHeight) {
40724
+ if (!image.decodedRgba) return "";
40725
+ const png = encodeRgbaToPng(image.width, image.height, image.decodedRgba);
40726
+ const chunks = [];
40727
+ for (let offset = 0; offset < png.length; offset += 8192)
40728
+ chunks.push(String.fromCharCode(...png.subarray(offset, offset + 8192)));
40729
+ const [a, b, c, d, e, f] = image.matrix;
40730
+ return `<image width="1" height="1" preserveAspectRatio="none" transform="matrix(${a} ${-b} ${-c} ${d} ${e + c} ${pageHeight - f - d})" href="data:image/png;base64,${btoa(chunks.join(""))}"/>`;
40731
+ }
40660
40732
  function svgPathData(segments, height) {
40661
40733
  const dParts = [];
40662
40734
  for (const seg of segments) {
@@ -40705,11 +40777,16 @@ function renderDisplayListToSvg(displayList, options = {}) {
40705
40777
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40706
40778
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40707
40779
  const clips = original.value.clipPaths ?? [];
40780
+ const imageClips = original.value.clipImages ?? [];
40708
40781
  for (const segments of clips) {
40709
40782
  const id = `text-clip-${clipId++}`;
40710
40783
  const path = `<path d="${svgPathData(segments, displayList.height)}"/>`;
40711
40784
  parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40712
40785
  }
40786
+ for (const image of imageClips) {
40787
+ const id = `image-clip-${clipId++}`;
40788
+ 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})">`);
40789
+ }
40713
40790
  if (operation.kind === "path") {
40714
40791
  const p = operation.value;
40715
40792
  const pathData = svgPathData(p.segments, displayList.height);
@@ -40729,24 +40806,9 @@ function renderDisplayListToSvg(displayList, options = {}) {
40729
40806
  parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40730
40807
  }
40731
40808
  } else if (operation.kind === "image") {
40732
- const img = operation.value;
40733
- if (!img.decodedRgba) {
40734
- for (let i = 0; i < clips.length; i++) parts.push("</g>");
40735
- continue;
40736
- }
40737
- const pngBytes = encodeRgbaToPng(img.width, img.height, img.decodedRgba);
40738
- const chunks = [];
40739
- for (let offset = 0; offset < pngBytes.length; offset += 8192)
40740
- chunks.push(String.fromCharCode(...pngBytes.subarray(offset, offset + 8192)));
40741
- const b64 = btoa(chunks.join(""));
40742
- const [a, b, c, d, e, f] = img.matrix;
40743
- const svgTx = e + c;
40744
- const svgTy = displayList.height - f - d;
40745
- parts.push(
40746
- ` <image width="1" height="1" preserveAspectRatio="none" transform="matrix(${a} ${-b} ${-c} ${d} ${svgTx} ${svgTy})" href="data:image/png;base64,${b64}"/>`
40747
- );
40809
+ parts.push(` ${svgImage(operation.value, displayList.height)}`);
40748
40810
  }
40749
- for (let i = 0; i < clips.length; i++) parts.push("</g>");
40811
+ for (let i = 0; i < clips.length + imageClips.length; i++) parts.push("</g>");
40750
40812
  }
40751
40813
  if (displayList.rotation) parts.push("</g>");
40752
40814
  parts.push("</svg>\n");
@@ -656,6 +656,7 @@ var messages_default = {
656
656
  "-5": "buffer error",
657
657
  "-6": "incompatible version"
658
658
  };
659
+ var Z_BUF_ERROR = -5;
659
660
  var MAX_MEM_LEVEL = 9;
660
661
  var HEAP_SIZE = 573;
661
662
  var MIN_MATCH = 3;
@@ -22547,22 +22548,31 @@ function decodeFlate(bytes, parms, maxDecodedBytes = DEFAULT_MAX_DECODED_BYTES)
22547
22548
  inflated = new BoundedFlateStream(bytes, maxDecodedBytes).getBytes();
22548
22549
  } catch (error) {
22549
22550
  if (error instanceof PdfError && error.code === "E_LIMIT") throw error;
22551
+ const wrapped = bytes[0] === 31 && bytes[1] === 139 || bytes.length >= 2 && (bytes[0] & 15) === 8 && bytes[0] >>> 4 <= 7 && (bytes[0] << 8 | bytes[1]) % 31 === 0;
22550
22552
  const decoder = new Inflate({
22551
- raw: !(bytes[0] === 31 && bytes[1] === 139),
22553
+ raw: !wrapped,
22552
22554
  chunkSize: Math.max(1, Math.min(64 * 1024, maxDecodedBytes + 1))
22553
22555
  });
22556
+ const chunks = [];
22554
22557
  let length = 0;
22555
22558
  decoder.onData = (chunk) => {
22556
22559
  length += chunk.length;
22557
22560
  if (length > maxDecodedBytes) {
22558
22561
  throw new PdfError("E_LIMIT", "FlateDecode output exceeds maximum decoded byte budget");
22559
22562
  }
22560
- decoder.chunks.push(chunk);
22563
+ chunks.push(chunk);
22561
22564
  };
22562
- if (!decoder.push(bytes, true) || decoder.err || !decoder.ended) {
22565
+ const complete = decoder.push(bytes, true);
22566
+ const truncated = wrapped && decoder.err === Z_BUF_ERROR && length > 0;
22567
+ if ((!complete || decoder.err || !decoder.ended) && !truncated) {
22563
22568
  throw new PdfError("E_CAPABILITY", "Invalid FlateDecode compressed stream");
22564
22569
  }
22565
- inflated = decoder.result;
22570
+ inflated = new Uint8Array(length);
22571
+ let offset = 0;
22572
+ for (const chunk of chunks) {
22573
+ inflated.set(chunk, offset);
22574
+ offset += chunk.length;
22575
+ }
22566
22576
  }
22567
22577
  return applyPredictor(inflated, parms);
22568
22578
  }
@@ -25274,7 +25284,7 @@ var ParsedCosDocument = class {
25274
25284
  return void 0;
25275
25285
  }
25276
25286
  };
25277
- function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false) {
25287
+ function parseNodeFromLexer(lexer, bytes, maxDepth, repair = false) {
25278
25288
  const stack = [];
25279
25289
  while (true) {
25280
25290
  const tok = lexer.nextToken();
@@ -25283,7 +25293,7 @@ function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false)
25283
25293
  if (!parent) return void 0;
25284
25294
  throw new PdfError("E_PARSE", parent.kind === "array" ? "Unterminated PDF array" : "Unterminated PDF dictionary");
25285
25295
  }
25286
- if (!parent && recoverEmptyObject && tok.kind === "keyword" && tok.value === "endobj") {
25296
+ if (!parent && repair && tok.kind === "keyword" && tok.value === "endobj") {
25287
25297
  return { kind: "null", span: tok.span };
25288
25298
  }
25289
25299
  let node;
@@ -25298,6 +25308,7 @@ function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false)
25298
25308
  parent.key = { kind: "name", rawBytes: tok.rawBytes, decoded: tok.decoded, span: tok.span };
25299
25309
  continue;
25300
25310
  } else {
25311
+ if (repair) continue;
25301
25312
  throw new PdfError("E_PARSE", `Expected dictionary key /Name, got ${tok.kind}`);
25302
25313
  }
25303
25314
  } else {
@@ -25466,7 +25477,7 @@ function parseHeaderVersion(bytes) {
25466
25477
  }
25467
25478
  return head.slice(idx + 5, idx + 8);
25468
25479
  }
25469
- function parseObjectAtOffset(bytes, offset, maxRecursionDepth, recoverEmptyObject = false) {
25480
+ function parseObjectAtOffset(bytes, offset, maxRecursionDepth, repair = false) {
25470
25481
  const lexer = new CosByteLexer(bytes, offset);
25471
25482
  const objNumTok = lexer.nextToken();
25472
25483
  const genNumTok = lexer.nextToken();
@@ -25474,7 +25485,7 @@ function parseObjectAtOffset(bytes, offset, maxRecursionDepth, recoverEmptyObjec
25474
25485
  if (objNumTok?.kind !== "number" || genNumTok?.kind !== "number" || objKwTok?.kind !== "keyword" || objKwTok.value !== "obj") {
25475
25486
  throw new PdfError("E_PARSE", `Malformed indirect object header at byte offset ${offset}`);
25476
25487
  }
25477
- const value = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, recoverEmptyObject);
25488
+ const value = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, repair);
25478
25489
  if (!value) {
25479
25490
  throw new PdfError("E_PARSE", `Empty indirect object ${objNumTok.value} at offset ${offset}`);
25480
25491
  }
@@ -25663,7 +25674,7 @@ function repairScanCosDocument(bytes, maxObjects, maxRecursionDepth) {
25663
25674
  try {
25664
25675
  const token = lexer.nextToken();
25665
25676
  if (token?.kind === "keyword" && token.value === "trailer") {
25666
- const trailer = parseNodeFromLexer(lexer, bytes, maxRecursionDepth);
25677
+ const trailer = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, true);
25667
25678
  if (trailer?.kind === "dict") trailers.push(trailer);
25668
25679
  pos = lexer.offset;
25669
25680
  continue;
@@ -25719,7 +25730,7 @@ function unpackRecoveredObjects(objects, maxObjects, maxDecompressedBytes, maxRe
25719
25730
  const t = dictGet(obj.value.dict, "Type");
25720
25731
  if (t?.kind === "name" && t.decoded === "ObjStm") {
25721
25732
  try {
25722
- for (const [unpackedNum, unpackedVal] of unpackObjectStream(obj.value, maxDecompressedBytes, maxRecursionDepth).entries()) {
25733
+ for (const [unpackedNum, unpackedVal] of unpackObjectStream(obj.value, maxDecompressedBytes, maxRecursionDepth, true).entries()) {
25723
25734
  if (!objects.has(unpackedNum)) {
25724
25735
  objects.set(unpackedNum, {
25725
25736
  objectNumber: unpackedNum,
@@ -25755,7 +25766,7 @@ function recoveredReferences(objects) {
25755
25766
  }
25756
25767
  return { ...rootRef ? { rootRef } : {}, ...infoRef ? { infoRef } : {} };
25757
25768
  }
25758
- function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth) {
25769
+ function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth, repair = false) {
25759
25770
  const nNode = dictGet(streamObj.dict, "N");
25760
25771
  const firstNode = dictGet(streamObj.dict, "First");
25761
25772
  if (nNode?.kind !== "number" || firstNode?.kind !== "number") {
@@ -25775,7 +25786,7 @@ function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth)
25775
25786
  for (const pair of pairs) {
25776
25787
  try {
25777
25788
  const valLexer = new CosByteLexer(decoded, firstNode.value + pair.relativeOffset);
25778
- const node = parseNodeFromLexer(valLexer, decoded, maxRecursionDepth);
25789
+ const node = parseNodeFromLexer(valLexer, decoded, maxRecursionDepth, repair);
25779
25790
  if (node) {
25780
25791
  result.set(pair.objectNumber, node);
25781
25792
  }
@@ -25958,7 +25969,7 @@ function parseCosDocument(bytes, options = {}) {
25958
25969
  if (!unpacked) {
25959
25970
  const stmObj = objects.get(entry.objectStreamNumber)?.value;
25960
25971
  if (stmObj?.kind === "stream") {
25961
- unpacked = unpackObjectStream(stmObj, maxDecompressedBytes, maxRecursionDepth);
25972
+ unpacked = unpackObjectStream(stmObj, maxDecompressedBytes, maxRecursionDepth, recovery === "repair");
25962
25973
  objStmCache.set(entry.objectStreamNumber, unpacked);
25963
25974
  }
25964
25975
  }
@@ -34430,7 +34441,11 @@ function resolvePageFonts(doc, resourcesDict) {
34430
34441
  let cmap;
34431
34442
  const toUniNode = doc.resolve(dictGet(fObj, "ToUnicode"));
34432
34443
  if (toUniNode?.kind === "stream") {
34433
- cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34444
+ try {
34445
+ cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34446
+ } catch (error) {
34447
+ if (error instanceof PdfError && error.code === "E_LIMIT") throw error;
34448
+ }
34434
34449
  }
34435
34450
  const encNode = doc.resolve(dictGet(fObj, "Encoding"));
34436
34451
  if (encNode?.kind === "dict") {
@@ -34446,7 +34461,7 @@ function resolvePageFonts(doc, resourcesDict) {
34446
34461
  const glyphNames = buildFontEncodingGlyphNamesMap(encNode);
34447
34462
  const widths = /* @__PURE__ */ new Map();
34448
34463
  let defaultWidth = 556;
34449
- const isTwoByteCid = subtype === "Type0" || Boolean(cmap?.isTwoByte);
34464
+ const isTwoByteCid = subtype === "Type0";
34450
34465
  let fontMatrix;
34451
34466
  let charProcs;
34452
34467
  let fontResources;
@@ -35554,8 +35569,12 @@ function evaluateContentStreamToDisplayList(params) {
35554
35569
  const images = [];
35555
35570
  const operations = [];
35556
35571
  const emit = (operation) => {
35557
- const clipPaths = curState().clipPaths;
35558
- if (clipPaths) operation = { ...operation, value: { ...operation.value, clipPaths } };
35572
+ const { clipPaths, clipImages } = curState();
35573
+ if (clipPaths || clipImages) operation = { ...operation, value: {
35574
+ ...operation.value,
35575
+ ...clipPaths ? { clipPaths } : {},
35576
+ ...clipImages ? { clipImages } : {}
35577
+ } };
35559
35578
  operations.push(operation);
35560
35579
  switch (operation.kind) {
35561
35580
  case "path":
@@ -35819,6 +35838,18 @@ function evaluateContentStreamToDisplayList(params) {
35819
35838
  let hasTextClip = false;
35820
35839
  let activeTm = [1, 0, 0, 1, 0, 0];
35821
35840
  let activeTlm = [1, 0, 0, 1, 0, 0];
35841
+ const paintImage = (image, patternMask, resources, activeFonts, depth) => {
35842
+ if (!patternMask) {
35843
+ emit({ kind: "image", value: image });
35844
+ return;
35845
+ }
35846
+ const st = curState();
35847
+ stateStack.push({ ...st, clipImages: [...st.clipImages ?? [], image] });
35848
+ walkNodes([{ kind: "path-op", paint: "f", segments: [
35849
+ { kind: "rect", x: 0, y: 0, width: 1, height: 1 }
35850
+ ] }], void 0, void 0, resources, activeFonts, depth);
35851
+ stateStack.pop();
35852
+ };
35822
35853
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
35823
35854
  for (const node of nodes) {
35824
35855
  switch (node.kind) {
@@ -36002,7 +36033,8 @@ function evaluateContentStreamToDisplayList(params) {
36002
36033
  st.fillAlpha,
36003
36034
  "PatternShading_" + st.fillPatternName,
36004
36035
  patClip,
36005
- shading?.kind === "stream" ? shading : void 0
36036
+ shading?.kind === "stream" ? shading : void 0,
36037
+ st.blendMode
36006
36038
  );
36007
36039
  if (shImg) {
36008
36040
  emit({ kind: "image", value: shImg });
@@ -36111,18 +36143,20 @@ function evaluateContentStreamToDisplayList(params) {
36111
36143
  const subNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "Subtype"));
36112
36144
  const sub = subNode?.kind === "name" ? subNode.decoded : "";
36113
36145
  if (sub === "Image") {
36146
+ const maskNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "ImageMask"));
36147
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36114
36148
  const decoded = decodeXObjectImageToRgba(
36115
36149
  params.cosDoc,
36116
36150
  xobjNode,
36117
36151
  activeResources,
36118
- {
36152
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36119
36153
  r: st.fillColor.r,
36120
36154
  g: st.fillColor.g,
36121
36155
  b: st.fillColor.b,
36122
36156
  alpha: st.fillAlpha
36123
36157
  }
36124
36158
  );
36125
- emit({ kind: "image", value: {
36159
+ paintImage({
36126
36160
  name: node.name,
36127
36161
  matrix: [...st.ctm],
36128
36162
  width: decoded.width,
@@ -36132,7 +36166,7 @@ function evaluateContentStreamToDisplayList(params) {
36132
36166
  decodedRgba: decoded.rgba,
36133
36167
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36134
36168
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36135
- } });
36169
+ }, patternMask, activeResources, activeFonts, depth);
36136
36170
  } else if (sub === "Form" && depth < 8) {
36137
36171
  const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36138
36172
  const formNodes = parseContentStream(formStreamBytes);
@@ -36188,19 +36222,22 @@ function evaluateContentStreamToDisplayList(params) {
36188
36222
  }
36189
36223
  case "inline-image": {
36190
36224
  const st = curState();
36225
+ const maskEntry = dictGet(node.dict, "ImageMask") ?? dictGet(node.dict, "IM");
36226
+ const maskNode = params.cosDoc ? params.cosDoc.resolve(maskEntry) : maskEntry;
36227
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36191
36228
  const decoded = decodeInlineImageNodeToRgba(
36192
36229
  params.cosDoc,
36193
36230
  node.dict,
36194
36231
  node.data,
36195
36232
  activeResources,
36196
- {
36233
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36197
36234
  r: st.fillColor.r,
36198
36235
  g: st.fillColor.g,
36199
36236
  b: st.fillColor.b,
36200
36237
  alpha: st.fillAlpha
36201
36238
  }
36202
36239
  );
36203
- emit({ kind: "image", value: {
36240
+ paintImage({
36204
36241
  name: "InlineImage",
36205
36242
  matrix: [...st.ctm],
36206
36243
  width: decoded.width,
@@ -36210,7 +36247,7 @@ function evaluateContentStreamToDisplayList(params) {
36210
36247
  decodedRgba: decoded.rgba,
36211
36248
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36212
36249
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36213
- } });
36250
+ }, patternMask, activeResources, activeFonts, depth);
36214
36251
  break;
36215
36252
  }
36216
36253
  case "text-object": {
@@ -40124,6 +40161,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40124
40161
  const aaVec = options.antialiasVector !== false;
40125
40162
  const aaTxt = options.antialiasText !== false;
40126
40163
  const clipMasks = /* @__PURE__ */ new Map();
40164
+ const imageClipMasks = /* @__PURE__ */ new Map();
40127
40165
  for (const original of paintOperations(displayList)) {
40128
40166
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40129
40167
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
@@ -40138,6 +40176,31 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40138
40176
  }
40139
40177
  clipMasks.set(clips, clipMask);
40140
40178
  }
40179
+ const imageClips = original.value.clipImages;
40180
+ if (imageClips) {
40181
+ let imageMask = imageClipMasks.get(imageClips);
40182
+ if (!imageMask) {
40183
+ imageMask = new Uint8Array(width * height * 4).fill(255);
40184
+ for (const image of imageClips) {
40185
+ const layer = renderDisplayListToBitmap({
40186
+ ...displayList,
40187
+ rotation: 0,
40188
+ paths: [],
40189
+ glyphs: [],
40190
+ images: [image],
40191
+ operations: [{ kind: "image", value: image }]
40192
+ }, { scale, transparent: true }).data;
40193
+ for (let i = 3; i < layer.length; i += 4) imageMask[i] = Math.round(imageMask[i] * layer[i] / 255);
40194
+ }
40195
+ imageClipMasks.set(imageClips, imageMask);
40196
+ }
40197
+ if (clipMask) {
40198
+ clipMask = clipMask.slice();
40199
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * imageMask[i] / 255);
40200
+ } else {
40201
+ clipMask = imageMask;
40202
+ }
40203
+ }
40141
40204
  if (operation.kind === "path") {
40142
40205
  const path = operation.value;
40143
40206
  if (path.fillColor) {