@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
  }
@@ -34624,7 +34635,11 @@ function resolvePageFonts(doc, resourcesDict) {
34624
34635
  let cmap;
34625
34636
  const toUniNode = doc.resolve(dictGet(fObj, "ToUnicode"));
34626
34637
  if (toUniNode?.kind === "stream") {
34627
- cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34638
+ try {
34639
+ cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34640
+ } catch (error) {
34641
+ if (error instanceof PdfError && error.code === "E_LIMIT") throw error;
34642
+ }
34628
34643
  }
34629
34644
  const encNode = doc.resolve(dictGet(fObj, "Encoding"));
34630
34645
  if (encNode?.kind === "dict") {
@@ -34640,7 +34655,7 @@ function resolvePageFonts(doc, resourcesDict) {
34640
34655
  const glyphNames = buildFontEncodingGlyphNamesMap(encNode);
34641
34656
  const widths = /* @__PURE__ */ new Map();
34642
34657
  let defaultWidth = 556;
34643
- const isTwoByteCid = subtype === "Type0" || Boolean(cmap?.isTwoByte);
34658
+ const isTwoByteCid = subtype === "Type0";
34644
34659
  let fontMatrix;
34645
34660
  let charProcs;
34646
34661
  let fontResources;
@@ -35748,8 +35763,12 @@ function evaluateContentStreamToDisplayList(params) {
35748
35763
  const images = [];
35749
35764
  const operations = [];
35750
35765
  const emit = (operation) => {
35751
- const clipPaths = curState().clipPaths;
35752
- if (clipPaths) operation = { ...operation, value: { ...operation.value, clipPaths } };
35766
+ const { clipPaths, clipImages } = curState();
35767
+ if (clipPaths || clipImages) operation = { ...operation, value: {
35768
+ ...operation.value,
35769
+ ...clipPaths ? { clipPaths } : {},
35770
+ ...clipImages ? { clipImages } : {}
35771
+ } };
35753
35772
  operations.push(operation);
35754
35773
  switch (operation.kind) {
35755
35774
  case "path":
@@ -36013,6 +36032,18 @@ function evaluateContentStreamToDisplayList(params) {
36013
36032
  let hasTextClip = false;
36014
36033
  let activeTm = [1, 0, 0, 1, 0, 0];
36015
36034
  let activeTlm = [1, 0, 0, 1, 0, 0];
36035
+ const paintImage = (image, patternMask, resources, activeFonts, depth) => {
36036
+ if (!patternMask) {
36037
+ emit({ kind: "image", value: image });
36038
+ return;
36039
+ }
36040
+ const st = curState();
36041
+ stateStack.push({ ...st, clipImages: [...st.clipImages ?? [], image] });
36042
+ walkNodes([{ kind: "path-op", paint: "f", segments: [
36043
+ { kind: "rect", x: 0, y: 0, width: 1, height: 1 }
36044
+ ] }], void 0, void 0, resources, activeFonts, depth);
36045
+ stateStack.pop();
36046
+ };
36016
36047
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
36017
36048
  for (const node of nodes) {
36018
36049
  switch (node.kind) {
@@ -36196,7 +36227,8 @@ function evaluateContentStreamToDisplayList(params) {
36196
36227
  st.fillAlpha,
36197
36228
  "PatternShading_" + st.fillPatternName,
36198
36229
  patClip,
36199
- shading?.kind === "stream" ? shading : void 0
36230
+ shading?.kind === "stream" ? shading : void 0,
36231
+ st.blendMode
36200
36232
  );
36201
36233
  if (shImg) {
36202
36234
  emit({ kind: "image", value: shImg });
@@ -36305,18 +36337,20 @@ function evaluateContentStreamToDisplayList(params) {
36305
36337
  const subNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "Subtype"));
36306
36338
  const sub = subNode?.kind === "name" ? subNode.decoded : "";
36307
36339
  if (sub === "Image") {
36340
+ const maskNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "ImageMask"));
36341
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36308
36342
  const decoded = decodeXObjectImageToRgba(
36309
36343
  params.cosDoc,
36310
36344
  xobjNode,
36311
36345
  activeResources,
36312
- {
36346
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36313
36347
  r: st.fillColor.r,
36314
36348
  g: st.fillColor.g,
36315
36349
  b: st.fillColor.b,
36316
36350
  alpha: st.fillAlpha
36317
36351
  }
36318
36352
  );
36319
- emit({ kind: "image", value: {
36353
+ paintImage({
36320
36354
  name: node.name,
36321
36355
  matrix: [...st.ctm],
36322
36356
  width: decoded.width,
@@ -36326,7 +36360,7 @@ function evaluateContentStreamToDisplayList(params) {
36326
36360
  decodedRgba: decoded.rgba,
36327
36361
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36328
36362
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36329
- } });
36363
+ }, patternMask, activeResources, activeFonts, depth);
36330
36364
  } else if (sub === "Form" && depth < 8) {
36331
36365
  const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36332
36366
  const formNodes = parseContentStream(formStreamBytes);
@@ -36382,19 +36416,22 @@ function evaluateContentStreamToDisplayList(params) {
36382
36416
  }
36383
36417
  case "inline-image": {
36384
36418
  const st = curState();
36419
+ const maskEntry = dictGet(node.dict, "ImageMask") ?? dictGet(node.dict, "IM");
36420
+ const maskNode = params.cosDoc ? params.cosDoc.resolve(maskEntry) : maskEntry;
36421
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36385
36422
  const decoded = decodeInlineImageNodeToRgba(
36386
36423
  params.cosDoc,
36387
36424
  node.dict,
36388
36425
  node.data,
36389
36426
  activeResources,
36390
- {
36427
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36391
36428
  r: st.fillColor.r,
36392
36429
  g: st.fillColor.g,
36393
36430
  b: st.fillColor.b,
36394
36431
  alpha: st.fillAlpha
36395
36432
  }
36396
36433
  );
36397
- emit({ kind: "image", value: {
36434
+ paintImage({
36398
36435
  name: "InlineImage",
36399
36436
  matrix: [...st.ctm],
36400
36437
  width: decoded.width,
@@ -36404,7 +36441,7 @@ function evaluateContentStreamToDisplayList(params) {
36404
36441
  decodedRgba: decoded.rgba,
36405
36442
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36406
36443
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36407
- } });
36444
+ }, patternMask, activeResources, activeFonts, depth);
36408
36445
  break;
36409
36446
  }
36410
36447
  case "text-object": {
@@ -40150,6 +40187,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40150
40187
  const aaVec = options.antialiasVector !== false;
40151
40188
  const aaTxt = options.antialiasText !== false;
40152
40189
  const clipMasks = /* @__PURE__ */ new Map();
40190
+ const imageClipMasks = /* @__PURE__ */ new Map();
40153
40191
  for (const original of paintOperations(displayList)) {
40154
40192
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40155
40193
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
@@ -40164,6 +40202,31 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40164
40202
  }
40165
40203
  clipMasks.set(clips, clipMask);
40166
40204
  }
40205
+ const imageClips = original.value.clipImages;
40206
+ if (imageClips) {
40207
+ let imageMask = imageClipMasks.get(imageClips);
40208
+ if (!imageMask) {
40209
+ imageMask = new Uint8Array(width * height * 4).fill(255);
40210
+ for (const image of imageClips) {
40211
+ const layer = renderDisplayListToBitmap({
40212
+ ...displayList,
40213
+ rotation: 0,
40214
+ paths: [],
40215
+ glyphs: [],
40216
+ images: [image],
40217
+ operations: [{ kind: "image", value: image }]
40218
+ }, { scale, transparent: true }).data;
40219
+ for (let i = 3; i < layer.length; i += 4) imageMask[i] = Math.round(imageMask[i] * layer[i] / 255);
40220
+ }
40221
+ imageClipMasks.set(imageClips, imageMask);
40222
+ }
40223
+ if (clipMask) {
40224
+ clipMask = clipMask.slice();
40225
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * imageMask[i] / 255);
40226
+ } else {
40227
+ clipMask = imageMask;
40228
+ }
40229
+ }
40167
40230
  if (operation.kind === "path") {
40168
40231
  const path = operation.value;
40169
40232
  if (path.fillColor) {
@@ -40312,6 +40375,15 @@ function escapeXmlText(str) {
40312
40375
  }
40313
40376
  return encodeToXmlString(valid);
40314
40377
  }
40378
+ function svgImage(image, pageHeight) {
40379
+ if (!image.decodedRgba) return "";
40380
+ const png = encodeRgbaToPng(image.width, image.height, image.decodedRgba);
40381
+ const chunks = [];
40382
+ for (let offset = 0; offset < png.length; offset += 8192)
40383
+ chunks.push(String.fromCharCode(...png.subarray(offset, offset + 8192)));
40384
+ const [a, b, c, d, e, f] = image.matrix;
40385
+ 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(""))}"/>`;
40386
+ }
40315
40387
  function svgPathData(segments, height) {
40316
40388
  const dParts = [];
40317
40389
  for (const seg of segments) {
@@ -40360,11 +40432,16 @@ function renderDisplayListToSvg(displayList, options = {}) {
40360
40432
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40361
40433
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40362
40434
  const clips = original.value.clipPaths ?? [];
40435
+ const imageClips = original.value.clipImages ?? [];
40363
40436
  for (const segments of clips) {
40364
40437
  const id = `text-clip-${clipId++}`;
40365
40438
  const path = `<path d="${svgPathData(segments, displayList.height)}"/>`;
40366
40439
  parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40367
40440
  }
40441
+ for (const image of imageClips) {
40442
+ const id = `image-clip-${clipId++}`;
40443
+ 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})">`);
40444
+ }
40368
40445
  if (operation.kind === "path") {
40369
40446
  const p = operation.value;
40370
40447
  const pathData = svgPathData(p.segments, displayList.height);
@@ -40384,24 +40461,9 @@ function renderDisplayListToSvg(displayList, options = {}) {
40384
40461
  parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40385
40462
  }
40386
40463
  } 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
- );
40464
+ parts.push(` ${svgImage(operation.value, displayList.height)}`);
40403
40465
  }
40404
- for (let i = 0; i < clips.length; i++) parts.push("</g>");
40466
+ for (let i = 0; i < clips.length + imageClips.length; i++) parts.push("</g>");
40405
40467
  }
40406
40468
  if (displayList.rotation) parts.push("</g>");
40407
40469
  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
  }
@@ -34775,7 +34786,11 @@ function resolvePageFonts(doc, resourcesDict) {
34775
34786
  let cmap;
34776
34787
  const toUniNode = doc.resolve(dictGet(fObj, "ToUnicode"));
34777
34788
  if (toUniNode?.kind === "stream") {
34778
- cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34789
+ try {
34790
+ cmap = parseToUnicodeCMap(doc.decodeStream(toUniNode));
34791
+ } catch (error) {
34792
+ if (error instanceof PdfError && error.code === "E_LIMIT") throw error;
34793
+ }
34779
34794
  }
34780
34795
  const encNode = doc.resolve(dictGet(fObj, "Encoding"));
34781
34796
  if (encNode?.kind === "dict") {
@@ -34791,7 +34806,7 @@ function resolvePageFonts(doc, resourcesDict) {
34791
34806
  const glyphNames = buildFontEncodingGlyphNamesMap(encNode);
34792
34807
  const widths = /* @__PURE__ */ new Map();
34793
34808
  let defaultWidth = 556;
34794
- const isTwoByteCid = subtype === "Type0" || Boolean(cmap?.isTwoByte);
34809
+ const isTwoByteCid = subtype === "Type0";
34795
34810
  let fontMatrix;
34796
34811
  let charProcs;
34797
34812
  let fontResources;
@@ -35899,8 +35914,12 @@ function evaluateContentStreamToDisplayList(params) {
35899
35914
  const images = [];
35900
35915
  const operations = [];
35901
35916
  const emit = (operation) => {
35902
- const clipPaths = curState().clipPaths;
35903
- if (clipPaths) operation = { ...operation, value: { ...operation.value, clipPaths } };
35917
+ const { clipPaths, clipImages } = curState();
35918
+ if (clipPaths || clipImages) operation = { ...operation, value: {
35919
+ ...operation.value,
35920
+ ...clipPaths ? { clipPaths } : {},
35921
+ ...clipImages ? { clipImages } : {}
35922
+ } };
35904
35923
  operations.push(operation);
35905
35924
  switch (operation.kind) {
35906
35925
  case "path":
@@ -36164,6 +36183,18 @@ function evaluateContentStreamToDisplayList(params) {
36164
36183
  let hasTextClip = false;
36165
36184
  let activeTm = [1, 0, 0, 1, 0, 0];
36166
36185
  let activeTlm = [1, 0, 0, 1, 0, 0];
36186
+ const paintImage = (image, patternMask, resources, activeFonts, depth) => {
36187
+ if (!patternMask) {
36188
+ emit({ kind: "image", value: image });
36189
+ return;
36190
+ }
36191
+ const st = curState();
36192
+ stateStack.push({ ...st, clipImages: [...st.clipImages ?? [], image] });
36193
+ walkNodes([{ kind: "path-op", paint: "f", segments: [
36194
+ { kind: "rect", x: 0, y: 0, width: 1, height: 1 }
36195
+ ] }], void 0, void 0, resources, activeFonts, depth);
36196
+ stateStack.pop();
36197
+ };
36167
36198
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
36168
36199
  for (const node of nodes) {
36169
36200
  switch (node.kind) {
@@ -36347,7 +36378,8 @@ function evaluateContentStreamToDisplayList(params) {
36347
36378
  st.fillAlpha,
36348
36379
  "PatternShading_" + st.fillPatternName,
36349
36380
  patClip,
36350
- shading?.kind === "stream" ? shading : void 0
36381
+ shading?.kind === "stream" ? shading : void 0,
36382
+ st.blendMode
36351
36383
  );
36352
36384
  if (shImg) {
36353
36385
  emit({ kind: "image", value: shImg });
@@ -36456,18 +36488,20 @@ function evaluateContentStreamToDisplayList(params) {
36456
36488
  const subNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "Subtype"));
36457
36489
  const sub = subNode?.kind === "name" ? subNode.decoded : "";
36458
36490
  if (sub === "Image") {
36491
+ const maskNode = params.cosDoc.resolve(dictGet(xobjNode.dict, "ImageMask"));
36492
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36459
36493
  const decoded = decodeXObjectImageToRgba(
36460
36494
  params.cosDoc,
36461
36495
  xobjNode,
36462
36496
  activeResources,
36463
- {
36497
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36464
36498
  r: st.fillColor.r,
36465
36499
  g: st.fillColor.g,
36466
36500
  b: st.fillColor.b,
36467
36501
  alpha: st.fillAlpha
36468
36502
  }
36469
36503
  );
36470
- emit({ kind: "image", value: {
36504
+ paintImage({
36471
36505
  name: node.name,
36472
36506
  matrix: [...st.ctm],
36473
36507
  width: decoded.width,
@@ -36477,7 +36511,7 @@ function evaluateContentStreamToDisplayList(params) {
36477
36511
  decodedRgba: decoded.rgba,
36478
36512
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36479
36513
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36480
- } });
36514
+ }, patternMask, activeResources, activeFonts, depth);
36481
36515
  } else if (sub === "Form" && depth < 8) {
36482
36516
  const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36483
36517
  const formNodes = parseContentStream(formStreamBytes);
@@ -36533,19 +36567,22 @@ function evaluateContentStreamToDisplayList(params) {
36533
36567
  }
36534
36568
  case "inline-image": {
36535
36569
  const st = curState();
36570
+ const maskEntry = dictGet(node.dict, "ImageMask") ?? dictGet(node.dict, "IM");
36571
+ const maskNode = params.cosDoc ? params.cosDoc.resolve(maskEntry) : maskEntry;
36572
+ const patternMask = !!st.fillPatternName && maskNode?.kind === "boolean" && maskNode.value;
36536
36573
  const decoded = decodeInlineImageNodeToRgba(
36537
36574
  params.cosDoc,
36538
36575
  node.dict,
36539
36576
  node.data,
36540
36577
  activeResources,
36541
- {
36578
+ patternMask ? { r: 1, g: 1, b: 1, alpha: 1 } : {
36542
36579
  r: st.fillColor.r,
36543
36580
  g: st.fillColor.g,
36544
36581
  b: st.fillColor.b,
36545
36582
  alpha: st.fillAlpha
36546
36583
  }
36547
36584
  );
36548
- emit({ kind: "image", value: {
36585
+ paintImage({
36549
36586
  name: "InlineImage",
36550
36587
  matrix: [...st.ctm],
36551
36588
  width: decoded.width,
@@ -36555,7 +36592,7 @@ function evaluateContentStreamToDisplayList(params) {
36555
36592
  decodedRgba: decoded.rgba,
36556
36593
  ...st.blendMode && st.blendMode !== "Normal" ? { blendMode: st.blendMode } : {},
36557
36594
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36558
- } });
36595
+ }, patternMask, activeResources, activeFonts, depth);
36559
36596
  break;
36560
36597
  }
36561
36598
  case "text-object": {
@@ -40132,6 +40169,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40132
40169
  const aaVec = options.antialiasVector !== false;
40133
40170
  const aaTxt = options.antialiasText !== false;
40134
40171
  const clipMasks = /* @__PURE__ */ new Map();
40172
+ const imageClipMasks = /* @__PURE__ */ new Map();
40135
40173
  for (const original of paintOperations(displayList)) {
40136
40174
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40137
40175
  const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
@@ -40146,6 +40184,31 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40146
40184
  }
40147
40185
  clipMasks.set(clips, clipMask);
40148
40186
  }
40187
+ const imageClips = original.value.clipImages;
40188
+ if (imageClips) {
40189
+ let imageMask = imageClipMasks.get(imageClips);
40190
+ if (!imageMask) {
40191
+ imageMask = new Uint8Array(width * height * 4).fill(255);
40192
+ for (const image of imageClips) {
40193
+ const layer = renderDisplayListToBitmap({
40194
+ ...displayList,
40195
+ rotation: 0,
40196
+ paths: [],
40197
+ glyphs: [],
40198
+ images: [image],
40199
+ operations: [{ kind: "image", value: image }]
40200
+ }, { scale, transparent: true }).data;
40201
+ for (let i = 3; i < layer.length; i += 4) imageMask[i] = Math.round(imageMask[i] * layer[i] / 255);
40202
+ }
40203
+ imageClipMasks.set(imageClips, imageMask);
40204
+ }
40205
+ if (clipMask) {
40206
+ clipMask = clipMask.slice();
40207
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * imageMask[i] / 255);
40208
+ } else {
40209
+ clipMask = imageMask;
40210
+ }
40211
+ }
40149
40212
  if (operation.kind === "path") {
40150
40213
  const path = operation.value;
40151
40214
  if (path.fillColor) {