@poe-platform/safe-bash 0.1.757 → 0.1.758

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 (55) hide show
  1. package/dist/image-ast/index.browser.js +72 -19
  2. package/dist/image-ast/index.js +72 -19
  3. package/dist/pdf-ast/ast.d.ts +3 -0
  4. package/dist/pdf-ast/index.js +88 -36
  5. package/dist/safe-bash/command-chunks/{chunk-F3J5ZLKF.js → chunk-522TDVLS.js} +1 -1
  6. package/dist/safe-bash/command-chunks/{chunk-VFS2MDAB.js → chunk-6YLD37NH.js} +2 -2
  7. package/dist/safe-bash/command-chunks/{chunk-YI3GKJ7Q.js → chunk-766IWMTB.js} +2 -2
  8. package/dist/safe-bash/command-chunks/{chunk-KSH2F6RG.js → chunk-CUFCNL6G.js} +1 -1
  9. package/dist/safe-bash/command-chunks/{chunk-S4MLIYSN.js → chunk-J2NPH7DO.js} +4 -0
  10. package/dist/safe-bash/command-chunks/{chunk-KBBI4CSU.js → chunk-L2C5TIII.js} +2 -2
  11. package/dist/safe-bash/command-chunks/{chunk-H2FQA4OU.js → chunk-TCAGGM44.js} +72 -19
  12. package/dist/safe-bash/command-chunks/{chunk-WI35236J.js → chunk-XYCWDGOG.js} +1 -1
  13. package/dist/safe-bash/command-chunks/{chunk-4F6PG2OT.js → chunk-YJWWRCIG.js} +8 -8
  14. package/dist/safe-bash-command-column/column.js +3 -3
  15. package/dist/safe-bash-command-column/index.js +3 -3
  16. package/dist/safe-bash-command-column/layout.js +2 -2
  17. package/dist/safe-bash-command-factor/command.js +2 -2
  18. package/dist/safe-bash-command-factor/index.js +2 -2
  19. package/dist/safe-bash-command-ffmpeg/index.js +5923 -5893
  20. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  21. package/dist/safe-bash-command-pandoc/command.js +3 -3
  22. package/dist/safe-bash-command-pandoc/index.js +3 -3
  23. package/dist/safe-bash-command-pdfimages/index.js +72 -19
  24. package/dist/safe-bash-command-pdfinfo/index.js +88 -36
  25. package/dist/safe-bash-command-pdftk/index.js +72 -19
  26. package/dist/safe-bash-command-pdftoppm/index.js +88 -36
  27. package/dist/safe-bash-command-pdftotext/index.js +72 -19
  28. package/dist/safe-bash-command-qpdf/index.js +72 -19
  29. package/dist/safe-bash-command-sips/index.js +2 -2
  30. package/dist/safe-bash-command-soffice/index.js +2 -2
  31. package/dist/safe-bash-command-ssconvert/command-bindings.d.ts +18 -0
  32. package/dist/safe-bash-command-ssconvert/command.d.ts +5 -14
  33. package/dist/safe-bash-command-ssconvert/commands.d.ts +6 -0
  34. package/dist/safe-bash-command-ssconvert/commands.js +871 -0
  35. package/dist/safe-bash-command-ssconvert/core.js +1 -1
  36. package/dist/safe-bash-command-ssconvert/index.js +269 -209
  37. package/dist/safe-bash-command-wkhtmltopdf/index.js +72 -19
  38. package/dist/safe-bash-command-yq/index.js +4 -4
  39. package/dist/safe-bash-compression-engine/files.js +2 -2
  40. package/dist/safe-bash-compression-engine/operand.js +4 -4
  41. package/dist/safe-bash-markdown-engine/commonmark-blocks.js +4 -4
  42. package/dist/safe-bash-markdown-engine/commonmark-inlines.js +4 -4
  43. package/dist/safe-bash-markdown-engine/commonmark-syntax.js +2 -2
  44. package/dist/safe-bash-markdown-engine/gfm-syntax.js +3 -3
  45. package/dist/safe-bash-markdown-engine/index.js +7 -7
  46. package/dist/safe-bash-query-engine/index.js +5 -5
  47. package/dist/safe-bash-query-engine/interpreter.js +4 -4
  48. package/dist/safe-bash-query-engine/query-core.js +5 -5
  49. package/package.json +6 -2
  50. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +16 -0
  51. package/dist/safe-bash/command-chunks/{chunk-OQVIJMBY.js → chunk-7HINP7ZK.js} +4 -4
  52. package/dist/safe-bash/command-chunks/{chunk-XAYEDOV5.js → chunk-CG4JSOK2.js} +3 -3
  53. package/dist/safe-bash/command-chunks/{chunk-YIK4ZYQ4.js → chunk-DC52GWRK.js} +9 -9
  54. package/dist/safe-bash/command-chunks/{chunk-TOTZFBDT.js → chunk-TKACIO4X.js} +4 -4
  55. package/dist/safe-bash/command-chunks/{chunk-VTWKS4RM.js → chunk-WF2LSKMI.js} +3 -3
@@ -25274,7 +25274,7 @@ var ParsedCosDocument = class {
25274
25274
  return void 0;
25275
25275
  }
25276
25276
  };
25277
- function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false) {
25277
+ function parseNodeFromLexer(lexer, bytes, maxDepth, repair = false) {
25278
25278
  const stack = [];
25279
25279
  while (true) {
25280
25280
  const tok = lexer.nextToken();
@@ -25283,7 +25283,7 @@ function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false)
25283
25283
  if (!parent) return void 0;
25284
25284
  throw new PdfError("E_PARSE", parent.kind === "array" ? "Unterminated PDF array" : "Unterminated PDF dictionary");
25285
25285
  }
25286
- if (!parent && recoverEmptyObject && tok.kind === "keyword" && tok.value === "endobj") {
25286
+ if (!parent && repair && tok.kind === "keyword" && tok.value === "endobj") {
25287
25287
  return { kind: "null", span: tok.span };
25288
25288
  }
25289
25289
  let node;
@@ -25298,6 +25298,7 @@ function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false)
25298
25298
  parent.key = { kind: "name", rawBytes: tok.rawBytes, decoded: tok.decoded, span: tok.span };
25299
25299
  continue;
25300
25300
  } else {
25301
+ if (repair) continue;
25301
25302
  throw new PdfError("E_PARSE", `Expected dictionary key /Name, got ${tok.kind}`);
25302
25303
  }
25303
25304
  } else {
@@ -25466,7 +25467,7 @@ function parseHeaderVersion(bytes) {
25466
25467
  }
25467
25468
  return head.slice(idx + 5, idx + 8);
25468
25469
  }
25469
- function parseObjectAtOffset(bytes, offset, maxRecursionDepth, recoverEmptyObject = false) {
25470
+ function parseObjectAtOffset(bytes, offset, maxRecursionDepth, repair = false) {
25470
25471
  const lexer = new CosByteLexer(bytes, offset);
25471
25472
  const objNumTok = lexer.nextToken();
25472
25473
  const genNumTok = lexer.nextToken();
@@ -25474,7 +25475,7 @@ function parseObjectAtOffset(bytes, offset, maxRecursionDepth, recoverEmptyObjec
25474
25475
  if (objNumTok?.kind !== "number" || genNumTok?.kind !== "number" || objKwTok?.kind !== "keyword" || objKwTok.value !== "obj") {
25475
25476
  throw new PdfError("E_PARSE", `Malformed indirect object header at byte offset ${offset}`);
25476
25477
  }
25477
- const value = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, recoverEmptyObject);
25478
+ const value = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, repair);
25478
25479
  if (!value) {
25479
25480
  throw new PdfError("E_PARSE", `Empty indirect object ${objNumTok.value} at offset ${offset}`);
25480
25481
  }
@@ -25663,7 +25664,7 @@ function repairScanCosDocument(bytes, maxObjects, maxRecursionDepth) {
25663
25664
  try {
25664
25665
  const token = lexer.nextToken();
25665
25666
  if (token?.kind === "keyword" && token.value === "trailer") {
25666
- const trailer = parseNodeFromLexer(lexer, bytes, maxRecursionDepth);
25667
+ const trailer = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, true);
25667
25668
  if (trailer?.kind === "dict") trailers.push(trailer);
25668
25669
  pos = lexer.offset;
25669
25670
  continue;
@@ -25719,7 +25720,7 @@ function unpackRecoveredObjects(objects, maxObjects, maxDecompressedBytes, maxRe
25719
25720
  const t = dictGet(obj.value.dict, "Type");
25720
25721
  if (t?.kind === "name" && t.decoded === "ObjStm") {
25721
25722
  try {
25722
- for (const [unpackedNum, unpackedVal] of unpackObjectStream(obj.value, maxDecompressedBytes, maxRecursionDepth).entries()) {
25723
+ for (const [unpackedNum, unpackedVal] of unpackObjectStream(obj.value, maxDecompressedBytes, maxRecursionDepth, true).entries()) {
25723
25724
  if (!objects.has(unpackedNum)) {
25724
25725
  objects.set(unpackedNum, {
25725
25726
  objectNumber: unpackedNum,
@@ -25755,7 +25756,7 @@ function recoveredReferences(objects) {
25755
25756
  }
25756
25757
  return { ...rootRef ? { rootRef } : {}, ...infoRef ? { infoRef } : {} };
25757
25758
  }
25758
- function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth) {
25759
+ function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth, repair = false) {
25759
25760
  const nNode = dictGet(streamObj.dict, "N");
25760
25761
  const firstNode = dictGet(streamObj.dict, "First");
25761
25762
  if (nNode?.kind !== "number" || firstNode?.kind !== "number") {
@@ -25775,7 +25776,7 @@ function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth)
25775
25776
  for (const pair of pairs) {
25776
25777
  try {
25777
25778
  const valLexer = new CosByteLexer(decoded, firstNode.value + pair.relativeOffset);
25778
- const node = parseNodeFromLexer(valLexer, decoded, maxRecursionDepth);
25779
+ const node = parseNodeFromLexer(valLexer, decoded, maxRecursionDepth, repair);
25779
25780
  if (node) {
25780
25781
  result.set(pair.objectNumber, node);
25781
25782
  }
@@ -25958,7 +25959,7 @@ function parseCosDocument(bytes, options = {}) {
25958
25959
  if (!unpacked) {
25959
25960
  const stmObj = objects.get(entry.objectStreamNumber)?.value;
25960
25961
  if (stmObj?.kind === "stream") {
25961
- unpacked = unpackObjectStream(stmObj, maxDecompressedBytes, maxRecursionDepth);
25962
+ unpacked = unpackObjectStream(stmObj, maxDecompressedBytes, maxRecursionDepth, recovery === "repair");
25962
25963
  objStmCache.set(entry.objectStreamNumber, unpacked);
25963
25964
  }
25964
25965
  }
@@ -34430,7 +34431,11 @@ function resolvePageFonts(doc, resourcesDict) {
34430
34431
  let cmap;
34431
34432
  const toUniNode = doc.resolve(dictGet(fObj, "ToUnicode"));
34432
34433
  if (toUniNode?.kind === "stream") {
34433
- cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34434
+ try {
34435
+ cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34436
+ } catch (error) {
34437
+ if (error instanceof PdfError && error.code === "E_LIMIT") throw error;
34438
+ }
34434
34439
  }
34435
34440
  const encNode = doc.resolve(dictGet(fObj, "Encoding"));
34436
34441
  if (encNode?.kind === "dict") {
@@ -35554,8 +35559,12 @@ function evaluateContentStreamToDisplayList(params) {
35554
35559
  const images = [];
35555
35560
  const operations = [];
35556
35561
  const emit = (operation) => {
35557
- const clipPaths = curState().clipPaths;
35558
- if (clipPaths) operation = { ...operation, value: { ...operation.value, clipPaths } };
35562
+ const { clipPaths, clipImages } = curState();
35563
+ if (clipPaths || clipImages) operation = { ...operation, value: {
35564
+ ...operation.value,
35565
+ ...clipPaths ? { clipPaths } : {},
35566
+ ...clipImages ? { clipImages } : {}
35567
+ } };
35559
35568
  operations.push(operation);
35560
35569
  switch (operation.kind) {
35561
35570
  case "path":
@@ -35819,6 +35828,18 @@ function evaluateContentStreamToDisplayList(params) {
35819
35828
  let hasTextClip = false;
35820
35829
  let activeTm = [1, 0, 0, 1, 0, 0];
35821
35830
  let activeTlm = [1, 0, 0, 1, 0, 0];
35831
+ const paintImage = (image, patternMask, resources, activeFonts, depth) => {
35832
+ if (!patternMask) {
35833
+ emit({ kind: "image", value: image });
35834
+ return;
35835
+ }
35836
+ const st = curState();
35837
+ stateStack.push({ ...st, clipImages: [...st.clipImages ?? [], image] });
35838
+ walkNodes([{ kind: "path-op", paint: "f", segments: [
35839
+ { kind: "rect", x: 0, y: 0, width: 1, height: 1 }
35840
+ ] }], void 0, void 0, resources, activeFonts, depth);
35841
+ stateStack.pop();
35842
+ };
35822
35843
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
35823
35844
  for (const node of nodes) {
35824
35845
  switch (node.kind) {
@@ -36002,7 +36023,8 @@ function evaluateContentStreamToDisplayList(params) {
36002
36023
  st.fillAlpha,
36003
36024
  "PatternShading_" + st.fillPatternName,
36004
36025
  patClip,
36005
- shading?.kind === "stream" ? shading : void 0
36026
+ shading?.kind === "stream" ? shading : void 0,
36027
+ st.blendMode
36006
36028
  );
36007
36029
  if (shImg) {
36008
36030
  emit({ kind: "image", value: shImg });
@@ -36111,18 +36133,20 @@ function evaluateContentStreamToDisplayList(params) {
36111
36133
  const subNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "Subtype"));
36112
36134
  const sub = subNode?.kind === "name" ? subNode.decoded : "";
36113
36135
  if (sub === "Image") {
36136
+ const maskNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "ImageMask"));
36137
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36114
36138
  const decoded = decodeXObjectImageToRgba(
36115
36139
  params.cosDoc,
36116
36140
  xobjNode,
36117
36141
  activeResources,
36118
- {
36142
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36119
36143
  r: st.fillColor.r,
36120
36144
  g: st.fillColor.g,
36121
36145
  b: st.fillColor.b,
36122
36146
  alpha: st.fillAlpha
36123
36147
  }
36124
36148
  );
36125
- emit({ kind: "image", value: {
36149
+ paintImage({
36126
36150
  name: node.name,
36127
36151
  matrix: [...st.ctm],
36128
36152
  width: decoded.width,
@@ -36132,7 +36156,7 @@ function evaluateContentStreamToDisplayList(params) {
36132
36156
  decodedRgba: decoded.rgba,
36133
36157
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36134
36158
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36135
- } });
36159
+ }, patternMask, activeResources, activeFonts, depth);
36136
36160
  } else if (sub === "Form" && depth < 8) {
36137
36161
  const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36138
36162
  const formNodes = parseContentStream(formStreamBytes);
@@ -36188,19 +36212,22 @@ function evaluateContentStreamToDisplayList(params) {
36188
36212
  }
36189
36213
  case "inline-image": {
36190
36214
  const st = curState();
36215
+ const maskEntry = dictGet(node.dict, "ImageMask") ?? dictGet(node.dict, "IM");
36216
+ const maskNode = params.cosDoc ? params.cosDoc.resolve(maskEntry) : maskEntry;
36217
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36191
36218
  const decoded = decodeInlineImageNodeToRgba(
36192
36219
  params.cosDoc,
36193
36220
  node.dict,
36194
36221
  node.data,
36195
36222
  activeResources,
36196
- {
36223
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36197
36224
  r: st.fillColor.r,
36198
36225
  g: st.fillColor.g,
36199
36226
  b: st.fillColor.b,
36200
36227
  alpha: st.fillAlpha
36201
36228
  }
36202
36229
  );
36203
- emit({ kind: "image", value: {
36230
+ paintImage({
36204
36231
  name: "InlineImage",
36205
36232
  matrix: [...st.ctm],
36206
36233
  width: decoded.width,
@@ -36210,7 +36237,7 @@ function evaluateContentStreamToDisplayList(params) {
36210
36237
  decodedRgba: decoded.rgba,
36211
36238
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36212
36239
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36213
- } });
36240
+ }, patternMask, activeResources, activeFonts, depth);
36214
36241
  break;
36215
36242
  }
36216
36243
  case "text-object": {
@@ -40124,6 +40151,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40124
40151
  const aaVec = options.antialiasVector !== false;
40125
40152
  const aaTxt = options.antialiasText !== false;
40126
40153
  const clipMasks = /* @__PURE__ */ new Map();
40154
+ const imageClipMasks = /* @__PURE__ */ new Map();
40127
40155
  for (const original of paintOperations(displayList)) {
40128
40156
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40129
40157
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
@@ -40138,6 +40166,31 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40138
40166
  }
40139
40167
  clipMasks.set(clips, clipMask);
40140
40168
  }
40169
+ const imageClips = original.value.clipImages;
40170
+ if (imageClips) {
40171
+ let imageMask = imageClipMasks.get(imageClips);
40172
+ if (!imageMask) {
40173
+ imageMask = new Uint8Array(width * height * 4).fill(255);
40174
+ for (const image of imageClips) {
40175
+ const layer = renderDisplayListToBitmap({
40176
+ ...displayList,
40177
+ rotation: 0,
40178
+ paths: [],
40179
+ glyphs: [],
40180
+ images: [image],
40181
+ operations: [{ kind: "image", value: image }]
40182
+ }, { scale, transparent: true }).data;
40183
+ for (let i = 3; i < layer.length; i += 4) imageMask[i] = Math.round(imageMask[i] * layer[i] / 255);
40184
+ }
40185
+ imageClipMasks.set(imageClips, imageMask);
40186
+ }
40187
+ if (clipMask) {
40188
+ clipMask = clipMask.slice();
40189
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * imageMask[i] / 255);
40190
+ } else {
40191
+ clipMask = imageMask;
40192
+ }
40193
+ }
40141
40194
  if (operation.kind === "path") {
40142
40195
  const path = operation.value;
40143
40196
  if (path.fillColor) {
@@ -25468,7 +25468,7 @@ var ParsedCosDocument = class {
25468
25468
  return void 0;
25469
25469
  }
25470
25470
  };
25471
- function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false) {
25471
+ function parseNodeFromLexer(lexer, bytes, maxDepth, repair = false) {
25472
25472
  const stack = [];
25473
25473
  while (true) {
25474
25474
  const tok = lexer.nextToken();
@@ -25477,7 +25477,7 @@ function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false)
25477
25477
  if (!parent) return void 0;
25478
25478
  throw new PdfError("E_PARSE", parent.kind === "array" ? "Unterminated PDF array" : "Unterminated PDF dictionary");
25479
25479
  }
25480
- if (!parent && recoverEmptyObject && tok.kind === "keyword" && tok.value === "endobj") {
25480
+ if (!parent && repair && tok.kind === "keyword" && tok.value === "endobj") {
25481
25481
  return { kind: "null", span: tok.span };
25482
25482
  }
25483
25483
  let node;
@@ -25492,6 +25492,7 @@ function parseNodeFromLexer(lexer, bytes, maxDepth, recoverEmptyObject = false)
25492
25492
  parent.key = { kind: "name", rawBytes: tok.rawBytes, decoded: tok.decoded, span: tok.span };
25493
25493
  continue;
25494
25494
  } else {
25495
+ if (repair) continue;
25495
25496
  throw new PdfError("E_PARSE", `Expected dictionary key /Name, got ${tok.kind}`);
25496
25497
  }
25497
25498
  } else {
@@ -25660,7 +25661,7 @@ function parseHeaderVersion(bytes) {
25660
25661
  }
25661
25662
  return head.slice(idx + 5, idx + 8);
25662
25663
  }
25663
- function parseObjectAtOffset(bytes, offset, maxRecursionDepth, recoverEmptyObject = false) {
25664
+ function parseObjectAtOffset(bytes, offset, maxRecursionDepth, repair = false) {
25664
25665
  const lexer = new CosByteLexer(bytes, offset);
25665
25666
  const objNumTok = lexer.nextToken();
25666
25667
  const genNumTok = lexer.nextToken();
@@ -25668,7 +25669,7 @@ function parseObjectAtOffset(bytes, offset, maxRecursionDepth, recoverEmptyObjec
25668
25669
  if (objNumTok?.kind !== "number" || genNumTok?.kind !== "number" || objKwTok?.kind !== "keyword" || objKwTok.value !== "obj") {
25669
25670
  throw new PdfError("E_PARSE", `Malformed indirect object header at byte offset ${offset}`);
25670
25671
  }
25671
- const value = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, recoverEmptyObject);
25672
+ const value = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, repair);
25672
25673
  if (!value) {
25673
25674
  throw new PdfError("E_PARSE", `Empty indirect object ${objNumTok.value} at offset ${offset}`);
25674
25675
  }
@@ -25857,7 +25858,7 @@ function repairScanCosDocument(bytes, maxObjects, maxRecursionDepth) {
25857
25858
  try {
25858
25859
  const token = lexer.nextToken();
25859
25860
  if (token?.kind === "keyword" && token.value === "trailer") {
25860
- const trailer = parseNodeFromLexer(lexer, bytes, maxRecursionDepth);
25861
+ const trailer = parseNodeFromLexer(lexer, bytes, maxRecursionDepth, true);
25861
25862
  if (trailer?.kind === "dict") trailers.push(trailer);
25862
25863
  pos = lexer.offset;
25863
25864
  continue;
@@ -25913,7 +25914,7 @@ function unpackRecoveredObjects(objects, maxObjects, maxDecompressedBytes, maxRe
25913
25914
  const t = dictGet(obj.value.dict, "Type");
25914
25915
  if (t?.kind === "name" && t.decoded === "ObjStm") {
25915
25916
  try {
25916
- for (const [unpackedNum, unpackedVal] of unpackObjectStream(obj.value, maxDecompressedBytes, maxRecursionDepth).entries()) {
25917
+ for (const [unpackedNum, unpackedVal] of unpackObjectStream(obj.value, maxDecompressedBytes, maxRecursionDepth, true).entries()) {
25917
25918
  if (!objects.has(unpackedNum)) {
25918
25919
  objects.set(unpackedNum, {
25919
25920
  objectNumber: unpackedNum,
@@ -25949,7 +25950,7 @@ function recoveredReferences(objects) {
25949
25950
  }
25950
25951
  return { ...rootRef ? { rootRef } : {}, ...infoRef ? { infoRef } : {} };
25951
25952
  }
25952
- function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth) {
25953
+ function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth, repair = false) {
25953
25954
  const nNode = dictGet(streamObj.dict, "N");
25954
25955
  const firstNode = dictGet(streamObj.dict, "First");
25955
25956
  if (nNode?.kind !== "number" || firstNode?.kind !== "number") {
@@ -25969,7 +25970,7 @@ function unpackObjectStream(streamObj, maxDecompressedBytes, maxRecursionDepth)
25969
25970
  for (const pair of pairs) {
25970
25971
  try {
25971
25972
  const valLexer = new CosByteLexer(decoded, firstNode.value + pair.relativeOffset);
25972
- const node = parseNodeFromLexer(valLexer, decoded, maxRecursionDepth);
25973
+ const node = parseNodeFromLexer(valLexer, decoded, maxRecursionDepth, repair);
25973
25974
  if (node) {
25974
25975
  result.set(pair.objectNumber, node);
25975
25976
  }
@@ -26152,7 +26153,7 @@ function parseCosDocument(bytes, options = {}) {
26152
26153
  if (!unpacked) {
26153
26154
  const stmObj = objects.get(entry.objectStreamNumber)?.value;
26154
26155
  if (stmObj?.kind === "stream") {
26155
- unpacked = unpackObjectStream(stmObj, maxDecompressedBytes, maxRecursionDepth);
26156
+ unpacked = unpackObjectStream(stmObj, maxDecompressedBytes, maxRecursionDepth, recovery === "repair");
26156
26157
  objStmCache.set(entry.objectStreamNumber, unpacked);
26157
26158
  }
26158
26159
  }
@@ -34624,7 +34625,11 @@ function resolvePageFonts(doc, resourcesDict) {
34624
34625
  let cmap;
34625
34626
  const toUniNode = doc.resolve(dictGet(fObj, "ToUnicode"));
34626
34627
  if (toUniNode?.kind === "stream") {
34627
- cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34628
+ try {
34629
+ cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34630
+ } catch (error) {
34631
+ if (error instanceof PdfError && error.code === "E_LIMIT") throw error;
34632
+ }
34628
34633
  }
34629
34634
  const encNode = doc.resolve(dictGet(fObj, "Encoding"));
34630
34635
  if (encNode?.kind === "dict") {
@@ -35748,8 +35753,12 @@ function evaluateContentStreamToDisplayList(params) {
35748
35753
  const images = [];
35749
35754
  const operations = [];
35750
35755
  const emit = (operation) => {
35751
- const clipPaths = curState().clipPaths;
35752
- if (clipPaths) operation = { ...operation, value: { ...operation.value, clipPaths } };
35756
+ const { clipPaths, clipImages } = curState();
35757
+ if (clipPaths || clipImages) operation = { ...operation, value: {
35758
+ ...operation.value,
35759
+ ...clipPaths ? { clipPaths } : {},
35760
+ ...clipImages ? { clipImages } : {}
35761
+ } };
35753
35762
  operations.push(operation);
35754
35763
  switch (operation.kind) {
35755
35764
  case "path":
@@ -36013,6 +36022,18 @@ function evaluateContentStreamToDisplayList(params) {
36013
36022
  let hasTextClip = false;
36014
36023
  let activeTm = [1, 0, 0, 1, 0, 0];
36015
36024
  let activeTlm = [1, 0, 0, 1, 0, 0];
36025
+ const paintImage = (image, patternMask, resources, activeFonts, depth) => {
36026
+ if (!patternMask) {
36027
+ emit({ kind: "image", value: image });
36028
+ return;
36029
+ }
36030
+ const st = curState();
36031
+ stateStack.push({ ...st, clipImages: [...st.clipImages ?? [], image] });
36032
+ walkNodes([{ kind: "path-op", paint: "f", segments: [
36033
+ { kind: "rect", x: 0, y: 0, width: 1, height: 1 }
36034
+ ] }], void 0, void 0, resources, activeFonts, depth);
36035
+ stateStack.pop();
36036
+ };
36016
36037
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
36017
36038
  for (const node of nodes) {
36018
36039
  switch (node.kind) {
@@ -36196,7 +36217,8 @@ function evaluateContentStreamToDisplayList(params) {
36196
36217
  st.fillAlpha,
36197
36218
  "PatternShading_" + st.fillPatternName,
36198
36219
  patClip,
36199
- shading?.kind === "stream" ? shading : void 0
36220
+ shading?.kind === "stream" ? shading : void 0,
36221
+ st.blendMode
36200
36222
  );
36201
36223
  if (shImg) {
36202
36224
  emit({ kind: "image", value: shImg });
@@ -36305,18 +36327,20 @@ function evaluateContentStreamToDisplayList(params) {
36305
36327
  const subNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "Subtype"));
36306
36328
  const sub = subNode?.kind === "name" ? subNode.decoded : "";
36307
36329
  if (sub === "Image") {
36330
+ const maskNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "ImageMask"));
36331
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36308
36332
  const decoded = decodeXObjectImageToRgba(
36309
36333
  params.cosDoc,
36310
36334
  xobjNode,
36311
36335
  activeResources,
36312
- {
36336
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36313
36337
  r: st.fillColor.r,
36314
36338
  g: st.fillColor.g,
36315
36339
  b: st.fillColor.b,
36316
36340
  alpha: st.fillAlpha
36317
36341
  }
36318
36342
  );
36319
- emit({ kind: "image", value: {
36343
+ paintImage({
36320
36344
  name: node.name,
36321
36345
  matrix: [...st.ctm],
36322
36346
  width: decoded.width,
@@ -36326,7 +36350,7 @@ function evaluateContentStreamToDisplayList(params) {
36326
36350
  decodedRgba: decoded.rgba,
36327
36351
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36328
36352
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36329
- } });
36353
+ }, patternMask, activeResources, activeFonts, depth);
36330
36354
  } else if (sub === "Form" && depth < 8) {
36331
36355
  const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36332
36356
  const formNodes = parseContentStream(formStreamBytes);
@@ -36382,19 +36406,22 @@ function evaluateContentStreamToDisplayList(params) {
36382
36406
  }
36383
36407
  case "inline-image": {
36384
36408
  const st = curState();
36409
+ const maskEntry = dictGet(node.dict, "ImageMask") ?? dictGet(node.dict, "IM");
36410
+ const maskNode = params.cosDoc ? params.cosDoc.resolve(maskEntry) : maskEntry;
36411
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36385
36412
  const decoded = decodeInlineImageNodeToRgba(
36386
36413
  params.cosDoc,
36387
36414
  node.dict,
36388
36415
  node.data,
36389
36416
  activeResources,
36390
- {
36417
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36391
36418
  r: st.fillColor.r,
36392
36419
  g: st.fillColor.g,
36393
36420
  b: st.fillColor.b,
36394
36421
  alpha: st.fillAlpha
36395
36422
  }
36396
36423
  );
36397
- emit({ kind: "image", value: {
36424
+ paintImage({
36398
36425
  name: "InlineImage",
36399
36426
  matrix: [...st.ctm],
36400
36427
  width: decoded.width,
@@ -36404,7 +36431,7 @@ function evaluateContentStreamToDisplayList(params) {
36404
36431
  decodedRgba: decoded.rgba,
36405
36432
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36406
36433
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36407
- } });
36434
+ }, patternMask, activeResources, activeFonts, depth);
36408
36435
  break;
36409
36436
  }
36410
36437
  case "text-object": {
@@ -40150,6 +40177,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40150
40177
  const aaVec = options.antialiasVector !== false;
40151
40178
  const aaTxt = options.antialiasText !== false;
40152
40179
  const clipMasks = /* @__PURE__ */ new Map();
40180
+ const imageClipMasks = /* @__PURE__ */ new Map();
40153
40181
  for (const original of paintOperations(displayList)) {
40154
40182
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40155
40183
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
@@ -40164,6 +40192,31 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40164
40192
  }
40165
40193
  clipMasks.set(clips, clipMask);
40166
40194
  }
40195
+ const imageClips = original.value.clipImages;
40196
+ if (imageClips) {
40197
+ let imageMask = imageClipMasks.get(imageClips);
40198
+ if (!imageMask) {
40199
+ imageMask = new Uint8Array(width * height * 4).fill(255);
40200
+ for (const image of imageClips) {
40201
+ const layer = renderDisplayListToBitmap({
40202
+ ...displayList,
40203
+ rotation: 0,
40204
+ paths: [],
40205
+ glyphs: [],
40206
+ images: [image],
40207
+ operations: [{ kind: "image", value: image }]
40208
+ }, { scale, transparent: true }).data;
40209
+ for (let i = 3; i < layer.length; i += 4) imageMask[i] = Math.round(imageMask[i] * layer[i] / 255);
40210
+ }
40211
+ imageClipMasks.set(imageClips, imageMask);
40212
+ }
40213
+ if (clipMask) {
40214
+ clipMask = clipMask.slice();
40215
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * imageMask[i] / 255);
40216
+ } else {
40217
+ clipMask = imageMask;
40218
+ }
40219
+ }
40167
40220
  if (operation.kind === "path") {
40168
40221
  const path = operation.value;
40169
40222
  if (path.fillColor) {
@@ -40312,6 +40365,15 @@ function escapeXmlText(str) {
40312
40365
  }
40313
40366
  return encodeToXmlString(valid);
40314
40367
  }
40368
+ function svgImage(image, pageHeight) {
40369
+ if (!image.decodedRgba) return "";
40370
+ const png = encodeRgbaToPng(image.width, image.height, image.decodedRgba);
40371
+ const chunks = [];
40372
+ for (let offset = 0; offset < png.length; offset += 8192)
40373
+ chunks.push(String.fromCharCode(...png.subarray(offset, offset + 8192)));
40374
+ const [a, b, c, d, e, f] = image.matrix;
40375
+ 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(""))}"/>`;
40376
+ }
40315
40377
  function svgPathData(segments, height) {
40316
40378
  const dParts = [];
40317
40379
  for (const seg of segments) {
@@ -40360,11 +40422,16 @@ function renderDisplayListToSvg(displayList, options = {}) {
40360
40422
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40361
40423
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40362
40424
  const clips = original.value.clipPaths ?? [];
40425
+ const imageClips = original.value.clipImages ?? [];
40363
40426
  for (const segments of clips) {
40364
40427
  const id = `text-clip-${clipId++}`;
40365
40428
  const path = `<path d="${svgPathData(segments, displayList.height)}"/>`;
40366
40429
  parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40367
40430
  }
40431
+ for (const image of imageClips) {
40432
+ const id = `image-clip-${clipId++}`;
40433
+ 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})">`);
40434
+ }
40368
40435
  if (operation.kind === "path") {
40369
40436
  const p = operation.value;
40370
40437
  const pathData = svgPathData(p.segments, displayList.height);
@@ -40384,24 +40451,9 @@ function renderDisplayListToSvg(displayList, options = {}) {
40384
40451
  parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40385
40452
  }
40386
40453
  } else if (operation.kind === "image") {
40387
- const img = operation.value;
40388
- if (!img.decodedRgba) {
40389
- for (let i = 0; i < clips.length; i++) parts.push("</g>");
40390
- continue;
40391
- }
40392
- const pngBytes = encodeRgbaToPng(img.width, img.height, img.decodedRgba);
40393
- const chunks = [];
40394
- for (let offset = 0; offset < pngBytes.length; offset += 8192)
40395
- chunks.push(String.fromCharCode(...pngBytes.subarray(offset, offset + 8192)));
40396
- const b64 = btoa(chunks.join(""));
40397
- const [a, b, c, d, e, f] = img.matrix;
40398
- const svgTx = e + c;
40399
- const svgTy = displayList.height - f - d;
40400
- parts.push(
40401
- ` <image width="1" height="1" preserveAspectRatio="none" transform="matrix(${a} ${-b} ${-c} ${d} ${svgTx} ${svgTy})" href="data:image/png;base64,${b64}"/>`
40402
- );
40454
+ parts.push(` ${svgImage(operation.value, displayList.height)}`);
40403
40455
  }
40404
- for (let i = 0; i < clips.length; i++) parts.push("</g>");
40456
+ for (let i = 0; i < clips.length + imageClips.length; i++) parts.push("</g>");
40405
40457
  }
40406
40458
  if (displayList.rotation) parts.push("</g>");
40407
40459
  parts.push("</svg>\n");