@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
@@ -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);
@@ -39288,6 +39364,184 @@ function downscaleImage(image, widthScale, heightScale) {
39288
39364
  }
39289
39365
  return image;
39290
39366
  }
39367
+ var MAX_STROKE_VERTICES = 1e6;
39368
+ function dashSubpath(path, pattern, phase) {
39369
+ const cycle = pattern.reduce((sum, value) => sum + value, 0);
39370
+ if (!(cycle > 0)) return [path];
39371
+ let offset = (phase % cycle + cycle) % cycle, index = 0;
39372
+ while (offset > 0) {
39373
+ if (offset < pattern[index]) break;
39374
+ offset -= pattern[index];
39375
+ index = (index + 1) % pattern.length;
39376
+ }
39377
+ let remaining = pattern[index] - offset;
39378
+ const points = path.closed ? [...path.points, path.points[0]] : path.points;
39379
+ const result = [];
39380
+ let current = [];
39381
+ let steps = 0;
39382
+ const flush = () => {
39383
+ if (current.length) result.push({ points: current, closed: false });
39384
+ current = [];
39385
+ };
39386
+ const advance = (point) => {
39387
+ while (remaining <= 0) {
39388
+ if (++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39389
+ if (index % 2 === 0) {
39390
+ if (pattern[index] === 0) result.push({ points: [point, point], closed: false });
39391
+ flush();
39392
+ }
39393
+ index = (index + 1) % pattern.length;
39394
+ remaining = pattern[index];
39395
+ }
39396
+ };
39397
+ for (let i = 1; i < points.length; i++) {
39398
+ const start = points[i - 1], end = points[i];
39399
+ const dx = end[0] - start[0], dy = end[1] - start[1];
39400
+ const length = Math.hypot(dx, dy);
39401
+ if (!Number.isFinite(length) || length / cycle * pattern.length > MAX_STROKE_VERTICES) {
39402
+ throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39403
+ }
39404
+ let distance = 0;
39405
+ while (distance < length) {
39406
+ const point = [start[0] + dx * distance / length, start[1] + dy * distance / length];
39407
+ advance(point);
39408
+ const step = Math.min(remaining, length - distance);
39409
+ if (distance + step === distance || ++steps > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke dash expansion exceeds the vertex limit");
39410
+ distance += step;
39411
+ remaining -= step;
39412
+ if (index % 2 === 0) {
39413
+ if (!current.length) current.push(point);
39414
+ current.push([start[0] + dx * distance / length, start[1] + dy * distance / length]);
39415
+ }
39416
+ }
39417
+ }
39418
+ flush();
39419
+ if (path.closed && result.length) {
39420
+ const first = result[0], last = result[result.length - 1];
39421
+ const start = path.points[0];
39422
+ const firstPoint = first.points[0], lastPoint = last.points[last.points.length - 1];
39423
+ if (firstPoint[0] === start[0] && firstPoint[1] === start[1] && lastPoint[0] === start[0] && lastPoint[1] === start[1]) {
39424
+ if (first === last) result[0] = { points: first.points, closed: true };
39425
+ else {
39426
+ result[0] = { points: [...last.points, ...first.points.slice(1)], closed: false };
39427
+ result.pop();
39428
+ }
39429
+ }
39430
+ }
39431
+ return result;
39432
+ }
39433
+ function strokeOutlines(paths, width, cap, join, miterLimit, dashArray = [], dashPhase = 0) {
39434
+ const half = width / 2;
39435
+ const contours = [];
39436
+ const pattern = dashArray.length % 2 ? [...dashArray, ...dashArray] : dashArray;
39437
+ let count = 0;
39438
+ let contour = [];
39439
+ const add = (x, y) => {
39440
+ if (++count > MAX_STROKE_VERTICES) throw new PdfError("E_LIMIT", "Stroke outline exceeds the vertex limit");
39441
+ contour.push([x, y]);
39442
+ };
39443
+ const arc = (point, dx1, dy1, dx2, dy2) => {
39444
+ let a1 = Math.atan2(dy1, dx1), a2 = Math.atan2(dy2, dx2);
39445
+ const ccw = a1 - a2 > 0 && a1 - a2 < Math.PI;
39446
+ const step = Math.acos(half / (half + 0.125)) * 2;
39447
+ add(point[0] + dx1, point[1] + dy1);
39448
+ if (step > 0) {
39449
+ if (!ccw) {
39450
+ if (a1 > a2) a2 += 2 * Math.PI;
39451
+ a2 -= step / 4;
39452
+ if ((a2 - a1) / step > MAX_STROKE_VERTICES - count) throw new PdfError("E_LIMIT", "Stroke arc exceeds the vertex limit");
39453
+ for (a1 += step; a1 < a2; a1 += step) add(point[0] + half * Math.cos(a1), point[1] + half * Math.sin(a1));
39454
+ } else {
39455
+ if (a1 < a2) a2 -= 2 * Math.PI;
39456
+ a2 += step / 4;
39457
+ if ((a1 - a2) / step > MAX_STROKE_VERTICES - count) throw new PdfError("E_LIMIT", "Stroke arc exceeds the vertex limit");
39458
+ for (a1 -= step; a1 > a2; a1 -= step) add(point[0] + half * Math.cos(a1), point[1] + half * Math.sin(a1));
39459
+ }
39460
+ }
39461
+ add(point[0] + dx2, point[1] + dy2);
39462
+ };
39463
+ const addCap = (point, next) => {
39464
+ const length = Math.hypot(next[0] - point[0], next[1] - point[1]);
39465
+ const dx = half * (next[1] - point[1]) / length;
39466
+ const dy = half * (next[0] - point[0]) / length;
39467
+ if (cap !== 1) {
39468
+ const sx = cap === 2 ? dy : 0, sy = cap === 2 ? dx : 0;
39469
+ add(point[0] - dx - sx, point[1] + dy - sy);
39470
+ add(point[0] + dx - sx, point[1] - dy - sy);
39471
+ } else {
39472
+ const angle = Math.atan2(dy, -dx);
39473
+ const step = Math.max(1e-3, Math.acos(half / (half + 0.125)) * 2);
39474
+ add(point[0] - dx, point[1] + dy);
39475
+ 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));
39476
+ add(point[0] + dx, point[1] - dy);
39477
+ }
39478
+ };
39479
+ const addJoin = (prev, point, next) => {
39480
+ const len1 = Math.hypot(point[0] - prev[0], point[1] - prev[1]);
39481
+ const len2 = Math.hypot(next[0] - point[0], next[1] - point[1]);
39482
+ const dx1 = half * (point[1] - prev[1]) / len1, dy1 = half * (point[0] - prev[0]) / len1;
39483
+ const dx2 = half * (next[1] - point[1]) / len2, dy2 = half * (next[0] - point[0]) / len2;
39484
+ const inner = (next[0] - point[0]) * (point[1] - prev[1]) - (next[1] - point[1]) * (point[0] - prev[0]) > 0;
39485
+ if (!inner && join === 1) {
39486
+ arc(point, dx1, -dy1, dx2, -dy2);
39487
+ return;
39488
+ }
39489
+ if (inner || join === 0) {
39490
+ const ax = prev[0] + dx1, ay = prev[1] - dy1;
39491
+ const bx = point[0] + dx1, by = point[1] - dy1;
39492
+ const cx = point[0] + dx2, cy = point[1] - dy2;
39493
+ const dx = next[0] + dx2, dy = next[1] - dy2;
39494
+ const den = (bx - ax) * (dy - cy) - (by - ay) * (dx - cx);
39495
+ if (Math.abs(den) >= 1e-30) {
39496
+ const t = ((ay - cy) * (dx - cx) - (ax - cx) * (dy - cy)) / den;
39497
+ const x = ax + (bx - ax) * t, y = ay + (by - ay) * t;
39498
+ if (Math.hypot(x - point[0], y - point[1]) <= half * (inner ? 1.01 : miterLimit)) {
39499
+ add(x, y);
39500
+ return;
39501
+ }
39502
+ } else if ((bx - prev[0]) * dy1 - (prev[1] - by) * dx1 < 0 !== (bx - next[0]) * dy1 - (next[1] - by) * dx1 < 0) {
39503
+ add(bx, by);
39504
+ return;
39505
+ }
39506
+ }
39507
+ add(point[0] + dx1, point[1] - dy1);
39508
+ add(point[0] + dx2, point[1] - dy2);
39509
+ };
39510
+ for (const path of paths) {
39511
+ for (const subpath of pattern.length ? dashSubpath(path, pattern, dashPhase) : [path]) {
39512
+ const points = [];
39513
+ for (const point of subpath.points) {
39514
+ const prev = points[points.length - 1];
39515
+ if (!prev || Math.hypot(prev[0] - point[0], prev[1] - point[1]) > 1e-14) points.push(point);
39516
+ }
39517
+ let closed = subpath.closed;
39518
+ 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();
39519
+ if (points.length < 3) closed = false;
39520
+ if (points.length === 1 && subpath.points.length > 1 && cap === 1) {
39521
+ contour = [];
39522
+ const [x, y] = points[0];
39523
+ addCap([x, y], [x + 1, y]);
39524
+ addCap([x, y], [x - 1, y]);
39525
+ contours.push(contour);
39526
+ } else if (points.length >= 2) {
39527
+ contour = [];
39528
+ if (!closed) addCap(points[0], points[1]);
39529
+ for (let i = closed ? 0 : 1; i < points.length - (closed ? 0 : 1); i++) {
39530
+ addJoin(points[(i + points.length - 1) % points.length], points[i], points[(i + 1) % points.length]);
39531
+ }
39532
+ if (closed) {
39533
+ contours.push(contour);
39534
+ contour = [];
39535
+ } else addCap(points[points.length - 1], points[points.length - 2]);
39536
+ for (let i = points.length - (closed ? 1 : 2); i >= (closed ? 0 : 1); i--) {
39537
+ addJoin(points[(i + 1) % points.length], points[i], points[(i + points.length - 1) % points.length]);
39538
+ }
39539
+ contours.push(contour);
39540
+ }
39541
+ }
39542
+ }
39543
+ return contours;
39544
+ }
39291
39545
  function encodePng(bitmap) {
39292
39546
  return encodeRgbaToPng(bitmap.width, bitmap.height, bitmap.data);
39293
39547
  }
@@ -40378,111 +40632,60 @@ function blendPixel(rgba, width, height, px, py, color, alpha, blendMode, clipMa
40378
40632
  rgba[idx + 2] = Math.round((effB * a + cbB * dstA * (1 - a)) / outA * 255);
40379
40633
  rgba[idx + 3] = Math.round(outA * 255);
40380
40634
  }
40381
- function drawAntiAliasedSegment(rgba, width, height, x0, y0, x1, y1, strokeWidth, color, alpha = 1, lineCap = 0, antialias = true, blendMode, clipMask) {
40382
- const halfW = Math.max(0.6, strokeWidth * 0.5);
40383
- const dx = x1 - x0;
40384
- const dy = y1 - y0;
40385
- const lenSq = dx * dx + dy * dy;
40386
- const segLen = Math.sqrt(lenSq);
40387
- const pad = lineCap === 2 ? halfW + 2 : halfW + 1;
40388
- const minX = Math.max(0, Math.floor(Math.min(x0, x1) - pad));
40389
- const maxX = Math.min(width - 1, Math.ceil(Math.max(x0, x1) + pad));
40390
- const minY = Math.max(0, Math.floor(Math.min(y0, y1) - pad));
40391
- const maxY = Math.min(height - 1, Math.ceil(Math.max(y0, y1) + pad));
40392
- for (let py = minY; py <= maxY; py++) {
40393
- for (let px = minX; px <= maxX; px++) {
40394
- const cx = px + 0.5;
40395
- const cy = py + 0.5;
40396
- if (segLen > 1e-6 && (lineCap === 0 || lineCap === 2)) {
40397
- const ux = dx / segLen;
40398
- const uy = dy / segLen;
40399
- const along = (cx - x0) * ux + (cy - y0) * uy;
40400
- const perp = Math.abs(-(cx - x0) * uy + (cy - y0) * ux);
40401
- const minAlong = lineCap === 2 ? -halfW : 0;
40402
- const maxAlong = lineCap === 2 ? segLen + halfW : segLen;
40403
- const overAlong = along < minAlong ? minAlong - along : along > maxAlong ? along - maxAlong : 0;
40404
- const dist2 = overAlong > 0 ? Math.max(perp, halfW + overAlong) : perp;
40405
- if (dist2 <= halfW + 0.75) {
40406
- const cov = antialias ? Math.max(0, Math.min(1, halfW + 0.5 - dist2)) : dist2 <= halfW + 0.25 ? 1 : 0;
40407
- blendPixel(rgba, width, height, px, py, color, cov * alpha, blendMode, clipMask);
40408
- }
40409
- continue;
40410
- }
40411
- let t = lenSq > 1e-6 ? ((cx - x0) * dx + (cy - y0) * dy) / lenSq : 0;
40412
- t = Math.max(0, Math.min(1, t));
40413
- const projX = x0 + t * dx;
40414
- const projY = y0 + t * dy;
40415
- const dist = Math.hypot(cx - projX, cy - projY);
40416
- if (dist <= halfW + 0.75) {
40417
- const cov = antialias ? Math.max(0, Math.min(1, halfW + 0.5 - dist)) : dist <= halfW + 0.25 ? 1 : 0;
40418
- blendPixel(rgba, width, height, px, py, color, cov * alpha, blendMode, clipMask);
40419
- }
40420
- }
40421
- }
40422
- }
40423
- function segmentsToScreenEdges(segments, pageHeight, scale, closeSubpaths = false) {
40424
- const edges = [];
40425
- let curX = 0;
40426
- let curY = 0;
40427
- let startX = 0;
40428
- let startY = 0;
40429
- let hasOpenSubpath = false;
40635
+ function segmentsToScreenPaths(segments, pageHeight, scale) {
40636
+ const paths = [];
40637
+ let points = [];
40638
+ let current = [0, 0];
40430
40639
  const toScreen = (x, y) => [x * scale, (pageHeight - y) * scale];
40431
- for (const seg of segments) {
40432
- if (seg.kind === "move") {
40433
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
40434
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
40435
- }
40436
- [curX, curY] = toScreen(seg.x, seg.y);
40437
- startX = curX;
40438
- startY = curY;
40439
- hasOpenSubpath = false;
40440
- } else if (seg.kind === "line") {
40441
- const [nx, ny] = toScreen(seg.x, seg.y);
40442
- edges.push({ x0: curX, y0: curY, x1: nx, y1: ny });
40443
- curX = nx;
40444
- curY = ny;
40445
- hasOpenSubpath = true;
40446
- } else if (seg.kind === "cubic") {
40447
- const [p1x, p1y] = toScreen(seg.x1, seg.y1);
40448
- const [p2x, p2y] = toScreen(seg.x2, seg.y2);
40449
- const [p3x, p3y] = toScreen(seg.x, seg.y);
40450
- const points = flattenCubic(curX, curY, p1x, p1y, p2x, p2y, p3x, p3y);
40451
- let px = curX;
40452
- let py = curY;
40453
- for (let i = 1; i < points.length; i++) {
40454
- const [qx, qy] = points[i];
40455
- edges.push({ x0: px, y0: py, x1: qx, y1: qy });
40456
- px = qx;
40457
- py = qy;
40458
- }
40459
- curX = p3x;
40460
- curY = p3y;
40461
- hasOpenSubpath = true;
40462
- } else if (seg.kind === "close") {
40463
- if (curX !== startX || curY !== startY) {
40464
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
40465
- curX = startX;
40466
- curY = startY;
40467
- }
40468
- hasOpenSubpath = false;
40469
- } else if (seg.kind === "rect") {
40470
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
40471
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
40472
- }
40473
- const [rx0, ry0] = toScreen(seg.x, seg.y);
40474
- const [rx1, ry1] = toScreen(seg.x + seg.width, seg.y + seg.height);
40475
- edges.push(
40476
- { x0: rx0, y0: ry0, x1: rx1, y1: ry0 },
40477
- { x0: rx1, y0: ry0, x1: rx1, y1: ry1 },
40478
- { x0: rx1, y0: ry1, x1: rx0, y1: ry1 },
40479
- { x0: rx0, y0: ry1, x1: rx0, y1: ry0 }
40480
- );
40481
- hasOpenSubpath = false;
40640
+ for (const segment of segments) {
40641
+ if (segment.kind === "move") {
40642
+ if (points.length) paths.push({ points, closed: false });
40643
+ current = toScreen(segment.x, segment.y);
40644
+ points = [current];
40645
+ } else if (segment.kind === "line") {
40646
+ if (!points.length) points = [current];
40647
+ current = toScreen(segment.x, segment.y);
40648
+ points.push(current);
40649
+ } else if (segment.kind === "cubic") {
40650
+ if (!points.length) points = [current];
40651
+ const a = toScreen(segment.x1, segment.y1), b = toScreen(segment.x2, segment.y2);
40652
+ const end = toScreen(segment.x, segment.y);
40653
+ const curve = flattenCubic(current[0], current[1], a[0], a[1], b[0], b[1], end[0], end[1]);
40654
+ for (let i = 1; i < curve.length; i++) points.push(curve[i]);
40655
+ current = end;
40656
+ } else if (segment.kind === "close") {
40657
+ if (points.length) {
40658
+ paths.push({ points, closed: true });
40659
+ current = points[0];
40660
+ points = [];
40661
+ }
40662
+ } else if (segment.kind === "rect") {
40663
+ if (points.length) paths.push({ points, closed: false });
40664
+ const first = toScreen(segment.x, segment.y);
40665
+ paths.push({ points: [
40666
+ first,
40667
+ toScreen(segment.x + segment.width, segment.y),
40668
+ toScreen(segment.x + segment.width, segment.y + segment.height),
40669
+ toScreen(segment.x, segment.y + segment.height)
40670
+ ], closed: true });
40671
+ current = first;
40672
+ points = [];
40673
+ }
40674
+ }
40675
+ if (points.length) paths.push({ points, closed: false });
40676
+ return paths;
40677
+ }
40678
+ function pathsToEdges(paths, closeSubpaths = false) {
40679
+ const edges = [];
40680
+ for (const { points, closed } of paths) {
40681
+ for (let i = 1; i < points.length; i++) {
40682
+ const a = points[i - 1], b = points[i];
40683
+ edges.push({ x0: a[0], y0: a[1], x1: b[0], y1: b[1] });
40684
+ }
40685
+ if ((closed || closeSubpaths) && points.length > 1) {
40686
+ const a = points[points.length - 1], b = points[0];
40687
+ edges.push({ x0: a[0], y0: a[1], x1: b[0], y1: b[1] });
40482
40688
  }
40483
- }
40484
- if (closeSubpaths && hasOpenSubpath && (curX !== startX || curY !== startY)) {
40485
- edges.push({ x0: curX, y0: curY, x1: startX, y1: startY });
40486
40689
  }
40487
40690
  return edges;
40488
40691
  }
@@ -40593,6 +40796,30 @@ function paintOperations(displayList) {
40593
40796
  ...displayList.glyphs.map((value) => ({ kind: "glyph", value }))
40594
40797
  ];
40595
40798
  }
40799
+ function renderSoftMask(mask, displayList, scale) {
40800
+ const bitmap = renderDisplayListToBitmap({
40801
+ ...displayList,
40802
+ rotation: 0,
40803
+ glyphs: [],
40804
+ paths: [],
40805
+ images: [],
40806
+ operations: mask.operations
40807
+ }, { scale, transparent: true });
40808
+ const { data } = bitmap;
40809
+ for (let i = 0; i < data.length; i += 4) {
40810
+ let value = data[i + 3];
40811
+ if (mask.subtype === "Luminosity") {
40812
+ const alpha = value / 255;
40813
+ const r = Math.round(data[i] * alpha + mask.backdrop.r * 255 * (1 - alpha));
40814
+ const g = Math.round(data[i + 1] * alpha + mask.backdrop.g * 255 * (1 - alpha));
40815
+ const b = Math.round(data[i + 2] * alpha + mask.backdrop.b * 255 * (1 - alpha));
40816
+ value = Math.round(pdfLum(r, g, b));
40817
+ }
40818
+ data[i] = data[i + 1] = data[i + 2] = 0;
40819
+ data[i + 3] = mask.transferMap?.[value] ?? value;
40820
+ }
40821
+ return bitmap;
40822
+ }
40596
40823
  function renderDisplayListToBitmap(displayList, options = {}) {
40597
40824
  const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
40598
40825
  const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
@@ -40616,10 +40843,28 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40616
40843
  const aaTxt = options.antialiasText !== false;
40617
40844
  let cachedClips;
40618
40845
  let cachedClipMask;
40846
+ let cachedSoftMask;
40847
+ let cachedSoftMaskPixels;
40619
40848
  const imageClipMasks = /* @__PURE__ */ new Map();
40620
40849
  for (const original of paintOperations(displayList)) {
40621
40850
  if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40622
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40851
+ let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40852
+ if (operation.kind === "group") {
40853
+ const group = operation.value;
40854
+ const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations: group.operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, transparent: true });
40855
+ for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
40856
+ operation = { kind: "image", value: {
40857
+ name: "TransparencyGroup",
40858
+ width: bitmap.width,
40859
+ height: bitmap.height,
40860
+ decodedRgba: bitmap.data,
40861
+ matrix: [bitmap.width / scale, 0, 0, bitmap.height / scale, 0, displayList.height - bitmap.height / scale],
40862
+ colorSpace: "DeviceRGB",
40863
+ bitsPerComponent: 8,
40864
+ blendMode: group.blendMode,
40865
+ clipRect: group.clipRect
40866
+ } };
40867
+ }
40623
40868
  const clips = original.value.clipPaths;
40624
40869
  let clipMask = clips && clips === cachedClips ? cachedClipMask : void 0;
40625
40870
  if (clips && !clipMask) {
@@ -40627,12 +40872,25 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40627
40872
  for (const clip of clips) {
40628
40873
  const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
40629
40874
  const layer = new Uint8Array(width * height * 4);
40630
- fillEdgesScanline4x4(layer, width, height, segmentsToScreenEdges(segments, displayList.height, scale, true), { r: 1, g: 1, b: 1 }, 1, fillRule);
40875
+ fillEdgesScanline4x4(layer, width, height, pathsToEdges(segmentsToScreenPaths(segments, displayList.height, scale), true), { r: 1, g: 1, b: 1 }, 1, fillRule);
40631
40876
  for (let i = 3; i < layer.length; i += 4) clipMask[i] = Math.round(clipMask[i] * layer[i] / 255);
40632
40877
  }
40633
40878
  cachedClips = clips;
40634
40879
  cachedClipMask = clipMask;
40635
40880
  }
40881
+ const softMask = original.value.softMask;
40882
+ if (softMask) {
40883
+ if (softMask !== cachedSoftMask) {
40884
+ cachedSoftMaskPixels = renderSoftMask(softMask, displayList, scale).data;
40885
+ cachedSoftMask = softMask;
40886
+ }
40887
+ if (clipMask) {
40888
+ clipMask = clipMask.slice();
40889
+ for (let i = 3; i < clipMask.length; i += 4) clipMask[i] = Math.round(clipMask[i] * cachedSoftMaskPixels[i] / 255);
40890
+ } else {
40891
+ clipMask = cachedSoftMaskPixels;
40892
+ }
40893
+ }
40636
40894
  const imageClips = original.value.clipImages;
40637
40895
  if (imageClips) {
40638
40896
  let imageMask = imageClipMasks.get(imageClips);
@@ -40661,62 +40919,38 @@ function renderDisplayListToBitmap(displayList, options = {}) {
40661
40919
  if (operation.kind === "path") {
40662
40920
  const path = operation.value;
40663
40921
  if (path.fillColor) {
40664
- const edges = segmentsToScreenEdges(path.segments, displayList.height, scale, true);
40922
+ const edges = pathsToEdges(segmentsToScreenPaths(path.segments, displayList.height, scale), true);
40665
40923
  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;
40666
40924
  fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
40667
40925
  }
40668
40926
  if (path.strokeColor) {
40669
- const edges = segmentsToScreenEdges(path.segments, displayList.height, scale, false);
40670
40927
  const rawSw = path.strokeWidth * scale;
40671
40928
  const sw = Math.max(1, rawSw);
40672
40929
  const strokeAlpha = options.thinLineMode === "shape" && rawSw < 1 ? (path.strokeAlpha ?? 1) * Math.max(0.25, rawSw) : path.strokeAlpha ?? 1;
40673
- const dashArr = path.dashArray && path.dashArray.length > 0 ? path.dashArray.map((d) => Math.max(0, d * scale)) : void 0;
40674
- const dashCycle = dashArr ? dashArr.reduce((a, b) => a + b, 0) : 0;
40675
- let dashDist = (path.dashPhase ?? 0) * scale % (dashCycle || 1);
40676
- if (dashDist < 0) dashDist += dashCycle;
40677
- for (const e of edges) {
40678
- if (!dashArr || dashCycle <= 1e-4) {
40679
- 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);
40680
- } else {
40681
- const dx = e.x1 - e.x0;
40682
- const dy = e.y1 - e.y0;
40683
- const edgeLen = Math.hypot(dx, dy);
40684
- if (edgeLen <= 1e-4) continue;
40685
- let pos = 0;
40686
- while (pos < edgeLen) {
40687
- let cycleRem = dashDist % dashCycle;
40688
- let dIdx = 0;
40689
- while (dIdx < dashArr.length - 1 && cycleRem >= dashArr[dIdx]) {
40690
- cycleRem -= dashArr[dIdx];
40691
- dIdx++;
40692
- }
40693
- const segRemainInDash = Math.max(1e-4, dashArr[dIdx] - cycleRem);
40694
- const step = Math.min(edgeLen - pos, segRemainInDash);
40695
- if (dIdx % 2 === 0) {
40696
- const t0 = pos / edgeLen;
40697
- const t1 = (pos + step) / edgeLen;
40698
- drawAntiAliasedSegment(
40699
- rgba,
40700
- width,
40701
- height,
40702
- e.x0 + dx * t0,
40703
- e.y0 + dy * t0,
40704
- e.x0 + dx * t1,
40705
- e.y0 + dy * t1,
40706
- sw,
40707
- path.strokeColor,
40708
- strokeAlpha,
40709
- path.lineCap ?? 0,
40710
- original.kind === "glyph" ? aaTxt : aaVec,
40711
- path.blendMode,
40712
- clipMask
40713
- );
40714
- }
40715
- pos += step;
40716
- dashDist = (dashDist + step) % dashCycle;
40717
- }
40718
- }
40719
- }
40930
+ const contours = strokeOutlines(
40931
+ segmentsToScreenPaths(path.segments, displayList.height, scale),
40932
+ sw,
40933
+ path.lineCap ?? 0,
40934
+ path.lineJoin ?? 0,
40935
+ path.miterLimit ?? 10,
40936
+ path.dashArray?.map((value) => Math.max(0, value * scale)),
40937
+ (path.dashPhase ?? 0) * scale
40938
+ );
40939
+ const edges = pathsToEdges(contours.map((points) => ({ points, closed: true })));
40940
+ 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;
40941
+ fillEdgesScanline4x4(
40942
+ rgba,
40943
+ width,
40944
+ height,
40945
+ edges,
40946
+ path.strokeColor,
40947
+ strokeAlpha,
40948
+ "nonzero",
40949
+ clipScreen,
40950
+ original.kind === "glyph" ? aaTxt : aaVec,
40951
+ path.blendMode,
40952
+ clipMask
40953
+ );
40720
40954
  }
40721
40955
  } else if (operation.kind === "image") {
40722
40956
  const img = operation.value;
@@ -40814,6 +41048,27 @@ function renderDisplayListToPng(displayList, options = {}) {
40814
41048
  const bmp = renderDisplayListToBitmap(displayList, options);
40815
41049
  return encodeRgbaToPng(bmp.width, bmp.height, bmp.data);
40816
41050
  }
41051
+ function pdfBlendModeToCss(mode) {
41052
+ if (!mode || mode === "Normal" || mode === "Compatible") return void 0;
41053
+ const map = {
41054
+ Multiply: "multiply",
41055
+ Screen: "screen",
41056
+ Overlay: "overlay",
41057
+ Darken: "darken",
41058
+ Lighten: "lighten",
41059
+ ColorDodge: "color-dodge",
41060
+ ColorBurn: "color-burn",
41061
+ HardLight: "hard-light",
41062
+ SoftLight: "soft-light",
41063
+ Difference: "difference",
41064
+ Exclusion: "exclusion",
41065
+ Hue: "hue",
41066
+ Saturation: "saturation",
41067
+ Color: "color",
41068
+ Luminosity: "luminosity"
41069
+ };
41070
+ return map[mode];
41071
+ }
40817
41072
  function escapeXmlText(str) {
40818
41073
  let valid = "";
40819
41074
  for (const char of str) {
@@ -40875,44 +41130,74 @@ function renderDisplayListToSvg(displayList, options = {}) {
40875
41130
  parts.push(`<g transform="matrix(${a} ${b} ${-c} ${-d} ${e + c * displayList.height} ${f + d * displayList.height})">`);
40876
41131
  }
40877
41132
  let clipId = 0;
40878
- for (const original of paintOperations(displayList)) {
40879
- if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
40880
- const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
40881
- const clips = original.value.clipPaths ?? [];
40882
- const imageClips = original.value.clipImages ?? [];
40883
- for (const clip of clips) {
40884
- const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
40885
- const id = `text-clip-${clipId++}`;
40886
- const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
40887
- parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
40888
- }
40889
- for (const image of imageClips) {
40890
- const id = `image-clip-${clipId++}`;
40891
- 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})">`);
40892
- }
40893
- if (operation.kind === "path") {
40894
- const p = operation.value;
40895
- const pathData = svgPathData(p.segments, displayList.height);
40896
- if (pathData) {
40897
- const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
40898
- const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
40899
- const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
40900
- const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
40901
- const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
40902
- const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
40903
- const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
40904
- const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
40905
- const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
40906
- const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
40907
- const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
40908
- const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
40909
- parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
41133
+ const softMaskIds = /* @__PURE__ */ new Map();
41134
+ const appendOperations = (operations) => {
41135
+ for (const original of operations) {
41136
+ if (original.kind === "glyph" && (original.value.renderMode === 3 || !original.value.outline && !original.value.unicode.trim())) continue;
41137
+ const operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
41138
+ const clips = original.value.clipPaths ?? [];
41139
+ const imageClips = original.value.clipImages ?? [];
41140
+ const blend = pdfBlendModeToCss(original.value.blendMode);
41141
+ if (blend) parts.push(`<g style="mix-blend-mode:${blend}">`);
41142
+ const softMask = original.value.softMask;
41143
+ if (softMask) {
41144
+ let id = softMaskIds.get(softMask);
41145
+ if (!id) {
41146
+ id = `soft-mask-${clipId++}`;
41147
+ softMaskIds.set(softMask, id);
41148
+ const bitmap = renderSoftMask(softMask, displayList, Math.max(scaleX, scaleY));
41149
+ const image = {
41150
+ name: id,
41151
+ width: bitmap.width,
41152
+ height: bitmap.height,
41153
+ decodedRgba: bitmap.data,
41154
+ matrix: [displayList.width, 0, 0, displayList.height, 0, 0],
41155
+ colorSpace: "DeviceGray",
41156
+ bitsPerComponent: 8
41157
+ };
41158
+ 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>`);
41159
+ }
41160
+ parts.push(`<g mask="url(#${id})">`);
40910
41161
  }
40911
- } else if (operation.kind === "image") {
40912
- parts.push(` ${svgImage(operation.value, displayList.height)}`);
41162
+ for (const clip of clips) {
41163
+ const { segments, fillRule } = "segments" in clip ? clip : { segments: clip, fillRule: "nonzero" };
41164
+ const id = `text-clip-${clipId++}`;
41165
+ const path = `<path d="${svgPathData(segments, displayList.height)}" clip-rule="${fillRule}"/>`;
41166
+ parts.push(`<defs><clipPath id="${id}" clipPathUnits="userSpaceOnUse">${path}</clipPath></defs><g clip-path="url(#${id})">`);
41167
+ }
41168
+ for (const image of imageClips) {
41169
+ const id = `image-clip-${clipId++}`;
41170
+ 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})">`);
41171
+ }
41172
+ if (operation.kind === "group") {
41173
+ parts.push(`<g opacity="${operation.value.alpha}" style="isolation:isolate">`);
41174
+ appendOperations(operation.value.operations);
41175
+ parts.push("</g>");
41176
+ } else if (operation.kind === "path") {
41177
+ const p = operation.value;
41178
+ const pathData = svgPathData(p.segments, displayList.height);
41179
+ if (pathData) {
41180
+ const fill = p.fillColor ? `rgb(${Math.round(p.fillColor.r * 255)},${Math.round(p.fillColor.g * 255)},${Math.round(p.fillColor.b * 255)})` : "none";
41181
+ const stroke = p.strokeColor ? `rgb(${Math.round(p.strokeColor.r * 255)},${Math.round(p.strokeColor.g * 255)},${Math.round(p.strokeColor.b * 255)})` : "none";
41182
+ const fillRuleAttr = p.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
41183
+ const fillOpacityAttr = p.fillAlpha !== void 0 && p.fillAlpha < 1 ? ` fill-opacity="${p.fillAlpha}"` : "";
41184
+ const strokeOpacityAttr = p.strokeAlpha !== void 0 && p.strokeAlpha < 1 ? ` stroke-opacity="${p.strokeAlpha}"` : "";
41185
+ const strokeWidthAttr = p.strokeWidth <= 0 ? ` stroke-width="1" vector-effect="non-scaling-stroke"` : ` stroke-width="${p.strokeWidth}"`;
41186
+ const lineCapAttr = p.lineCap === 1 ? ` stroke-linecap="round"` : p.lineCap === 2 ? ` stroke-linecap="square"` : "";
41187
+ const lineJoinAttr = p.lineJoin === 1 ? ` stroke-linejoin="round"` : p.lineJoin === 2 ? ` stroke-linejoin="bevel"` : "";
41188
+ const miterLimitAttr = p.miterLimit !== void 0 && p.miterLimit !== 10 ? ` stroke-miterlimit="${p.miterLimit}"` : "";
41189
+ const dashArrayAttr = p.dashArray && p.dashArray.length > 0 ? ` stroke-dasharray="${p.dashArray.join(" ")}"` : "";
41190
+ const dashOffsetAttr = p.dashPhase ? ` stroke-dashoffset="${p.dashPhase}"` : "";
41191
+ const labelAttr = original.kind === "glyph" ? ` aria-label="${escapeXmlText(original.value.unicode)}"` : "";
41192
+ parts.push(` <path${labelAttr} d="${pathData}" fill="${fill}"${fillRuleAttr}${fillOpacityAttr} stroke="${stroke}"${strokeOpacityAttr}${strokeWidthAttr}${lineCapAttr}${lineJoinAttr}${miterLimitAttr}${dashArrayAttr}${dashOffsetAttr}/>`);
41193
+ }
41194
+ } else if (operation.kind === "image") {
41195
+ parts.push(` ${svgImage(operation.value, displayList.height)}`);
41196
+ }
41197
+ for (let i = 0; i < clips.length + imageClips.length + (softMask ? 1 : 0) + (blend ? 1 : 0); i++) parts.push("</g>");
40913
41198
  }
40914
- for (let i = 0; i < clips.length + imageClips.length; i++) parts.push("</g>");
40915
- }
41199
+ };
41200
+ appendOperations(paintOperations(displayList));
40916
41201
  if (displayList.rotation) parts.push("</g>");
40917
41202
  parts.push("</svg>\n");
40918
41203
  return parts.join("\n");
@@ -44330,3 +44615,15 @@ export {
44330
44615
  * Copyright 2012 Mozilla Foundation. Licensed under Apache-2.0.
44331
44616
  * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
44332
44617
  */
44618
+ /*!
44619
+ * Anti-Grain Geometry - Version 2.3
44620
+ * Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
44621
+ *
44622
+ * Permission to copy, use, modify, sell and distribute this software
44623
+ * is granted provided this copyright notice appears in all copies.
44624
+ * This software is provided "as is" without express or implied
44625
+ * warranty, and with no claim as to its suitability for any purpose.
44626
+ *
44627
+ * Adapted from PDFium agg_math_stroke.h and agg_vcgen_stroke.cpp.
44628
+ * See THIRD_PARTY_NOTICES.md for the source revision and adaptations.
44629
+ */