@poe-platform/safe-bash 0.1.762 → 0.1.764

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 (35) hide show
  1. package/dist/image-ast/index.browser.js +454 -208
  2. package/dist/image-ast/index.js +454 -208
  3. package/dist/pdf-ast/ast.d.ts +23 -0
  4. package/dist/pdf-ast/index.js +543 -244
  5. package/dist/safe-bash/chunks/{chunk-CRQDMBQA.js → chunk-FSH7QRIC.js} +10 -1
  6. package/dist/safe-bash/command-chunks/{chunk-D4GXXV65.js → chunk-B7YLGJRF.js} +2 -2
  7. package/dist/safe-bash/command-chunks/{chunk-P3Q2QSCA.js → chunk-G3IIEU2N.js} +457 -208
  8. package/dist/safe-bash/command-chunks/{chunk-F7MJRXQ2.js → chunk-RDPJGIQF.js} +1 -1
  9. package/dist/safe-bash/commands/python/index.browser.js +1 -1
  10. package/dist/safe-bash/commands/python/llm-module.js +3 -1
  11. package/dist/safe-bash/commands/python/shell-module.js +7 -0
  12. package/dist/safe-bash/core.browser.js +33 -13
  13. package/dist/safe-bash/shell/runtime.js +44 -12
  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 +7476 -7338
  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 +454 -208
  22. package/dist/safe-bash-command-pdfinfo/index.js +541 -244
  23. package/dist/safe-bash-command-pdftk/index.js +454 -208
  24. package/dist/safe-bash-command-pdftoppm/index.js +541 -244
  25. package/dist/safe-bash-command-pdftotext/index.js +454 -208
  26. package/dist/safe-bash-command-qpdf/index.js +454 -208
  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 +514 -208
  30. package/dist/safe-bash-command-wkhtmltopdf/index.js +455 -208
  31. package/dist/safe-playwright-cloudflare/browser-snapshot-labels.d.ts +14 -0
  32. package/dist/safe-playwright-cloudflare/browser-snapshot-labels.js +62 -0
  33. package/dist/safe-playwright-cloudflare/browser-snapshot-scheduler.js +8 -1
  34. package/package.json +2 -2
  35. package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +27 -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);
@@ -38943,6 +39019,184 @@ function downscaleImage(image, widthScale, heightScale) {
38943
39019
  }
38944
39020
  return image;
38945
39021
  }
39022
+ var MAX_STROKE_VERTICES = 1e6;
39023
+ function dashSubpath(path, pattern, phase) {
39024
+ const cycle = pattern.reduce((sum, value) => sum + value, 0);
39025
+ if (!(cycle > 0)) return [path];
39026
+ let offset = (phase % cycle + cycle) % cycle, index = 0;
39027
+ while (offset > 0) {
39028
+ if (offset < pattern[index]) break;
39029
+ offset -= pattern[index];
39030
+ index = (index + 1) % pattern.length;
39031
+ }
39032
+ let remaining = pattern[index] - offset;
39033
+ const points = path.closed ? [...path.points, path.points[0]] : path.points;
39034
+ const result = [];
39035
+ let current = [];
39036
+ let steps = 0;
39037
+ const flush = () => {
39038
+ if (current.length) result.push({ points: current, closed: false });
39039
+ current = [];
39040
+ };
39041
+ const advance = (point) => {
39042
+ while (remaining <= 0) {
39043
+ if (++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39044
+ if (index % 2 === 0) {
39045
+ if (pattern[index] === 0) result.push({ points: [point, point], closed: false });
39046
+ flush();
39047
+ }
39048
+ index = (index + 1) % pattern.length;
39049
+ remaining = pattern[index];
39050
+ }
39051
+ };
39052
+ for (let i = 1; i < points.length; i++) {
39053
+ const start = points[i - 1], end = points[i];
39054
+ const dx = end[0] - start[0], dy = end[1] - start[1];
39055
+ const length = Math.hypot(dx, dy);
39056
+ if (!Number.isFinite(length) || length / cycle * pattern.length > MAX_STROKE_VERTICES) {
39057
+ throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39058
+ }
39059
+ let distance = 0;
39060
+ while (distance < length) {
39061
+ const point = [start[0] + dx * distance / length, start[1] + dy * distance / length];
39062
+ advance(point);
39063
+ const step = Math.min(remaining, length - distance);
39064
+ if (distance + step === distance || ++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39065
+ distance += step;
39066
+ remaining -= step;
39067
+ if (index % 2 === 0) {
39068
+ if (!current.length) current.push(point);
39069
+ current.push([start[0] + dx * distance / length, start[1] + dy * distance / length]);
39070
+ }
39071
+ }
39072
+ }
39073
+ flush();
39074
+ if (path.closed && result.length) {
39075
+ const first = result[0], last = result[result.length - 1];
39076
+ const start = path.points[0];
39077
+ const firstPoint = first.points[0], lastPoint = last.points[last.points.length - 1];
39078
+ if (firstPoint[0] === start[0] && firstPoint[1] === start[1] && lastPoint[0] === start[0] && lastPoint[1] === start[1]) {
39079
+ if (first === last) result[0] = { points: first.points, closed: true };
39080
+ else {
39081
+ result[0] = { points: [...last.points, ...first.points.slice(1)], closed: false };
39082
+ result.pop();
39083
+ }
39084
+ }
39085
+ }
39086
+ return result;
39087
+ }
39088
+ function strokeOutlines(paths, width, cap, join, miterLimit, dashArray = [], dashPhase = 0) {
39089
+ const half = width / 2;
39090
+ const contours = [];
39091
+ const pattern = dashArray.length % 2 ? [...dashArray, ...dashArray] : dashArray;
39092
+ let count = 0;
39093
+ let contour = [];
39094
+ const add = (x, y) => {
39095
+ if (++count > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke outline exceeds the vertex limit");
39096
+ contour.push([x, y]);
39097
+ };
39098
+ const arc = (point, dx1, dy1, dx2, dy2) => {
39099
+ let a1 = Math.atan2(dy1, dx1), a2 = Math.atan2(dy2, dx2);
39100
+ const ccw = a1 - a2 > 0 && a1 - a2 < Math.PI;
39101
+ const step = Math.acos(half / (half + 0.125)) * 2;
39102
+ add(point[0] + dx1, point[1] + dy1);
39103
+ if (step > 0) {
39104
+ if (!ccw) {
39105
+ if (a1 > a2) a2 += 2 * Math.PI;
39106
+ a2 -= step / 4;
39107
+ if ((a2 - a1) / step > MAX_STROKE_VERTICES - count) throw new PdfError("E_LIMIT", "Stroke arc exceeds the vertex limit");
39108
+ for (a1 += step; a1 < a2; a1 += step) add(point[0] + half * Math.cos(a1), point[1] + half * Math.sin(a1));
39109
+ } else {
39110
+ if (a1 < a2) a2 -= 2 * Math.PI;
39111
+ a2 += step / 4;
39112
+ if ((a1 - a2) / step > MAX_STROKE_VERTICES - count) throw new PdfError("E_LIMIT", "Stroke arc exceeds the vertex limit");
39113
+ for (a1 -= step; a1 > a2; a1 -= step) add(point[0] + half * Math.cos(a1), point[1] + half * Math.sin(a1));
39114
+ }
39115
+ }
39116
+ add(point[0] + dx2, point[1] + dy2);
39117
+ };
39118
+ const addCap = (point, next) => {
39119
+ const length = Math.hypot(next[0] - point[0], next[1] - point[1]);
39120
+ const dx = half * (next[1] - point[1]) / length;
39121
+ const dy = half * (next[0] - point[0]) / length;
39122
+ if (cap !== 1) {
39123
+ const sx = cap === 2 ? dy : 0, sy = cap === 2 ? dx : 0;
39124
+ add(point[0] - dx - sx, point[1] + dy - sy);
39125
+ add(point[0] + dx - sx, point[1] - dy - sy);
39126
+ } else {
39127
+ const angle = Math.atan2(dy, -dx);
39128
+ const step = Math.max(1e-3, Math.acos(half / (half + 0.125)) * 2);
39129
+ add(point[0] - dx, point[1] + dy);
39130
+ for (let a = angle + step; a < angle + Math.PI - step / 4; a += step) add(point[0] + half * Math.cos(a), point[1] + half * Math.sin(a));
39131
+ add(point[0] + dx, point[1] - dy);
39132
+ }
39133
+ };
39134
+ const addJoin = (prev, point, next) => {
39135
+ const len1 = Math.hypot(point[0] - prev[0], point[1] - prev[1]);
39136
+ const len2 = Math.hypot(next[0] - point[0], next[1] - point[1]);
39137
+ const dx1 = half * (point[1] - prev[1]) / len1, dy1 = half * (point[0] - prev[0]) / len1;
39138
+ const dx2 = half * (next[1] - point[1]) / len2, dy2 = half * (next[0] - point[0]) / len2;
39139
+ const inner = (next[0] - point[0]) * (point[1] - prev[1]) - (next[1] - point[1]) * (point[0] - prev[0]) > 0;
39140
+ if (!inner && join === 1) {
39141
+ arc(point, dx1, -dy1, dx2, -dy2);
39142
+ return;
39143
+ }
39144
+ if (inner || join === 0) {
39145
+ const ax = prev[0] + dx1, ay = prev[1] - dy1;
39146
+ const bx = point[0] + dx1, by = point[1] - dy1;
39147
+ const cx = point[0] + dx2, cy = point[1] - dy2;
39148
+ const dx = next[0] + dx2, dy = next[1] - dy2;
39149
+ const den = (bx - ax) * (dy - cy) - (by - ay) * (dx - cx);
39150
+ if (Math.abs(den) >= 1e-30) {
39151
+ const t = ((ay - cy) * (dx - cx) - (ax - cx) * (dy - cy)) / den;
39152
+ const x = ax + (bx - ax) * t, y = ay + (by - ay) * t;
39153
+ if (Math.hypot(x - point[0], y - point[1]) <= half * (inner ? 1.01 : miterLimit)) {
39154
+ add(x, y);
39155
+ return;
39156
+ }
39157
+ } else if ((bx - prev[0]) * dy1 - (prev[1] - by) * dx1 < 0 !== (bx - next[0]) * dy1 - (next[1] - by) * dx1 < 0) {
39158
+ add(bx, by);
39159
+ return;
39160
+ }
39161
+ }
39162
+ add(point[0] + dx1, point[1] - dy1);
39163
+ add(point[0] + dx2, point[1] - dy2);
39164
+ };
39165
+ for (const path of paths) {
39166
+ for (const subpath of pattern.length ? dashSubpath(path, pattern, dashPhase) : [path]) {
39167
+ const points = [];
39168
+ for (const point of subpath.points) {
39169
+ const prev = points[points.length - 1];
39170
+ if (!prev || Math.hypot(prev[0] - point[0], prev[1] - point[1]) > 1e-14) points.push(point);
39171
+ }
39172
+ let closed = subpath.closed;
39173
+ if (closed && points.length > 1 && Math.hypot(points[0][0] - points[points.length - 1][0], points[0][1] - points[points.length - 1][1]) <= 1e-14) points.pop();
39174
+ if (points.length < 3) closed = false;
39175
+ if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
39176
+ contour = [];
39177
+ const [x, y] = points[0];
39178
+ addCap([x, y], [x + 1, y]);
39179
+ addCap([x, y], [x - 1, y]);
39180
+ contours.push(contour);
39181
+ } else if (points.length >= 2) {
39182
+ contour = [];
39183
+ if (!closed) addCap(points[0], points[1]);
39184
+ for (let i = closed ? 0 : 1; i < points.length - (closed ? 0 : 1); i++) {
39185
+ addJoin(points[(i + points.length - 1) % points.length], points[i], points[(i + 1) % points.length]);
39186
+ }
39187
+ if (closed) {
39188
+ contours.push(contour);
39189
+ contour = [];
39190
+ } else addCap(points[points.length - 1], points[points.length - 2]);
39191
+ for (let i = points.length - (closed ? 1 : 2); i >= (closed ? 0 : 1); i--) {
39192
+ addJoin(points[(i + 1) % points.length], points[i], points[(i + points.length - 1) % points.length]);
39193
+ }
39194
+ contours.push(contour);
39195
+ }
39196
+ }
39197
+ }
39198
+ return contours;
39199
+ }
38946
39200
  function encodePng(bitmap) {
38947
39201
  return encodeRgbaToPng(bitmap.width, bitmap.height, bitmap.data);
38948
39202
  }
@@ -40033,111 +40287,60 @@ function blendPixel(rgba, width, height, px, py, color, alpha, blendMode, clipMa
40033
40287
  rgba[idx + 2] = Math.round((effB * a + cbB * dstA * (1 - a)) / outA * 255);
40034
40288
  rgba[idx + 3] = Math.round(outA * 255);
40035
40289
  }
40036
- function drawAntiAliasedSegment(rgba, width, height, x0, y0, x1, y1, strokeWidth, color, alpha = 1, lineCap = 0, antialias = true, blendMode, clipMask) {
40037
- const halfW = Math.max(0.6, strokeWidth * 0.5);
40038
- const dx = x1 - x0;
40039
- const dy = y1 - y0;
40040
- const lenSq = dx * dx + dy * dy;
40041
- const segLen = Math.sqrt(lenSq);
40042
- const pad = lineCap === 2 ? halfW + 2 : halfW + 1;
40043
- const minX = Math.max(0, Math.floor(Math.min(x0, x1) - pad));
40044
- const maxX = Math.min(width - 1, Math.ceil(Math.max(x0, x1) + pad));
40045
- const minY = Math.max(0, Math.floor(Math.min(y0, y1) - pad));
40046
- const maxY = Math.min(height - 1, Math.ceil(Math.max(y0, y1) + pad));
40047
- for (let py = minY; py <= maxY; py++) {
40048
- for (let px = minX; px <= maxX; px++) {
40049
- const cx = px + 0.5;
40050
- const cy = py + 0.5;
40051
- if (segLen > 1e-6 && (lineCap === 0 || lineCap === 2)) {
40052
- const ux = dx / segLen;
40053
- const uy = dy / segLen;
40054
- const along = (cx - x0) * ux + (cy - y0) * uy;
40055
- const perp = Math.abs(-(cx - x0) * uy + (cy - y0) * ux);
40056
- const minAlong = lineCap === 2 ? -halfW : 0;
40057
- const maxAlong = lineCap === 2 ? segLen + halfW : segLen;
40058
- const overAlong = along < minAlong ? minAlong - along : along > maxAlong ? along - maxAlong : 0;
40059
- const dist2 = overAlong > 0 ? Math.max(perp, halfW + overAlong) : perp;
40060
- if (dist2 <= halfW + 0.75) {
40061
- const cov = antialias ? Math.max(0, Math.min(1, halfW + 0.5 - dist2)) : dist2 <= halfW + 0.25 ? 1 : 0;
40062
- blendPixel(rgba, width, height, px, py, color, cov * alpha, blendMode, clipMask);
40063
- }
40064
- continue;
40065
- }
40066
- let t = lenSq > 1e-6 ? ((cx - x0) * dx + (cy - y0) * dy) / lenSq : 0;
40067
- t = Math.max(0, Math.min(1, t));
40068
- const projX = x0 + t * dx;
40069
- const projY = y0 + t * dy;
40070
- const dist = Math.hypot(cx - projX, cy - projY);
40071
- if (dist <= halfW + 0.75) {
40072
- const cov = antialias ? Math.max(0, Math.min(1, halfW + 0.5 - dist)) : dist <= halfW + 0.25 ? 1 : 0;
40073
- blendPixel(rgba, width, height, px, py, color, cov * alpha, blendMode, clipMask);
40074
- }
40075
- }
40076
- }
40077
- }
40078
- function segmentsToScreenEdges(segments, pageHeight, scale, closeSubpaths = false) {
40079
- const edges = [];
40080
- let curX = 0;
40081
- let curY = 0;
40082
- let startX = 0;
40083
- let startY = 0;
40084
- let hasOpenSubpath = false;
40290
+ function segmentsToScreenPaths(segments, pageHeight, scale) {
40291
+ const paths = [];
40292
+ let points = [];
40293
+ let current = [0, 0];
40085
40294
  const toScreen = (x, y) => [x * scale, (pageHeight - y) * scale];
40086
- for (const seg of segments) {
40087
- if (seg.kind === "move") {
40088
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
40089
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
40090
- }
40091
- [curX, curY] = toScreen(seg.x, seg.y);
40092
- startX = curX;
40093
- startY = curY;
40094
- hasOpenSubpath = false;
40095
- } else if (seg.kind === "line") {
40096
- const [nx, ny] = toScreen(seg.x, seg.y);
40097
- edges.push({ x0: curX, y0: curY, x1: nx, y1: ny });
40098
- curX = nx;
40099
- curY = ny;
40100
- hasOpenSubpath = true;
40101
- } else if (seg.kind === "cubic") {
40102
- const [p1x, p1y] = toScreen(seg.x1, seg.y1);
40103
- const [p2x, p2y] = toScreen(seg.x2, seg.y2);
40104
- const [p3x, p3y] = toScreen(seg.x, seg.y);
40105
- const points = flattenCubic(curX, curY, p1x, p1y, p2x, p2y, p3x, p3y);
40106
- let px = curX;
40107
- let py = curY;
40108
- for (let i = 1; i < points.length; i++) {
40109
- const [qx, qy] = points[i];
40110
- edges.push({ x0: px, y0: py, x1: qx, y1: qy });
40111
- px = qx;
40112
- py = qy;
40113
- }
40114
- curX = p3x;
40115
- curY = p3y;
40116
- hasOpenSubpath = true;
40117
- } else if (seg.kind === "close") {
40118
- if (curX !== startX || curY !== startY) {
40119
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
40120
- curX = startX;
40121
- curY = startY;
40122
- }
40123
- hasOpenSubpath = false;
40124
- } else if (seg.kind === "rect") {
40125
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
40126
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
40127
- }
40128
- const [rx0, ry0] = toScreen(seg.x, seg.y);
40129
- const [rx1, ry1] = toScreen(seg.x + seg.width, seg.y + seg.height);
40130
- edges.push(
40131
- { x0: rx0, y0: ry0, x1: rx1, y1: ry0 },
40132
- { x0: rx1, y0: ry0, x1: rx1, y1: ry1 },
40133
- { x0: rx1, y0: ry1, x1: rx0, y1: ry1 },
40134
- { x0: rx0, y0: ry1, x1: rx0, y1: ry0 }
40135
- );
40136
- hasOpenSubpath = false;
40295
+ for (const segment of segments) {
40296
+ if (segment.kind === "move") {
40297
+ if (points.length) paths.push({ points, closed: false });
40298
+ current = toScreen(segment.x, segment.y);
40299
+ points = [current];
40300
+ } else if (segment.kind === "line") {
40301
+ if (!points.length) points = [current];
40302
+ current = toScreen(segment.x, segment.y);
40303
+ points.push(current);
40304
+ } else if (segment.kind === "cubic") {
40305
+ if (!points.length) points = [current];
40306
+ const a = toScreen(segment.x1, segment.y1), b = toScreen(segment.x2, segment.y2);
40307
+ const end = toScreen(segment.x, segment.y);
40308
+ const curve = flattenCubic(current[0], current[1], a[0], a[1], b[0], b[1], end[0], end[1]);
40309
+ for (let i = 1; i < curve.length; i++) points.push(curve[i]);
40310
+ current = end;
40311
+ } else if (segment.kind === "close") {
40312
+ if (points.length) {
40313
+ paths.push({ points, closed: true });
40314
+ current = points[0];
40315
+ points = [];
40316
+ }
40317
+ } else if (segment.kind === "rect") {
40318
+ if (points.length) paths.push({ points, closed: false });
40319
+ const first = toScreen(segment.x, segment.y);
40320
+ paths.push({ points: [
40321
+ first,
40322
+ toScreen(segment.x + segment.width, segment.y),
40323
+ toScreen(segment.x + segment.width, segment.y + segment.height),
40324
+ toScreen(segment.x, segment.y + segment.height)
40325
+ ], closed: true });
40326
+ current = first;
40327
+ points = [];
40328
+ }
40329
+ }
40330
+ if (points.length) paths.push({ points, closed: false });
40331
+ return paths;
40332
+ }
40333
+ function pathsToEdges(paths, closeSubpaths = false) {
40334
+ const edges = [];
40335
+ for (const { points, closed } of paths) {
40336
+ for (let i = 1; i < points.length; i++) {
40337
+ const a = points[i - 1], b = points[i];
40338
+ edges.push({ x0: a[0], y0: a[1], x1: b[0], y1: b[1] });
40339
+ }
40340
+ if ((closed || closeSubpaths) && points.length > 1) {
40341
+ const a = points[points.length - 1], b = points[0];
40342
+ edges.push({ x0: a[0], y0: a[1], x1: b[0], y1: b[1] });
40137
40343
  }
40138
- }
40139
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
40140
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
40141
40344
  }
40142
40345
  return edges;
40143
40346
  }
@@ -40248,6 +40451,30 @@ function paintOperations(displayList) {
40248
40451
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
40249
40452
  ];
40250
40453
  }
40454
+ function renderSoftMask(mask, displayList, scale) {
40455
+ const bitmap = renderDisplayListToBitmap({
40456
+ ...displayList,
40457
+ rotation: 0,
40458
+ glyphs: [],
40459
+ paths: [],
40460
+ images: [],
40461
+ operations: mask.operations
40462
+ }, { scale, transparent: true });
40463
+ const { data } = bitmap;
40464
+ for (let i = 0; i < data.length; i += 4) {
40465
+ let value = data[i + 3];
40466
+ if (mask.subtype === "Luminosity") {
40467
+ const alpha = value / 255;
40468
+ const r = Math.round(data[i] * alpha + mask.backdrop.r * 255 * (1 - alpha));
40469
+ const g = Math.round(data[i + 1] * alpha + mask.backdrop.g * 255 * (1 - alpha));
40470
+ const b = Math.round(data[i + 2] * alpha + mask.backdrop.b * 255 * (1 - alpha));
40471
+ value = Math.round(pdfLum(r, g, b));
40472
+ }
40473
+ data[i] = data[i + 1] = data[i + 2] = 0;
40474
+ data[i + 3] = mask.transferMap?.[value] ?? value;
40475
+ }
40476
+ return bitmap;
40477
+ }
40251
40478
  function renderDisplayListToBitmap(displayList, options = {}) {
40252
40479
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
40253
40480
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -40271,10 +40498,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40271
40498
  const aaTxt = options.antialiasText !== false;
40272
40499
  let cachedClips;
40273
40500
  let cachedClipMask;
40501
+ let cachedSoftMask;
40502
+ let cachedSoftMaskPixels;
40274
40503
  const imageClipMasks = /* @__PURE__ */ new Map();
40275
40504
  for (const original of paintOperations(displayList)) {
40276
40505
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40277
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40506
+ let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40507
+ if (operation.kind === "group") {
40508
+ const group = operation.value;
40509
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
40510
+ for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
40511
+ operation = { kind: "image", value: {
40512
+ name: "TransparencyGroup",
40513
+ width: bitmap.width,
40514
+ height: bitmap.height,
40515
+ decodedRgba: bitmap.data,
40516
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
40517
+ colorSpace: "DeviceRGB",
40518
+ bitsPerComponent: 8,
40519
+ blendMode: group.blendMode,
40520
+ clipRect: group.clipRect
40521
+ } };
40522
+ }
40278
40523
  const clips = original.value.clipPaths;
40279
40524
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
40280
40525
  if (clips && !clipMask) {
@@ -40282,12 +40527,25 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40282
40527
  for (const clip of clips) {
40283
40528
  const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
40284
40529
  const layer = new Uint8Array(width * height * 4);
40285
- fillEdgesScanline4x4(layer, width, height, segmentsToScreenEdges(segments, displayList.height, scale, true), { r: 1, g: 1, b: 1 }, 1, fillRule);
40530
+ fillEdgesScanline4x4(layer, width, height, pathsToEdges(segmentsToScreenPaths(segments, displayList.height, scale), true), { r: 1, g: 1, b: 1 }, 1, fillRule);
40286
40531
  for (let i = 3; i < layer.length; i += 4) clipMask[i] = Math.round(clipMask[i] * layer[i] / 255);
40287
40532
  }
40288
40533
  cachedClips = clips;
40289
40534
  cachedClipMask = clipMask;
40290
40535
  }
40536
+ const softMask = original.value.softMask;
40537
+ if (softMask) {
40538
+ if (softMask !== cachedSoftMask) {
40539
+ cachedSoftMaskPixels = renderSoftMask(softMask, displayList, scale).data;
40540
+ cachedSoftMask = softMask;
40541
+ }
40542
+ if (clipMask) {
40543
+ clipMask = clipMask.slice();
40544
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * cachedSoftMaskPixels[i] / 255);
40545
+ } else {
40546
+ clipMask = cachedSoftMaskPixels;
40547
+ }
40548
+ }
40291
40549
  const imageClips = original.value.clipImages;
40292
40550
  if (imageClips) {
40293
40551
  let imageMask = imageClipMasks.get(imageClips);
@@ -40316,62 +40574,38 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40316
40574
  if (operation.kind === "path") {
40317
40575
  const path = operation.value;
40318
40576
  if (path.fillColor) {
40319
- const edges = segmentsToScreenEdges(path.segments, displayList.height, scale, true);
40577
+ const edges = pathsToEdges(segmentsToScreenPaths(path.segments, displayList.height, scale), true);
40320
40578
  const clipScreen = path.clipRect ? [path.clipRect[0] * scale, (displayList.height - path.clipRect[3]) * scale, path.clipRect[2] * scale, (displayList.height - path.clipRect[1]) * scale] : void 0;
40321
40579
  fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
40322
40580
  }
40323
40581
  if (path.strokeColor) {
40324
- const edges = segmentsToScreenEdges(path.segments, displayList.height, scale, false);
40325
40582
  const rawSw = path.strokeWidth * scale;
40326
40583
  const sw = Math.max(1, rawSw);
40327
40584
  const strokeAlpha = options.thinLineMode === "shape" && rawSw < 1 ? (path.strokeAlpha ?? 1) * Math.max(0.25, rawSw) : path.strokeAlpha ?? 1;
40328
- const dashArr = path.dashArray && path.dashArray.length > 0 ? path.dashArray.map((d) => Math.max(0, d * scale)) : void 0;
40329
- const dashCycle = dashArr ? dashArr.reduce((a, b) => a + b, 0) : 0;
40330
- let dashDist = (path.dashPhase ?? 0) * scale % (dashCycle || 1);
40331
- if (dashDist < 0) dashDist += dashCycle;
40332
- for (const e of edges) {
40333
- if (!dashArr || dashCycle <= 1e-4) {
40334
- drawAntiAliasedSegment(rgba, width, height, e.x0, e.y0, e.x1, e.y1, sw, path.strokeColor, strokeAlpha, path.lineCap ?? 0, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
40335
- } else {
40336
- const dx = e.x1 - e.x0;
40337
- const dy = e.y1 - e.y0;
40338
- const edgeLen = Math.hypot(dx, dy);
40339
- if (edgeLen <= 1e-4) continue;
40340
- let pos = 0;
40341
- while (pos < edgeLen) {
40342
- let cycleRem = dashDist % dashCycle;
40343
- let dIdx = 0;
40344
- while (dIdx < dashArr.length - 1 && cycleRem >= dashArr[dIdx]) {
40345
- cycleRem -= dashArr[dIdx];
40346
- dIdx++;
40347
- }
40348
- const segRemainInDash = Math.max(1e-4, dashArr[dIdx] - cycleRem);
40349
- const step = Math.min(edgeLen - pos, segRemainInDash);
40350
- if (dIdx % 2 === 0) {
40351
- const t0 = pos / edgeLen;
40352
- const t1 = (pos + step) / edgeLen;
40353
- drawAntiAliasedSegment(
40354
- rgba,
40355
- width,
40356
- height,
40357
- e.x0 + dx * t0,
40358
- e.y0 + dy * t0,
40359
- e.x0 + dx * t1,
40360
- e.y0 + dy * t1,
40361
- sw,
40362
- path.strokeColor,
40363
- strokeAlpha,
40364
- path.lineCap ?? 0,
40365
- original.kind === "glyph" ? aaTxt : aaVec,
40366
- path.blendMode,
40367
- clipMask
40368
- );
40369
- }
40370
- pos += step;
40371
- dashDist = (dashDist + step) % dashCycle;
40372
- }
40373
- }
40374
- }
40585
+ const contours = strokeOutlines(
40586
+ segmentsToScreenPaths(path.segments, displayList.height, scale),
40587
+ sw,
40588
+ path.lineCap ?? 0,
40589
+ path.lineJoin ?? 0,
40590
+ path.miterLimit ?? 10,
40591
+ path.dashArray?.map((value) => Math.max(0, value * scale)),
40592
+ (path.dashPhase ?? 0) * scale
40593
+ );
40594
+ const edges = pathsToEdges(contours.map((points) => ({ points, closed: true })));
40595
+ const clipScreen = path.clipRect ? [path.clipRect[0] * scale, (displayList.height - path.clipRect[3]) * scale, path.clipRect[2] * scale, (displayList.height - path.clipRect[1]) * scale] : void 0;
40596
+ fillEdgesScanline4x4(
40597
+ rgba,
40598
+ width,
40599
+ height,
40600
+ edges,
40601
+ path.strokeColor,
40602
+ strokeAlpha,
40603
+ "nonzero",
40604
+ clipScreen,
40605
+ original.kind === "glyph" ? aaTxt : aaVec,
40606
+ path.blendMode,
40607
+ clipMask
40608
+ );
40375
40609
  }
40376
40610
  } else if (operation.kind === "image") {
40377
40611
  const img = operation.value;
@@ -40469,6 +40703,27 @@ function renderDisplayListToPng(displayList, options = {}) {
40469
40703
  const bmp = renderDisplayListToBitmap(displayList, options);
40470
40704
  return encodeRgbaToPng(bmp.width, bmp.height, bmp.data);
40471
40705
  }
40706
+ function pdfBlendModeToCss(mode) {
40707
+ if (!mode || mode === "Normal" || mode === "Compatible") return void 0;
40708
+ const map = {
40709
+ Multiply: "multiply",
40710
+ Screen: "screen",
40711
+ Overlay: "overlay",
40712
+ Darken: "darken",
40713
+ Lighten: "lighten",
40714
+ ColorDodge: "color-dodge",
40715
+ ColorBurn: "color-burn",
40716
+ HardLight: "hard-light",
40717
+ SoftLight: "soft-light",
40718
+ Difference: "difference",
40719
+ Exclusion: "exclusion",
40720
+ Hue: "hue",
40721
+ Saturation: "saturation",
40722
+ Color: "color",
40723
+ Luminosity: "luminosity"
40724
+ };
40725
+ return map[mode];
40726
+ }
40472
40727
  function escapeXmlText(str) {
40473
40728
  let valid = "";
40474
40729
  for (const char of str) {
@@ -40530,44 +40785,74 @@ function renderDisplayListToSvg(displayList, options = {}) {
40530
40785
  parts.push(`<g transform="matrix(${a} ${b} ${-c} ${-d} ${e + c * displayList.height} ${f + d * displayList.height})">`);
40531
40786
  }
40532
40787
  let clipId = 0;
40533
- for (const original of paintOperations(displayList)) {
40534
- if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40535
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40536
- const clips = original.value.clipPaths ?? [];
40537
- const imageClips = original.value.clipImages ?? [];
40538
- for (const clip of clips) {
40539
- const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
40540
- const id = `text-clip-${clipId++}`;
40541
- const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
40542
- parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40543
- }
40544
- for (const image of imageClips) {
40545
- const id = `image-clip-${clipId++}`;
40546
- 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})">`);
40547
- }
40548
- if (operation.kind === "path") {
40549
- const p = operation.value;
40550
- const pathData = svgPathData(p.segments, displayList.height);
40551
- if (pathData) {
40552
- const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
40553
- const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
40554
- const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
40555
- const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
40556
- const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
40557
- const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
40558
- const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
40559
- const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
40560
- const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
40561
- const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
40562
- const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
40563
- const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
40564
- parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40788
+ const softMaskIds = /* @__PURE__ */ new Map();
40789
+ const appendOperations = (operations) => {
40790
+ for (const original of operations) {
40791
+ if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40792
+ const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40793
+ const clips = original.value.clipPaths ?? [];
40794
+ const imageClips = original.value.clipImages ?? [];
40795
+ const blend = pdfBlendModeToCss(original.value.blendMode);
40796
+ if (blend) parts.push(`<g style="mix-blend-mode:${blend}">`);
40797
+ const softMask = original.value.softMask;
40798
+ if (softMask) {
40799
+ let id = softMaskIds.get(softMask);
40800
+ if (!id) {
40801
+ id = `soft-mask-${clipId++}`;
40802
+ softMaskIds.set(softMask, id);
40803
+ const bitmap = renderSoftMask(softMask, displayList, Math.max(scaleX, scaleY));
40804
+ const image = {
40805
+ name: id,
40806
+ width: bitmap.width,
40807
+ height: bitmap.height,
40808
+ decodedRgba: bitmap.data,
40809
+ matrix: [displayList.width, 0, 0, displayList.height, 0, 0],
40810
+ colorSpace: "DeviceGray",
40811
+ bitsPerComponent: 8
40812
+ };
40813
+ 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>`);
40814
+ }
40815
+ parts.push(`<g mask="url(#${id})">`);
40565
40816
  }
40566
- } else if (operation.kind === "image") {
40567
- parts.push(` ${svgImage(operation.value, displayList.height)}`);
40817
+ for (const clip of clips) {
40818
+ const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
40819
+ const id = `text-clip-${clipId++}`;
40820
+ const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
40821
+ parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40822
+ }
40823
+ for (const image of imageClips) {
40824
+ const id = `image-clip-${clipId++}`;
40825
+ 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})">`);
40826
+ }
40827
+ if (operation.kind === "group") {
40828
+ parts.push(`<g opacity="${operation.value.alpha}" style="isolation:isolate">`);
40829
+ appendOperations(operation.value.operations);
40830
+ parts.push("</g>");
40831
+ } else if (operation.kind === "path") {
40832
+ const p = operation.value;
40833
+ const pathData = svgPathData(p.segments, displayList.height);
40834
+ if (pathData) {
40835
+ const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
40836
+ const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
40837
+ const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
40838
+ const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
40839
+ const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
40840
+ const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
40841
+ const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
40842
+ const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
40843
+ const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
40844
+ const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
40845
+ const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
40846
+ const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
40847
+ parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
40848
+ }
40849
+ } else if (operation.kind === "image") {
40850
+ parts.push(` ${svgImage(operation.value, displayList.height)}`);
40851
+ }
40852
+ for (let i = 0; i < clips.length + imageClips.length + (softMask ? 1 : 0) + (blend ? 1 : 0); i++) parts.push("</g>");
40568
40853
  }
40569
- for (let i = 0; i < clips.length + imageClips.length; i++) parts.push("</g>");
40570
- }
40854
+ };
40855
+ appendOperations(paintOperations(displayList));
40571
40856
  if (displayList.rotation) parts.push("</g>");
40572
40857
  parts.push("</svg>\n");
40573
40858
  return parts.join("\n");
@@ -42200,3 +42485,15 @@ export {
42200
42485
  * Copyright 2012 Mozilla Foundation. Licensed under Apache-2.0.
42201
42486
  * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
42202
42487
  */
42488
+ /*!
42489
+ * Anti-Grain Geometry - Version 2.3
42490
+ * Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
42491
+ *
42492
+ * Permission to copy, use, modify, sell and distribute this software
42493
+ * is granted provided this copyright notice appears in all copies.
42494
+ * This software is provided "as is" without express or implied
42495
+ * warranty, and with no claim as to its suitability for any purpose.
42496
+ *
42497
+ * Adapted from PDFium agg_math_stroke.h and agg_vcgen_stroke.cpp.
42498
+ * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
42499
+ */