@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
@@ -35762,14 +35762,18 @@ function evaluateContentStreamToDisplayList(params) {
35762
35762
  const paths = [];
35763
35763
  const images = [];
35764
35764
  const operations = [];
35765
+ let capturedOperations;
35766
+ let insideSoftMask = false;
35765
35767
  const emit = (operation) => {
35766
- const { clipPaths, clipImages } = curState();
35767
- if (clipPaths || clipImages) operation = { ...operation, value: {
35768
+ const { clipPaths, clipImages, softMask } = curState();
35769
+ if (clipPaths || clipImages || softMask) operation = { ...operation, value: {
35768
35770
  ...operation.value,
35769
35771
  ...clipPaths ? { clipPaths } : {},
35770
- ...clipImages ? { clipImages } : {}
35772
+ ...clipImages ? { clipImages } : {},
35773
+ ...softMask ? { softMask } : {}
35771
35774
  } };
35772
- operations.push(operation);
35775
+ (capturedOperations ?? operations).push(operation);
35776
+ if (insideSoftMask) return;
35773
35777
  switch (operation.kind) {
35774
35778
  case "path":
35775
35779
  paths.push(operation.value);
@@ -35875,7 +35879,7 @@ function evaluateContentStreamToDisplayList(params) {
35875
35879
  );
35876
35880
  return { r: kClamp(r), g: kClamp(g), b: kClamp(b) };
35877
35881
  };
35878
- const applyStateOperator = (st, operator, ops, activeResources) => {
35882
+ const applyStateOperator = (st, operator, ops, activeResources, activeFonts, depth) => {
35879
35883
  const num = (i, fb = 0) => ops[i]?.kind === "number" ? ops[i].value : fb;
35880
35884
  if (operator === "cm") {
35881
35885
  const m = [num(0, 1), num(1, 0), num(2, 0), num(3, 1), num(4, 0), num(5, 0)];
@@ -35958,6 +35962,46 @@ function evaluateContentStreamToDisplayList(params) {
35958
35962
  const extDict = params.cosDoc.resolveDict(dictGet(activeResources, "ExtGState"));
35959
35963
  const gsDict = extDict ? params.cosDoc.resolveDict(dictGet(extDict, ops[0].decoded)) : void 0;
35960
35964
  if (gsDict) {
35965
+ const mask = params.cosDoc.resolve(dictGet(gsDict, "SMask"));
35966
+ if (mask?.kind === "name" && mask.decoded === "None") {
35967
+ st.softMask = void 0;
35968
+ } else if (mask?.kind === "dict") {
35969
+ const subtype = params.cosDoc.resolve(dictGet(mask, "S"));
35970
+ const form = params.cosDoc.resolve(dictGet(mask, "G"));
35971
+ if (form?.kind === "stream" && subtype?.kind === "name" && (subtype.decoded === "Alpha" || subtype.decoded === "Luminosity")) {
35972
+ if (depth >= 8) throw new PdfError("E_LIMIT", "Soft-mask nesting exceeds the form depth limit");
35973
+ const parentOperations = capturedOperations;
35974
+ const parentInsideSoftMask = insideSoftMask;
35975
+ const savedTextState = { pendingTextClip, hasTextClip, activeTm, activeTlm };
35976
+ const captured = [];
35977
+ capturedOperations = captured;
35978
+ insideSoftMask = true;
35979
+ const maskState = { ...st, softMask: void 0, fillAlpha: 1, strokeAlpha: 1, blendMode: "Normal" };
35980
+ delete maskState.clipPaths;
35981
+ delete maskState.clipImages;
35982
+ delete maskState.clipRect;
35983
+ stateStack.push(maskState);
35984
+ try {
35985
+ paintForm(form, activeResources, activeFonts, depth, void 0, void 0, true);
35986
+ } finally {
35987
+ stateStack.pop();
35988
+ capturedOperations = parentOperations;
35989
+ insideSoftMask = parentInsideSoftMask;
35990
+ ({ pendingTextClip, hasTextClip, activeTm, activeTlm } = savedTextState);
35991
+ }
35992
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
35993
+ const colorSpace = group ? dictGet(group, "CS") : void 0;
35994
+ const bc = params.cosDoc.resolveArray(dictGet(mask, "BC"));
35995
+ const components = bc?.items.map((item) => {
35996
+ const value = params.cosDoc.resolve(item);
35997
+ return value?.kind === "number" ? value.value : 0;
35998
+ });
35999
+ const [r, g, b] = components ? convertColorSpaceComponentsToRgb(params.cosDoc, colorSpace, "DeviceRGB", components, activeResources) : [0, 0, 0];
36000
+ const transfer = params.cosDoc.resolve(dictGet(mask, "TR"));
36001
+ 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;
36002
+ st.softMask = { subtype: subtype.decoded, operations: captured, backdrop: { r, g, b }, transferMap };
36003
+ }
36004
+ }
35961
36005
  const bmNode = params.cosDoc.resolve(dictGet(gsDict, "BM"));
35962
36006
  if (bmNode?.kind === "name") {
35963
36007
  st.blendMode = bmNode.decoded === "Compatible" ? "Normal" : bmNode.decoded;
@@ -36044,6 +36088,84 @@ function evaluateContentStreamToDisplayList(params) {
36044
36088
  ] }], void 0, void 0, resources, activeFonts, depth);
36045
36089
  stateStack.pop();
36046
36090
  };
36091
+ const paintForm = (form, activeResources, activeFonts, depth, mcid, actualText, maskGroup = false) => {
36092
+ const st = curState();
36093
+ const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
36094
+ const groupType = group ? params.cosDoc.resolve(dictGet(group, "S")) : void 0;
36095
+ const isolated = group ? params.cosDoc.resolve(dictGet(group, "I")) : void 0;
36096
+ const isolate = !maskGroup && groupType?.kind === "name" && groupType.decoded === "Transparency" && isolated?.kind === "boolean" && isolated.value;
36097
+ const formStreamBytes = params.cosDoc.decodeStream(form);
36098
+ const formNodes = parseContentStream(formStreamBytes);
36099
+ const formResDict = params.cosDoc.resolveDict(dictGet(form.dict, "Resources")) ?? activeResources;
36100
+ const formFonts = new Map(activeFonts);
36101
+ for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
36102
+ formFonts.set(k, v);
36103
+ }
36104
+ let nextCtm = [...st.ctm];
36105
+ const matArr = params.cosDoc.resolveArray(dictGet(form.dict, "Matrix"));
36106
+ if (matArr && matArr.items.length >= 6) {
36107
+ const mn = (idx, fb = 0) => {
36108
+ const resolved = params.cosDoc.resolve(matArr.items[idx]);
36109
+ return resolved?.kind === "number" ? resolved.value : fb;
36110
+ };
36111
+ const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
36112
+ nextCtm = multiplyMatrices(formMat, nextCtm);
36113
+ }
36114
+ let nextClip = !isolate && st.clipRect ? [...st.clipRect] : void 0;
36115
+ let nextClipPaths = isolate ? void 0 : st.clipPaths;
36116
+ const bboxArr = params.cosDoc.resolveArray(dictGet(form.dict, "BBox"));
36117
+ if (bboxArr && bboxArr.items.length >= 4) {
36118
+ const bn = (idx, fb = 0) => {
36119
+ const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
36120
+ return resolved?.kind === "number" ? resolved.value : fb;
36121
+ };
36122
+ const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
36123
+ const pts = [
36124
+ transformPoint(nextCtm, bx0, by0),
36125
+ transformPoint(nextCtm, bx1, by0),
36126
+ transformPoint(nextCtm, bx1, by1),
36127
+ transformPoint(nextCtm, bx0, by1)
36128
+ ];
36129
+ nextClipPaths = [...nextClipPaths ?? [], [
36130
+ ...pts.map(([x, y], index) => ({ kind: index === 0 ? "move" : "line", x, y })),
36131
+ { kind: "close" }
36132
+ ]];
36133
+ const fMinX = Math.min(...pts.map((p) => p[0]));
36134
+ const fMinY = Math.min(...pts.map((p) => p[1]));
36135
+ const fMaxX = Math.max(...pts.map((p) => p[0]));
36136
+ const fMaxY = Math.max(...pts.map((p) => p[1]));
36137
+ if (fMaxX > fMinX && fMaxY > fMinY) {
36138
+ nextClip = nextClip ? [
36139
+ Math.max(nextClip[0], fMinX),
36140
+ Math.max(nextClip[1], fMinY),
36141
+ Math.min(nextClip[2], fMaxX),
36142
+ Math.min(nextClip[3], fMaxY)
36143
+ ] : [fMinX, fMinY, fMaxX, fMaxY];
36144
+ }
36145
+ }
36146
+ const parentOperations = capturedOperations;
36147
+ const children = [];
36148
+ const nextState = { ...st, ctm: nextCtm };
36149
+ if (isolate) {
36150
+ capturedOperations = children;
36151
+ nextState.fillAlpha = nextState.strokeAlpha = 1;
36152
+ nextState.blendMode = "Normal";
36153
+ nextState.softMask = void 0;
36154
+ delete nextState.clipImages;
36155
+ delete nextState.clipPaths;
36156
+ delete nextState.clipRect;
36157
+ }
36158
+ if (nextClip) nextState.clipRect = nextClip;
36159
+ if (nextClipPaths) nextState.clipPaths = nextClipPaths;
36160
+ stateStack.push(nextState);
36161
+ try {
36162
+ walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
36163
+ } finally {
36164
+ stateStack.pop();
36165
+ capturedOperations = parentOperations;
36166
+ }
36167
+ if (isolate) emit({ kind: "group", value: { operations: children, alpha: st.fillAlpha, blendMode: st.blendMode, clipRect: st.clipRect } });
36168
+ };
36047
36169
  const walkNodes = (nodes, mcid, actualText, activeResources = params.resourcesDict, activeFonts = fonts, depth = 0) => {
36048
36170
  for (const node of nodes) {
36049
36171
  switch (node.kind) {
@@ -36088,7 +36210,7 @@ function evaluateContentStreamToDisplayList(params) {
36088
36210
  break;
36089
36211
  }
36090
36212
  case "state-op": {
36091
- applyStateOperator(curState(), node.operator, node.operands, activeResources);
36213
+ applyStateOperator(curState(), node.operator, node.operands, activeResources, activeFonts, depth);
36092
36214
  break;
36093
36215
  }
36094
36216
  case "path-op": {
@@ -36374,53 +36496,7 @@ function evaluateContentStreamToDisplayList(params) {
36374
36496
  ...st.clipRect ? { clipRect: [...st.clipRect] } : {}
36375
36497
  }, patternMask, activeResources, activeFonts, depth);
36376
36498
  } else if (sub === "Form" && depth < 8) {
36377
- const formStreamBytes = params.cosDoc.decodeStream(xobjNode);
36378
- const formNodes = parseContentStream(formStreamBytes);
36379
- const formResDict = params.cosDoc.resolveDict(dictGet(xobjNode.dict, "Resources")) ?? activeResources;
36380
- const formFonts = new Map(activeFonts);
36381
- for (const [k, v] of resolvePageFonts(params.cosDoc, formResDict).entries()) {
36382
- formFonts.set(k, v);
36383
- }
36384
- let nextCtm = [...st.ctm];
36385
- const matArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "Matrix"));
36386
- if (matArr && matArr.items.length >= 6) {
36387
- const mn = (idx, fb = 0) => {
36388
- const resolved = params.cosDoc.resolve(matArr.items[idx]);
36389
- return resolved?.kind === "number" ? resolved.value : fb;
36390
- };
36391
- const formMat = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
36392
- nextCtm = multiplyMatrices(formMat, nextCtm);
36393
- }
36394
- let nextClip = st.clipRect ? [...st.clipRect] : void 0;
36395
- const bboxArr = params.cosDoc.resolveArray(dictGet(xobjNode.dict, "BBox"));
36396
- if (bboxArr && bboxArr.items.length >= 4) {
36397
- const bn = (idx, fb = 0) => {
36398
- const resolved = params.cosDoc.resolve(bboxArr.items[idx]);
36399
- return resolved?.kind === "number" ? resolved.value : fb;
36400
- };
36401
- const bx0 = bn(0, 0), by0 = bn(1, 0), bx1 = bn(2, 0), by1 = bn(3, 0);
36402
- const pts = [
36403
- transformPoint(nextCtm, bx0, by0),
36404
- transformPoint(nextCtm, bx1, by0),
36405
- transformPoint(nextCtm, bx0, by1),
36406
- transformPoint(nextCtm, bx1, by1)
36407
- ];
36408
- const fMinX = Math.min(...pts.map((p) => p[0]));
36409
- const fMinY = Math.min(...pts.map((p) => p[1]));
36410
- const fMaxX = Math.max(...pts.map((p) => p[0]));
36411
- const fMaxY = Math.max(...pts.map((p) => p[1]));
36412
- if (fMaxX > fMinX && fMaxY > fMinY) {
36413
- nextClip = nextClip ? [
36414
- Math.max(nextClip[0], fMinX),
36415
- Math.max(nextClip[1], fMinY),
36416
- Math.min(nextClip[2], fMaxX),
36417
- Math.min(nextClip[3], fMaxY)
36418
- ] : [fMinX, fMinY, fMaxX, fMaxY];
36419
- }
36420
- }
36421
- stateStack.push({ ...st, ctm: nextCtm, ...nextClip ? { clipRect: nextClip } : {} });
36422
- walkNodes(formNodes, mcid, actualText, formResDict, formFonts, depth + 1);
36423
- if (stateStack.length > 1) stateStack.pop();
36499
+ paintForm(xobjNode, activeResources, activeFonts, depth, mcid, actualText);
36424
36500
  }
36425
36501
  }
36426
36502
  }
@@ -36639,7 +36715,7 @@ function evaluateContentStreamToDisplayList(params) {
36639
36715
  st.textRenderMode = cmd.mode;
36640
36716
  break;
36641
36717
  case "state-op":
36642
- applyStateOperator(st, cmd.operator, cmd.operands, activeResources);
36718
+ applyStateOperator(st, cmd.operator, cmd.operands, activeResources, activeFonts, depth);
36643
36719
  break;
36644
36720
  case "show-text":
36645
36721
  emitTokenBytes(cmd.token.bytes);
@@ -38902,6 +38978,47 @@ function flattenCubic(x1, y1, x2, y2, x3, y3, x4, y4) {
38902
38978
  points.push([x4, y4]);
38903
38979
  return points;
38904
38980
  }
38981
+ function sampleImageLinear(image, x, y, out) {
38982
+ x = Math.max(0, Math.min(image.width - 1, x));
38983
+ y = Math.max(0, Math.min(image.height - 1, y));
38984
+ const x0 = Math.floor(x), y0 = Math.floor(y);
38985
+ const fx = x - x0, fy = y - y0;
38986
+ out.fill(0);
38987
+ for (let j = 0; j < 2; j++) {
38988
+ for (let i = 0; i < 2; i++) {
38989
+ const offset = (Math.min(image.height - 1, y0 + j) * image.width + Math.min(image.width - 1, x0 + i)) * 4;
38990
+ const alpha = image.data[offset + 3] * (i ? fx : 1 - fx) * (j ? fy : 1 - fy);
38991
+ out[0] = out[0] + image.data[offset] * alpha;
38992
+ out[1] = out[1] + image.data[offset + 1] * alpha;
38993
+ out[2] = out[2] + image.data[offset + 2] * alpha;
38994
+ out[3] = out[3] + alpha;
38995
+ }
38996
+ }
38997
+ if (out[3] > 0) {
38998
+ out[0] = out[0] / out[3];
38999
+ out[1] = out[1] / out[3];
39000
+ out[2] = out[2] / out[3];
39001
+ }
39002
+ }
39003
+ function downscaleImage(image, widthScale, heightScale) {
39004
+ const sample = new Float64Array(4);
39005
+ while (widthScale > 2 && image.width > 1 || heightScale > 2 && image.height > 1) {
39006
+ const width = widthScale > 2 ? Math.ceil(image.width / 2) : image.width;
39007
+ const height = heightScale > 2 ? Math.ceil(image.height / 2) : image.height;
39008
+ const data = new Uint8Array(width * height * 4);
39009
+ for (let y = 0; y < height; y++) {
39010
+ for (let x = 0; x < width; x++) {
39011
+ sampleImageLinear(image, (x + 0.5) * image.width / width - 0.5, (y + 0.5) * image.height / height - 0.5, sample);
39012
+ const offset = (y * width + x) * 4;
39013
+ for (let c = 0; c < 4; c++) data[offset + c] = Math.round(sample[c]);
39014
+ }
39015
+ }
39016
+ widthScale /= image.width / width;
39017
+ heightScale /= image.height / height;
39018
+ image = { width, height, data };
39019
+ }
39020
+ return image;
39021
+ }
38905
39022
  function encodePng(bitmap) {
38906
39023
  return encodeRgbaToPng(bitmap.width, bitmap.height, bitmap.data);
38907
39024
  }
@@ -40207,6 +40324,30 @@ function paintOperations(displayList) {
40207
40324
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
40208
40325
  ];
40209
40326
  }
40327
+ function renderSoftMask(mask, displayList, scale) {
40328
+ const bitmap = renderDisplayListToBitmap({
40329
+ ...displayList,
40330
+ rotation: 0,
40331
+ glyphs: [],
40332
+ paths: [],
40333
+ images: [],
40334
+ operations: mask.operations
40335
+ }, { scale, transparent: true });
40336
+ const { data } = bitmap;
40337
+ for (let i = 0; i < data.length; i += 4) {
40338
+ let value = data[i + 3];
40339
+ if (mask.subtype === "Luminosity") {
40340
+ const alpha = value / 255;
40341
+ const r = Math.round(data[i] * alpha + mask.backdrop.r * 255 * (1 - alpha));
40342
+ const g = Math.round(data[i + 1] * alpha + mask.backdrop.g * 255 * (1 - alpha));
40343
+ const b = Math.round(data[i + 2] * alpha + mask.backdrop.b * 255 * (1 - alpha));
40344
+ value = Math.round(pdfLum(r, g, b));
40345
+ }
40346
+ data[i] = data[i + 1] = data[i + 2] = 0;
40347
+ data[i + 3] = mask.transferMap?.[value] ?? value;
40348
+ }
40349
+ return bitmap;
40350
+ }
40210
40351
  function renderDisplayListToBitmap(displayList, options = {}) {
40211
40352
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
40212
40353
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -40230,10 +40371,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40230
40371
  const aaTxt = options.antialiasText !== false;
40231
40372
  let cachedClips;
40232
40373
  let cachedClipMask;
40374
+ let cachedSoftMask;
40375
+ let cachedSoftMaskPixels;
40233
40376
  const imageClipMasks = /* @__PURE__ */ new Map();
40234
40377
  for (const original of paintOperations(displayList)) {
40235
40378
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40236
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40379
+ let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40380
+ if (operation.kind === "group") {
40381
+ const group = operation.value;
40382
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
40383
+ for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
40384
+ operation = { kind: "image", value: {
40385
+ name: "TransparencyGroup",
40386
+ width: bitmap.width,
40387
+ height: bitmap.height,
40388
+ decodedRgba: bitmap.data,
40389
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
40390
+ colorSpace: "DeviceRGB",
40391
+ bitsPerComponent: 8,
40392
+ blendMode: group.blendMode,
40393
+ clipRect: group.clipRect
40394
+ } };
40395
+ }
40237
40396
  const clips = original.value.clipPaths;
40238
40397
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
40239
40398
  if (clips && !clipMask) {
@@ -40247,6 +40406,19 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40247
40406
  cachedClips = clips;
40248
40407
  cachedClipMask = clipMask;
40249
40408
  }
40409
+ const softMask = original.value.softMask;
40410
+ if (softMask) {
40411
+ if (softMask !== cachedSoftMask) {
40412
+ cachedSoftMaskPixels = renderSoftMask(softMask, displayList, scale).data;
40413
+ cachedSoftMask = softMask;
40414
+ }
40415
+ if (clipMask) {
40416
+ clipMask = clipMask.slice();
40417
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * cachedSoftMaskPixels[i] / 255);
40418
+ } else {
40419
+ clipMask = cachedSoftMaskPixels;
40420
+ }
40421
+ }
40250
40422
  const imageClips = original.value.clipImages;
40251
40423
  if (imageClips) {
40252
40424
  let imageMask = imageClipMasks.get(imageClips);
@@ -40350,6 +40522,17 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40350
40522
  const maxPx = Math.min(width - 1, clipMaxPx, Math.ceil(Math.max(...cornersPx)) - 1);
40351
40523
  const minPy = Math.max(0, clipMinPy, Math.floor(Math.min(...cornersPy)));
40352
40524
  const maxPy = Math.min(height - 1, clipMaxPy, Math.ceil(Math.max(...cornersPy)) - 1);
40525
+ if (minPx > maxPx || minPy > maxPy) continue;
40526
+ const source = downscaleImage(
40527
+ { width: img.width, height: img.height, data: img.decodedRgba },
40528
+ Math.hypot(d, c) * img.width / Math.abs(det * scale),
40529
+ Math.hypot(b, a) * img.height / Math.abs(det * scale)
40530
+ );
40531
+ const ax = a * scale / img.width, ay = b * scale / img.width;
40532
+ const bx = c * scale / img.height, by = d * scale / img.height;
40533
+ const s1 = ax * ax + ay * ay, s2 = bx * bx + by * by, cross = ax * bx + ay * by;
40534
+ const smooth = Math.fround((s1 + s2 + Math.hypot(s1 - s2, 2 * cross)) / 2) <= 1;
40535
+ const sample = new Float64Array(4);
40353
40536
  for (let py = minPy; py <= maxPy; py++) {
40354
40537
  const yPdf = displayList.height - (py + 0.5) / scale;
40355
40538
  if (img.clipRect && (yPdf < img.clipRect[1] || yPdf > img.clipRect[3])) continue;
@@ -40361,9 +40544,14 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40361
40544
  const u = (d * dxPdf - c * dyPdf) / det;
40362
40545
  const v = (-b * dxPdf + a * dyPdf) / det;
40363
40546
  if (u < 0 || u > 1 || v < 0 || v > 1) continue;
40364
- const sx = Math.min(img.width - 1, Math.max(0, Math.floor(u * img.width)));
40365
- const sy = Math.min(img.height - 1, Math.max(0, Math.floor((1 - v) * img.height)));
40366
- const sIdx = (sy * img.width + sx) * 4;
40547
+ if (smooth) {
40548
+ sampleImageLinear(source, u * source.width - 0.5, (1 - v) * source.height - 0.5, sample);
40549
+ } else {
40550
+ const sx = Math.min(source.width - 1, Math.max(0, Math.floor(u * source.width)));
40551
+ const sy = Math.min(source.height - 1, Math.max(0, Math.floor((1 - v) * source.height)));
40552
+ const sIdx = (sy * source.width + sx) * 4;
40553
+ for (let c2 = 0; c2 < 4; c2++) sample[c2] = source.data[sIdx + c2];
40554
+ }
40367
40555
  blendPixel(
40368
40556
  rgba,
40369
40557
  width,
@@ -40371,11 +40559,11 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40371
40559
  px,
40372
40560
  py,
40373
40561
  {
40374
- r: img.decodedRgba[sIdx] / 255,
40375
- g: img.decodedRgba[sIdx + 1] / 255,
40376
- b: img.decodedRgba[sIdx + 2] / 255
40562
+ r: sample[0] / 255,
40563
+ g: sample[1] / 255,
40564
+ b: sample[2] / 255
40377
40565
  },
40378
- img.decodedRgba[sIdx + 3] / 255,
40566
+ sample[3] / 255,
40379
40567
  img.blendMode,
40380
40568
  clipMask
40381
40569
  );
@@ -40412,6 +40600,27 @@ function renderDisplayListToPng(displayList, options = {}) {
40412
40600
  const bmp = renderDisplayListToBitmap(displayList, options);
40413
40601
  return encodeRgbaToPng(bmp.width, bmp.height, bmp.data);
40414
40602
  }
40603
+ function pdfBlendModeToCss(mode) {
40604
+ if (!mode || mode === "Normal" || mode === "Compatible") return void 0;
40605
+ const map = {
40606
+ Multiply: "multiply",
40607
+ Screen: "screen",
40608
+ Overlay: "overlay",
40609
+ Darken: "darken",
40610
+ Lighten: "lighten",
40611
+ ColorDodge: "color-dodge",
40612
+ ColorBurn: "color-burn",
40613
+ HardLight: "hard-light",
40614
+ SoftLight: "soft-light",
40615
+ Difference: "difference",
40616
+ Exclusion: "exclusion",
40617
+ Hue: "hue",
40618
+ Saturation: "saturation",
40619
+ Color: "color",
40620
+ Luminosity: "luminosity"
40621
+ };
40622
+ return map[mode];
40623
+ }
40415
40624
  function escapeXmlText(str) {
40416
40625
  let valid = "";
40417
40626
  for (const char of str) {
@@ -40473,44 +40682,74 @@ function renderDisplayListToSvg(displayList, options = {}) {
40473
40682
  parts.push(`<g transform="matrix(${a} ${b} ${-c} ${-d} ${e + c * displayList.height} ${f + d * displayList.height})">`);
40474
40683
  }
40475
40684
  let clipId = 0;
40476
- for (const original of paintOperations(displayList)) {
40477
- if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40478
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40479
- const clips = original.value.clipPaths ?? [];
40480
- const imageClips = original.value.clipImages ?? [];
40481
- for (const clip of clips) {
40482
- const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
40483
- const id = `text-clip-${clipId++}`;
40484
- const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
40485
- parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40486
- }
40487
- for (const image of imageClips) {
40488
- const id = `image-clip-${clipId++}`;
40489
- 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})">`);
40490
- }
40491
- if (operation.kind === "path") {
40492
- const p = operation.value;
40493
- const pathData = svgPathData(p.segments, displayList.height);
40494
- if (pathData) {
40495
- const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
40496
- const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
40497
- const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
40498
- const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
40499
- const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
40500
- const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
40501
- const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
40502
- const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
40503
- const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
40504
- const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
40505
- const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
40506
- const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
40507
- parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40685
+ const softMaskIds = /* @__PURE__ */ new Map();
40686
+ const appendOperations = (operations) => {
40687
+ for (const original of operations) {
40688
+ if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40689
+ const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40690
+ const clips = original.value.clipPaths ?? [];
40691
+ const imageClips = original.value.clipImages ?? [];
40692
+ const blend = pdfBlendModeToCss(original.value.blendMode);
40693
+ if (blend) parts.push(`<g style="mix-blend-mode:${blend}">`);
40694
+ const softMask = original.value.softMask;
40695
+ if (softMask) {
40696
+ let id = softMaskIds.get(softMask);
40697
+ if (!id) {
40698
+ id = `soft-mask-${clipId++}`;
40699
+ softMaskIds.set(softMask, id);
40700
+ const bitmap = renderSoftMask(softMask, displayList, Math.max(scaleX, scaleY));
40701
+ const image = {
40702
+ name: id,
40703
+ width: bitmap.width,
40704
+ height: bitmap.height,
40705
+ decodedRgba: bitmap.data,
40706
+ matrix: [displayList.width, 0, 0, displayList.height, 0, 0],
40707
+ colorSpace: "DeviceGray",
40708
+ bitsPerComponent: 8
40709
+ };
40710
+ 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>`);
40711
+ }
40712
+ parts.push(`<g mask="url(#${id})">`);
40508
40713
  }
40509
- } else if (operation.kind === "image") {
40510
- parts.push(` ${svgImage(operation.value, displayList.height)}`);
40714
+ for (const clip of clips) {
40715
+ const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
40716
+ const id = `text-clip-${clipId++}`;
40717
+ const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
40718
+ parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40719
+ }
40720
+ for (const image of imageClips) {
40721
+ const id = `image-clip-${clipId++}`;
40722
+ 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})">`);
40723
+ }
40724
+ if (operation.kind === "group") {
40725
+ parts.push(`<g opacity="${operation.value.alpha}" style="isolation:isolate">`);
40726
+ appendOperations(operation.value.operations);
40727
+ parts.push("</g>");
40728
+ } else if (operation.kind === "path") {
40729
+ const p = operation.value;
40730
+ const pathData = svgPathData(p.segments, displayList.height);
40731
+ if (pathData) {
40732
+ const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
40733
+ const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
40734
+ const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
40735
+ const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
40736
+ const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
40737
+ const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
40738
+ const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
40739
+ const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
40740
+ const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
40741
+ const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
40742
+ const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
40743
+ const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
40744
+ parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40745
+ }
40746
+ } else if (operation.kind === "image") {
40747
+ parts.push(` ${svgImage(operation.value, displayList.height)}`);
40748
+ }
40749
+ for (let i = 0; i < clips.length + imageClips.length + (softMask ? 1 : 0) + (blend ? 1 : 0); i++) parts.push("</g>");
40511
40750
  }
40512
- for (let i = 0; i < clips.length + imageClips.length; i++) parts.push("</g>");
40513
- }
40751
+ };
40752
+ appendOperations(paintOperations(displayList));
40514
40753
  if (displayList.rotation) parts.push("</g>");
40515
40754
  parts.push("</svg>\n");
40516
40755
  return parts.join("\n");
@@ -42138,3 +42377,8 @@ export {
42138
42377
  * Adapted from PDFium third_party/agg23/agg_curves.cpp, curve4_div.
42139
42378
  * See THIRD_PARTY_NOTICES.md for the pinned revision and adaptations.
42140
42379
  */
42380
+ /*!
42381
+ * Staged image reduction adapted from Mozilla PDF.js CanvasGraphics._scaleImage.
42382
+ * Copyright 2012 Mozilla Foundation. Licensed under Apache-2.0.
42383
+ * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
42384
+ */