@poe-platform/safe-bash 0.1.761 → 0.1.763

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/image-ast/index.browser.js +255 -62
  2. package/dist/image-ast/index.js +255 -62
  3. package/dist/pdf-ast/ast.d.ts +23 -0
  4. package/dist/pdf-ast/index.js +344 -98
  5. package/dist/safe-bash/command-chunks/{chunk-6VX5ZQL5.js → chunk-4XHONGIU.js} +2 -2
  6. package/dist/safe-bash/command-chunks/{chunk-OSMLVM7P.js → chunk-S3G2B4OX.js} +258 -62
  7. package/dist/safe-bash/command-chunks/{chunk-GR725WRX.js → chunk-S5EX6UP5.js} +1 -1
  8. package/dist/safe-bash/commands/csvcut/index.d.ts +1 -1
  9. package/dist/safe-bash/commands/csvcut/index.js +3 -1
  10. package/dist/safe-bash/commands/csvgrep/index.d.ts +1 -1
  11. package/dist/safe-bash/commands/csvgrep/index.js +3 -1
  12. package/dist/safe-bash/core.browser.js +8 -6
  13. package/dist/safe-bash/shell/runtime.js +5 -5
  14. package/dist/safe-bash-checksum-engine/index.d.ts +1 -1
  15. package/dist/safe-bash-checksum-engine/index.js +5 -1
  16. package/dist/safe-bash-command-ffmpeg/index.js +7942 -7853
  17. package/dist/safe-bash-command-gh/index.js +174 -105
  18. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  19. package/dist/safe-bash-command-pandoc/command.js +3 -3
  20. package/dist/safe-bash-command-pandoc/index.js +3 -3
  21. package/dist/safe-bash-command-pdfimages/index.js +255 -62
  22. package/dist/safe-bash-command-pdfinfo/index.js +342 -98
  23. package/dist/safe-bash-command-pdftk/index.js +255 -62
  24. package/dist/safe-bash-command-pdftoppm/index.js +342 -98
  25. package/dist/safe-bash-command-pdftotext/index.js +255 -62
  26. package/dist/safe-bash-command-qpdf/index.js +255 -62
  27. package/dist/safe-bash-command-sips/index.js +2 -2
  28. package/dist/safe-bash-command-soffice/index.js +1 -1
  29. package/dist/safe-bash-command-ssconvert/index.js +318 -65
  30. package/dist/safe-bash-command-wkhtmltopdf/index.js +255 -62
  31. package/package.json +2 -2
  32. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +23 -0
@@ -36107,14 +36107,18 @@ function evaluateContentStreamToDisplayList(params) {
36107
36107
  const paths = [];
36108
36108
  const images = [];
36109
36109
  const operations = [];
36110
+ let capturedOperations;
36111
+ let insideSoftMask = false;
36110
36112
  const emit = (operation) => {
36111
- const { clipPaths, clipImages } = curState();
36112
- if (clipPaths || clipImages) operation = { ...operation, value: {
36113
+ const { clipPaths, clipImages, softMask } = curState();
36114
+ if (clipPaths || clipImages || softMask) operation = { ...operation, value: {
36113
36115
  ...operation.value,
36114
36116
  ...clipPaths ? { clipPaths } : {},
36115
- ...clipImages ? { clipImages } : {}
36117
+ ...clipImages ? { clipImages } : {},
36118
+ ...softMask ? { softMask } : {}
36116
36119
  } };
36117
- operations.push(operation);
36120
+ (capturedOperations ?? operations).push(operation);
36121
+ if (insideSoftMask) return;
36118
36122
  switch (operation.kind) {
36119
36123
  case "path":
36120
36124
  paths.push(operation.value);
@@ -36220,7 +36224,7 @@ function evaluateContentStreamToDisplayList(params) {
36220
36224
  );
36221
36225
  return { r: kClamp(r), g: kClamp(g), b: kClamp(b) };
36222
36226
  };
36223
- const applyStateOperator = (st, operator, ops, activeResources) => {
36227
+ const applyStateOperator = (st, operator, ops, activeResources, activeFonts, depth) => {
36224
36228
  const num = (i, fb = 0) => ops[i]?.kind === "number" ? ops[i].value : fb;
36225
36229
  if (operator === "cm") {
36226
36230
  const m = [num(0, 1), num(1, 0), num(2, 0), num(3, 1), num(4, 0), num(5, 0)];
@@ -36303,6 +36307,46 @@ function evaluateContentStreamToDisplayList(params) {
36303
36307
  const extDict = params.cosDoc.resolveDict(dictGet(activeResources, "ExtGState"));
36304
36308
  const gsDict = extDict ? params.cosDoc.resolveDict(dictGet(extDict, ops[0].decoded)) : void 0;
36305
36309
  if (gsDict) {
36310
+ const mask = params.cosDoc.resolve(dictGet(gsDict, "SMask"));
36311
+ if (mask?.kind === "name" && mask.decoded === "None") {
36312
+ st.softMask = void 0;
36313
+ } else if (mask?.kind === "dict") {
36314
+ const subtype = params.cosDoc.resolve(dictGet(mask, "S"));
36315
+ const form = params.cosDoc.resolve(dictGet(mask, "G"));
36316
+ if (form?.kind === "stream" && subtype?.kind === "name" && (subtype.decoded === "Alpha" || subtype.decoded === "Luminosity")) {
36317
+ if (depth >= 8) throw new PdfError("E_LIMIT", "Soft-mask nesting exceeds the form depth limit");
36318
+ const parentOperations = capturedOperations;
36319
+ const parentInsideSoftMask = insideSoftMask;
36320
+ const savedTextState = { pendingTextClip, hasTextClip, activeTm, activeTlm };
36321
+ const captured = [];
36322
+ capturedOperations = captured;
36323
+ insideSoftMask = true;
36324
+ const maskState = { ...st, softMask: void 0, fillAlpha: 1, strokeAlpha: 1, blendMode: "Normal" };
36325
+ delete maskState.clipPaths;
36326
+ delete maskState.clipImages;
36327
+ delete maskState.clipRect;
36328
+ stateStack.push(maskState);
36329
+ try {
36330
+ paintForm(form, activeResources, activeFonts, depth, void 0, void 0, true);
36331
+ } finally {
36332
+ stateStack.pop();
36333
+ capturedOperations = parentOperations;
36334
+ insideSoftMask = parentInsideSoftMask;
36335
+ ({ pendingTextClip, hasTextClip, activeTm, activeTlm } = savedTextState);
36336
+ }
36337
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
36338
+ const colorSpace = group ? dictGet(group, "CS") : void 0;
36339
+ const bc = params.cosDoc.resolveArray(dictGet(mask, "BC"));
36340
+ const components = bc?.items.map((item) => {
36341
+ const value = params.cosDoc.resolve(item);
36342
+ return value?.kind === "number" ? value.value : 0;
36343
+ });
36344
+ const [r, g, b] = components ? convertColorSpaceComponentsToRgb(params.cosDoc, colorSpace, "DeviceRGB", components, activeResources) : [0, 0, 0];
36345
+ const transfer = params.cosDoc.resolve(dictGet(mask, "TR"));
36346
+ const transferMap = transfer?.kind === "dict" || transfer?.kind === "stream" ? Uint8Array.from({ length: 256 }, (_, i) => Math.floor(kClamp(Math.fround(evalShadingFunctionToComponents(params.cosDoc, transfer, Math.fround(i / 255))[0] ?? 0)) * 255)) : void 0;
36347
+ st.softMask = { subtype: subtype.decoded, operations: captured, backdrop: { r, g, b }, transferMap };
36348
+ }
36349
+ }
36306
36350
  const bmNode = params.cosDoc.resolve(dictGet(gsDict, "BM"));
36307
36351
  if (bmNode?.kind === "name") {
36308
36352
  st.blendMode = bmNode.decoded === "Compatible" ? "Normal" : bmNode.decoded;
@@ -36389,6 +36433,84 @@ function evaluateContentStreamToDisplayList(params) {
36389
36433
  ] }], void 0, void 0, resources, activeFonts, depth);
36390
36434
  stateStack.pop();
36391
36435
  };
36436
+ const paintForm = (form, activeResources, activeFonts, depth, mcid, actualText, maskGroup = false) => {
36437
+ const st = curState();
36438
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
36439
+ const groupType = group ? params.cosDoc.resolve(dictGet(group, "S")) : void 0;
36440
+ const isolated = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
36441
+ const isolate = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && isolated?.kind === "boolean" && isolated.value;
36442
+ const formStreamBytes = params.cosDoc.decodeStream(form);
36443
+ const formNodes = parseContentStream(formStreamBytes);
36444
+ const formResDict = params.cosDoc.resolveDict(dictGet(form.dict, "Resources")) ?? activeResources;
36445
+ const formFonts = new Map(activeFonts);
36446
+ for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
36447
+ formFonts.set(k, v);
36448
+ }
36449
+ let nextCtm = [...st.ctm];
36450
+ const matArr = params.cosDoc.resolveArray(dictGet(form.dict, "Matrix"));
36451
+ if (matArr && matArr.items.length >= 6) {
36452
+ const mn = (idx, fb = 0) => {
36453
+ const resolved = params.cosDoc.resolve(matArr.items[idx]);
36454
+ return resolved?.kind === "number" ? resolved.value : fb;
36455
+ };
36456
+ const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
36457
+ nextCtm = multiplyMatrices(formMat, nextCtm);
36458
+ }
36459
+ let nextClip = !isolate && st.clipRect ? [...st.clipRect] : void 0;
36460
+ let nextClipPaths = isolate ? void 0 : st.clipPaths;
36461
+ const bboxArr = params.cosDoc.resolveArray(dictGet(form.dict, "BBox"));
36462
+ if (bboxArr && bboxArr.items.length >= 4) {
36463
+ const bn = (idx, fb = 0) => {
36464
+ const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
36465
+ return resolved?.kind === "number" ? resolved.value : fb;
36466
+ };
36467
+ const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
36468
+ const pts = [
36469
+ transformPoint(nextCtm, bx0, by0),
36470
+ transformPoint(nextCtm, bx1, by0),
36471
+ transformPoint(nextCtm, bx1, by1),
36472
+ transformPoint(nextCtm, bx0, by1)
36473
+ ];
36474
+ nextClipPaths = [...nextClipPaths ?? [], [
36475
+ ...pts.map(([x, y], index) => ({ kind: index === 0 ? "move" : "line", x, y })),
36476
+ { kind: "close" }
36477
+ ]];
36478
+ const fMinX = Math.min(...pts.map((p) => p[0]));
36479
+ const fMinY = Math.min(...pts.map((p) => p[1]));
36480
+ const fMaxX = Math.max(...pts.map((p) => p[0]));
36481
+ const fMaxY = Math.max(...pts.map((p) => p[1]));
36482
+ if (fMaxX > fMinX && fMaxY > fMinY) {
36483
+ nextClip = nextClip ? [
36484
+ Math.max(nextClip[0], fMinX),
36485
+ Math.max(nextClip[1], fMinY),
36486
+ Math.min(nextClip[2], fMaxX),
36487
+ Math.min(nextClip[3], fMaxY)
36488
+ ] : [fMinX, fMinY, fMaxX, fMaxY];
36489
+ }
36490
+ }
36491
+ const parentOperations = capturedOperations;
36492
+ const children = [];
36493
+ const nextState = { ...st, ctm: nextCtm };
36494
+ if (isolate) {
36495
+ capturedOperations = children;
36496
+ nextState.fillAlpha = nextState.strokeAlpha = 1;
36497
+ nextState.blendMode = "Normal";
36498
+ nextState.softMask = void 0;
36499
+ delete nextState.clipImages;
36500
+ delete nextState.clipPaths;
36501
+ delete nextState.clipRect;
36502
+ }
36503
+ if (nextClip) nextState.clipRect = nextClip;
36504
+ if (nextClipPaths) nextState.clipPaths = nextClipPaths;
36505
+ stateStack.push(nextState);
36506
+ try {
36507
+ walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
36508
+ } finally {
36509
+ stateStack.pop();
36510
+ capturedOperations = parentOperations;
36511
+ }
36512
+ if (isolate) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
36513
+ };
36392
36514
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
36393
36515
  for (const node of nodes) {
36394
36516
  switch (node.kind) {
@@ -36433,7 +36555,7 @@ function evaluateContentStreamToDisplayList(params) {
36433
36555
  break;
36434
36556
  }
36435
36557
  case "state-op": {
36436
- applyStateOperator(curState(), node.operator, node.operands, activeResources);
36558
+ applyStateOperator(curState(), node.operator, node.operands, activeResources, activeFonts, depth);
36437
36559
  break;
36438
36560
  }
36439
36561
  case "path-op": {
@@ -36719,53 +36841,7 @@ function evaluateContentStreamToDisplayList(params) {
36719
36841
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36720
36842
  }, patternMask, activeResources, activeFonts, depth);
36721
36843
  } else if (sub === "Form" && depth < 8) {
36722
- const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36723
- const formNodes = parseContentStream(formStreamBytes);
36724
- const formResDict = params.cosDoc.resolveDict(dictGet(xobjNode.dict, "Resources")) ?? activeResources;
36725
- const formFonts = new Map(activeFonts);
36726
- for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
36727
- formFonts.set(k, v);
36728
- }
36729
- let nextCtm = [...st.ctm];
36730
- const matArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "Matrix"));
36731
- if (matArr && matArr.items.length >= 6) {
36732
- const mn = (idx, fb = 0) => {
36733
- const resolved = params.cosDoc.resolve(matArr.items[idx]);
36734
- return resolved?.kind === "number" ? resolved.value : fb;
36735
- };
36736
- const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
36737
- nextCtm = multiplyMatrices(formMat, nextCtm);
36738
- }
36739
- let nextClip = st.clipRect ? [...st.clipRect] : void 0;
36740
- const bboxArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "BBox"));
36741
- if (bboxArr && bboxArr.items.length >= 4) {
36742
- const bn = (idx, fb = 0) => {
36743
- const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
36744
- return resolved?.kind === "number" ? resolved.value : fb;
36745
- };
36746
- const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
36747
- const pts = [
36748
- transformPoint(nextCtm, bx0, by0),
36749
- transformPoint(nextCtm, bx1, by0),
36750
- transformPoint(nextCtm, bx0, by1),
36751
- transformPoint(nextCtm, bx1, by1)
36752
- ];
36753
- const fMinX = Math.min(...pts.map((p) => p[0]));
36754
- const fMinY = Math.min(...pts.map((p) => p[1]));
36755
- const fMaxX = Math.max(...pts.map((p) => p[0]));
36756
- const fMaxY = Math.max(...pts.map((p) => p[1]));
36757
- if (fMaxX > fMinX && fMaxY > fMinY) {
36758
- nextClip = nextClip ? [
36759
- Math.max(nextClip[0], fMinX),
36760
- Math.max(nextClip[1], fMinY),
36761
- Math.min(nextClip[2], fMaxX),
36762
- Math.min(nextClip[3], fMaxY)
36763
- ] : [fMinX, fMinY, fMaxX, fMaxY];
36764
- }
36765
- }
36766
- stateStack.push({ ...st, ctm: nextCtm, ...nextClip ? { clipRect: nextClip } : {} });
36767
- walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
36768
- if (stateStack.length > 1) stateStack.pop();
36844
+ paintForm(xobjNode, activeResources, activeFonts, depth, mcid, actualText);
36769
36845
  }
36770
36846
  }
36771
36847
  }
@@ -36984,7 +37060,7 @@ function evaluateContentStreamToDisplayList(params) {
36984
37060
  st.textRenderMode = cmd.mode;
36985
37061
  break;
36986
37062
  case "state-op":
36987
- applyStateOperator(st, cmd.operator, cmd.operands, activeResources);
37063
+ applyStateOperator(st, cmd.operator, cmd.operands, activeResources, activeFonts, depth);
36988
37064
  break;
36989
37065
  case "show-text":
36990
37066
  emitTokenBytes(cmd.token.bytes);
@@ -39247,6 +39323,47 @@ function flattenCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
39247
39323
  points.push([x4, y4]);
39248
39324
  return points;
39249
39325
  }
39326
+ function sampleImageLinear(image, x, y, out) {
39327
+ x = Math.max(0, Math.min(image.width - 1, x));
39328
+ y = Math.max(0, Math.min(image.height - 1, y));
39329
+ const x0 = Math.floor(x), y0 = Math.floor(y);
39330
+ const fx = x - x0, fy = y - y0;
39331
+ out.fill(0);
39332
+ for (let j = 0; j < 2; j++) {
39333
+ for (let i = 0; i < 2; i++) {
39334
+ const offset = (Math.min(image.height - 1, y0 + j) * image.width + Math.min(image.width - 1, x0 + i)) * 4;
39335
+ const alpha = image.data[offset + 3] * (i ? fx : 1 - fx) * (j ? fy : 1 - fy);
39336
+ out[0] = out[0] + image.data[offset] * alpha;
39337
+ out[1] = out[1] + image.data[offset + 1] * alpha;
39338
+ out[2] = out[2] + image.data[offset + 2] * alpha;
39339
+ out[3] = out[3] + alpha;
39340
+ }
39341
+ }
39342
+ if (out[3] > 0) {
39343
+ out[0] = out[0] / out[3];
39344
+ out[1] = out[1] / out[3];
39345
+ out[2] = out[2] / out[3];
39346
+ }
39347
+ }
39348
+ function downscaleImage(image, widthScale, heightScale) {
39349
+ const sample = new Float64Array(4);
39350
+ while (widthScale > 2 && image.width > 1 || heightScale > 2 && image.height > 1) {
39351
+ const width = widthScale > 2 ? Math.ceil(image.width / 2) : image.width;
39352
+ const height = heightScale > 2 ? Math.ceil(image.height / 2) : image.height;
39353
+ const data = new Uint8Array(width * height * 4);
39354
+ for (let y = 0; y < height; y++) {
39355
+ for (let x = 0; x < width; x++) {
39356
+ sampleImageLinear(image, (x + 0.5) * image.width / width - 0.5, (y + 0.5) * image.height / height - 0.5, sample);
39357
+ const offset = (y * width + x) * 4;
39358
+ for (let c = 0; c < 4; c++) data[offset + c] = Math.round(sample[c]);
39359
+ }
39360
+ }
39361
+ widthScale /= image.width / width;
39362
+ heightScale /= image.height / height;
39363
+ image = { width, height, data };
39364
+ }
39365
+ return image;
39366
+ }
39250
39367
  function encodePng(bitmap) {
39251
39368
  return encodeRgbaToPng(bitmap.width, bitmap.height, bitmap.data);
39252
39369
  }
@@ -40552,6 +40669,30 @@ function paintOperations(displayList) {
40552
40669
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
40553
40670
  ];
40554
40671
  }
40672
+ function renderSoftMask(mask, displayList, scale) {
40673
+ const bitmap = renderDisplayListToBitmap({
40674
+ ...displayList,
40675
+ rotation: 0,
40676
+ glyphs: [],
40677
+ paths: [],
40678
+ images: [],
40679
+ operations: mask.operations
40680
+ }, { scale, transparent: true });
40681
+ const { data } = bitmap;
40682
+ for (let i = 0; i < data.length; i += 4) {
40683
+ let value = data[i + 3];
40684
+ if (mask.subtype === "Luminosity") {
40685
+ const alpha = value / 255;
40686
+ const r = Math.round(data[i] * alpha + mask.backdrop.r * 255 * (1 - alpha));
40687
+ const g = Math.round(data[i + 1] * alpha + mask.backdrop.g * 255 * (1 - alpha));
40688
+ const b = Math.round(data[i + 2] * alpha + mask.backdrop.b * 255 * (1 - alpha));
40689
+ value = Math.round(pdfLum(r, g, b));
40690
+ }
40691
+ data[i] = data[i + 1] = data[i + 2] = 0;
40692
+ data[i + 3] = mask.transferMap?.[value] ?? value;
40693
+ }
40694
+ return bitmap;
40695
+ }
40555
40696
  function renderDisplayListToBitmap(displayList, options = {}) {
40556
40697
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
40557
40698
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -40575,10 +40716,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40575
40716
  const aaTxt = options.antialiasText !== false;
40576
40717
  let cachedClips;
40577
40718
  let cachedClipMask;
40719
+ let cachedSoftMask;
40720
+ let cachedSoftMaskPixels;
40578
40721
  const imageClipMasks = /* @__PURE__ */ new Map();
40579
40722
  for (const original of paintOperations(displayList)) {
40580
40723
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40581
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40724
+ let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40725
+ if (operation.kind === "group") {
40726
+ const group = operation.value;
40727
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
40728
+ for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
40729
+ operation = { kind: "image", value: {
40730
+ name: "TransparencyGroup",
40731
+ width: bitmap.width,
40732
+ height: bitmap.height,
40733
+ decodedRgba: bitmap.data,
40734
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
40735
+ colorSpace: "DeviceRGB",
40736
+ bitsPerComponent: 8,
40737
+ blendMode: group.blendMode,
40738
+ clipRect: group.clipRect
40739
+ } };
40740
+ }
40582
40741
  const clips = original.value.clipPaths;
40583
40742
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
40584
40743
  if (clips && !clipMask) {
@@ -40592,6 +40751,19 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40592
40751
  cachedClips = clips;
40593
40752
  cachedClipMask = clipMask;
40594
40753
  }
40754
+ const softMask = original.value.softMask;
40755
+ if (softMask) {
40756
+ if (softMask !== cachedSoftMask) {
40757
+ cachedSoftMaskPixels = renderSoftMask(softMask, displayList, scale).data;
40758
+ cachedSoftMask = softMask;
40759
+ }
40760
+ if (clipMask) {
40761
+ clipMask = clipMask.slice();
40762
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * cachedSoftMaskPixels[i] / 255);
40763
+ } else {
40764
+ clipMask = cachedSoftMaskPixels;
40765
+ }
40766
+ }
40595
40767
  const imageClips = original.value.clipImages;
40596
40768
  if (imageClips) {
40597
40769
  let imageMask = imageClipMasks.get(imageClips);
@@ -40695,6 +40867,17 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40695
40867
  const maxPx = Math.min(width - 1, clipMaxPx, Math.ceil(Math.max(...cornersPx)) - 1);
40696
40868
  const minPy = Math.max(0, clipMinPy, Math.floor(Math.min(...cornersPy)));
40697
40869
  const maxPy = Math.min(height - 1, clipMaxPy, Math.ceil(Math.max(...cornersPy)) - 1);
40870
+ if (minPx > maxPx || minPy > maxPy) continue;
40871
+ const source = downscaleImage(
40872
+ { width: img.width, height: img.height, data: img.decodedRgba },
40873
+ Math.hypot(d, c) * img.width / Math.abs(det * scale),
40874
+ Math.hypot(b, a) * img.height / Math.abs(det * scale)
40875
+ );
40876
+ const ax = a * scale / img.width, ay = b * scale / img.width;
40877
+ const bx = c * scale / img.height, by = d * scale / img.height;
40878
+ const s1 = ax * ax + ay * ay, s2 = bx * bx + by * by, cross = ax * bx + ay * by;
40879
+ const smooth = Math.fround((s1 + s2 + Math.hypot(s1 - s2, 2 * cross)) / 2) <= 1;
40880
+ const sample = new Float64Array(4);
40698
40881
  for (let py = minPy; py <= maxPy; py++) {
40699
40882
  const yPdf = displayList.height - (py + 0.5) / scale;
40700
40883
  if (img.clipRect && (yPdf < img.clipRect[1] || yPdf > img.clipRect[3])) continue;
@@ -40706,9 +40889,14 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40706
40889
  const u = (d * dxPdf - c * dyPdf) / det;
40707
40890
  const v = (-b * dxPdf + a * dyPdf) / det;
40708
40891
  if (u < 0 || u > 1 || v < 0 || v > 1) continue;
40709
- const sx = Math.min(img.width - 1, Math.max(0, Math.floor(u * img.width)));
40710
- const sy = Math.min(img.height - 1, Math.max(0, Math.floor((1 - v) * img.height)));
40711
- const sIdx = (sy * img.width + sx) * 4;
40892
+ if (smooth) {
40893
+ sampleImageLinear(source, u * source.width - 0.5, (1 - v) * source.height - 0.5, sample);
40894
+ } else {
40895
+ const sx = Math.min(source.width - 1, Math.max(0, Math.floor(u * source.width)));
40896
+ const sy = Math.min(source.height - 1, Math.max(0, Math.floor((1 - v) * source.height)));
40897
+ const sIdx = (sy * source.width + sx) * 4;
40898
+ for (let c2 = 0; c2 < 4; c2++) sample[c2] = source.data[sIdx + c2];
40899
+ }
40712
40900
  blendPixel(
40713
40901
  rgba,
40714
40902
  width,
@@ -40716,11 +40904,11 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40716
40904
  px,
40717
40905
  py,
40718
40906
  {
40719
- r: img.decodedRgba[sIdx] / 255,
40720
- g: img.decodedRgba[sIdx + 1] / 255,
40721
- b: img.decodedRgba[sIdx + 2] / 255
40907
+ r: sample[0] / 255,
40908
+ g: sample[1] / 255,
40909
+ b: sample[2] / 255
40722
40910
  },
40723
- img.decodedRgba[sIdx + 3] / 255,
40911
+ sample[3] / 255,
40724
40912
  img.blendMode,
40725
40913
  clipMask
40726
40914
  );
@@ -40757,6 +40945,27 @@ function renderDisplayListToPng(displayList, options = {}) {
40757
40945
  const bmp = renderDisplayListToBitmap(displayList, options);
40758
40946
  return encodeRgbaToPng(bmp.width, bmp.height, bmp.data);
40759
40947
  }
40948
+ function pdfBlendModeToCss(mode) {
40949
+ if (!mode || mode === "Normal" || mode === "Compatible") return void 0;
40950
+ const map = {
40951
+ Multiply: "multiply",
40952
+ Screen: "screen",
40953
+ Overlay: "overlay",
40954
+ Darken: "darken",
40955
+ Lighten: "lighten",
40956
+ ColorDodge: "color-dodge",
40957
+ ColorBurn: "color-burn",
40958
+ HardLight: "hard-light",
40959
+ SoftLight: "soft-light",
40960
+ Difference: "difference",
40961
+ Exclusion: "exclusion",
40962
+ Hue: "hue",
40963
+ Saturation: "saturation",
40964
+ Color: "color",
40965
+ Luminosity: "luminosity"
40966
+ };
40967
+ return map[mode];
40968
+ }
40760
40969
  function escapeXmlText(str) {
40761
40970
  let valid = "";
40762
40971
  for (const char of str) {
@@ -40818,44 +41027,74 @@ function renderDisplayListToSvg(displayList, options = {}) {
40818
41027
  parts.push(`<g transform="matrix(${a} ${b} ${-c} ${-d} ${e + c * displayList.height} ${f + d * displayList.height})">`);
40819
41028
  }
40820
41029
  let clipId = 0;
40821
- for (const original of paintOperations(displayList)) {
40822
- if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40823
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40824
- const clips = original.value.clipPaths ?? [];
40825
- const imageClips = original.value.clipImages ?? [];
40826
- for (const clip of clips) {
40827
- const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
40828
- const id = `text-clip-${clipId++}`;
40829
- const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
40830
- parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40831
- }
40832
- for (const image of imageClips) {
40833
- const id = `image-clip-${clipId++}`;
40834
- 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})">`);
40835
- }
40836
- if (operation.kind === "path") {
40837
- const p = operation.value;
40838
- const pathData = svgPathData(p.segments, displayList.height);
40839
- if (pathData) {
40840
- const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
40841
- const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
40842
- const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
40843
- const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
40844
- const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
40845
- const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
40846
- const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
40847
- const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
40848
- const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
40849
- const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
40850
- const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
40851
- const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
40852
- parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
41030
+ const softMaskIds = /* @__PURE__ */ new Map();
41031
+ const appendOperations = (operations) => {
41032
+ for (const original of operations) {
41033
+ if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
41034
+ const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
41035
+ const clips = original.value.clipPaths ?? [];
41036
+ const imageClips = original.value.clipImages ?? [];
41037
+ const blend = pdfBlendModeToCss(original.value.blendMode);
41038
+ if (blend) parts.push(`<g style="mix-blend-mode:${blend}">`);
41039
+ const softMask = original.value.softMask;
41040
+ if (softMask) {
41041
+ let id = softMaskIds.get(softMask);
41042
+ if (!id) {
41043
+ id = `soft-mask-${clipId++}`;
41044
+ softMaskIds.set(softMask, id);
41045
+ const bitmap = renderSoftMask(softMask, displayList, Math.max(scaleX, scaleY));
41046
+ const image = {
41047
+ name: id,
41048
+ width: bitmap.width,
41049
+ height: bitmap.height,
41050
+ decodedRgba: bitmap.data,
41051
+ matrix: [displayList.width, 0, 0, displayList.height, 0, 0],
41052
+ colorSpace: "DeviceGray",
41053
+ bitsPerComponent: 8
41054
+ };
41055
+ 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>`);
41056
+ }
41057
+ parts.push(`<g mask="url(#${id})">`);
40853
41058
  }
40854
- } else if (operation.kind === "image") {
40855
- parts.push(` ${svgImage(operation.value, displayList.height)}`);
41059
+ for (const clip of clips) {
41060
+ const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
41061
+ const id = `text-clip-${clipId++}`;
41062
+ const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
41063
+ parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
41064
+ }
41065
+ for (const image of imageClips) {
41066
+ const id = `image-clip-${clipId++}`;
41067
+ 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})">`);
41068
+ }
41069
+ if (operation.kind === "group") {
41070
+ parts.push(`<g opacity="${operation.value.alpha}" style="isolation:isolate">`);
41071
+ appendOperations(operation.value.operations);
41072
+ parts.push("</g>");
41073
+ } else if (operation.kind === "path") {
41074
+ const p = operation.value;
41075
+ const pathData = svgPathData(p.segments, displayList.height);
41076
+ if (pathData) {
41077
+ const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
41078
+ const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
41079
+ const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
41080
+ const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
41081
+ const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
41082
+ const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
41083
+ const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
41084
+ const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
41085
+ const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
41086
+ const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
41087
+ const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
41088
+ const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
41089
+ parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
41090
+ }
41091
+ } else if (operation.kind === "image") {
41092
+ parts.push(` ${svgImage(operation.value, displayList.height)}`);
41093
+ }
41094
+ for (let i = 0; i < clips.length + imageClips.length + (softMask ? 1 : 0) + (blend ? 1 : 0); i++) parts.push("</g>");
40856
41095
  }
40857
- for (let i = 0; i < clips.length + imageClips.length; i++) parts.push("</g>");
40858
- }
41096
+ };
41097
+ appendOperations(paintOperations(displayList));
40859
41098
  if (displayList.rotation) parts.push("</g>");
40860
41099
  parts.push("</svg>\n");
40861
41100
  return parts.join("\n");
@@ -44268,3 +44507,8 @@ export {
44268
44507
  * Adapted from PDFium third_party/agg23/agg_curves.cpp, curve4_div.
44269
44508
  * See THIRD_PARTY_NOTICES.md for the pinned revision and adaptations.
44270
44509
  */
44510
+ /*!
44511
+ * Staged image reduction adapted from Mozilla PDF.js CanvasGraphics._scaleImage.
44512
+ * Copyright 2012 Mozilla Foundation. Licensed under Apache-2.0.
44513
+ * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
44514
+ */