@poe-platform/safe-bash 0.1.780 → 0.1.782

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.
@@ -22419,7 +22419,7 @@ function cosString(value, span) {
22419
22419
  if (typeof value === "string") {
22420
22420
  let needsUtf16 = false;
22421
22421
  for (let i = 0; i < value.length; i++) {
22422
- if (value.charCodeAt(i) > 255) {
22422
+ if (!PDF_DOC_ENCODING_REVERSE.has(value.charCodeAt(i))) {
22423
22423
  needsUtf16 = true;
22424
22424
  break;
22425
22425
  }
@@ -22437,7 +22437,7 @@ function cosString(value, span) {
22437
22437
  }
22438
22438
  const bytes = new Uint8Array(value.length);
22439
22439
  for (let i = 0; i < value.length; i++) {
22440
- bytes[i] = value.charCodeAt(i) & 255;
22440
+ bytes[i] = PDF_DOC_ENCODING_REVERSE.get(value.charCodeAt(i));
22441
22441
  }
22442
22442
  return { kind: "string", format: "literal", bytes, span };
22443
22443
  }
@@ -22584,6 +22584,9 @@ var PDF_DOC_ENCODING_MAP = {
22584
22584
  160: 8364,
22585
22585
  173: 65533
22586
22586
  };
22587
+ var PDF_DOC_ENCODING_REVERSE = new Map(
22588
+ Array.from({ length: 256 }, (_, byte) => [PDF_DOC_ENCODING_MAP[byte] ?? byte, byte])
22589
+ );
22587
22590
  function decodeUtf16UnitsWithSurrogateCheck(units) {
22588
22591
  let out = "";
22589
22592
  for (let i = 0; i < units.length; i++) {
@@ -29933,6 +29936,7 @@ var CosByteLexer = class {
29933
29936
  const start = this.pos;
29934
29937
  this.pos++;
29935
29938
  let depth = 1;
29939
+ let recovery;
29936
29940
  const out = [];
29937
29941
  while (this.pos < this.end && depth > 0) {
29938
29942
  const b = this.bytes[this.pos++];
@@ -29967,7 +29971,15 @@ var CosByteLexer = class {
29967
29971
  out.push(b);
29968
29972
  } else if (b === 41) {
29969
29973
  depth--;
29970
- if (depth > 0) out.push(b);
29974
+ if (depth > 0) {
29975
+ const next = this.bytes[this.pos];
29976
+ const afterLine = next === 13 && this.bytes[this.pos + 1] === 10 ? this.pos + 2 : this.pos + 1;
29977
+ const delimiter = this.bytes[afterLine];
29978
+ if (!recovery && this.pos + 2 < this.end && (next === 10 || next === 13) && (delimiter === 47 || delimiter === 62)) {
29979
+ recovery = { offset: this.pos, length: out.length };
29980
+ }
29981
+ out.push(b);
29982
+ }
29971
29983
  } else if (b === 13) {
29972
29984
  if (this.pos < this.end && this.bytes[this.pos] === 10) this.pos++;
29973
29985
  out.push(10);
@@ -29978,6 +29990,10 @@ var CosByteLexer = class {
29978
29990
  throw new PdfError("E_LIMIT", "PDF literal string exceeds maximum byte length");
29979
29991
  }
29980
29992
  }
29993
+ if (depth > 0 && recovery) {
29994
+ this.pos = recovery.offset;
29995
+ out.length = recovery.length;
29996
+ }
29981
29997
  return {
29982
29998
  kind: "string",
29983
29999
  bytes: Uint8Array.from(out),
@@ -34948,6 +34964,7 @@ function evaluateContentStreamToDisplayList(params) {
34948
34964
  };
34949
34965
  const initialState = {
34950
34966
  ctm: [1, 0, 0, 1, 0, 0],
34967
+ initialCtm: [1, 0, 0, 1, 0, 0],
34951
34968
  strokeColor: { r: 0, g: 0, b: 0 },
34952
34969
  fillColor: { r: 0, g: 0, b: 0 },
34953
34970
  strokeAlpha: 1,
@@ -35245,6 +35262,116 @@ function evaluateContentStreamToDisplayList(params) {
35245
35262
  ] }], void 0, void 0, resources, activeFonts, depth);
35246
35263
  stateStack.pop();
35247
35264
  };
35265
+ const paintPattern = (segments, fillRule, resources, activeFonts, depth, mcid, actualText) => {
35266
+ const st = curState(), doc = params.cosDoc;
35267
+ if (!st.fillPatternName || !doc || !resources) return false;
35268
+ if (depth >= 8) throw new PdfError("E_LIMIT", "Pattern nesting exceeds the form depth limit");
35269
+ const patterns = doc.resolveDict(dictGet(resources, "Pattern"));
35270
+ const pattern = patterns && doc.resolve(dictGet(patterns, st.fillPatternName));
35271
+ const dict = pattern?.kind === "stream" ? pattern.dict : pattern?.kind === "dict" ? pattern : void 0;
35272
+ if (!dict) return false;
35273
+ const nums = (key, fallback) => {
35274
+ const array = doc.resolveArray(dictGet(dict, key));
35275
+ return array ? array.items.map((item, i) => {
35276
+ const value = doc.resolve(item);
35277
+ return value?.kind === "number" ? value.value : fallback[i] ?? 0;
35278
+ }) : fallback;
35279
+ };
35280
+ let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
35281
+ const include = (x, y) => {
35282
+ x0 = Math.min(x0, x);
35283
+ y0 = Math.min(y0, y);
35284
+ x1 = Math.max(x1, x);
35285
+ y1 = Math.max(y1, y);
35286
+ };
35287
+ for (const segment of segments) {
35288
+ if (segment.kind === "close") continue;
35289
+ include(segment.x, segment.y);
35290
+ if (segment.kind === "cubic") {
35291
+ include(segment.x1, segment.y1);
35292
+ include(segment.x2, segment.y2);
35293
+ }
35294
+ if (segment.kind === "rect") include(segment.x + segment.width, segment.y + segment.height);
35295
+ }
35296
+ const [originX, originY] = params.origin ?? [0, 0];
35297
+ const clip = st.clipRect ?? [originX, originY, originX + params.width, originY + params.height];
35298
+ const bounds = [Math.max(x0, clip[0]), Math.max(y0, clip[1]), Math.min(x1, clip[2]), Math.min(y1, clip[3])];
35299
+ if (!(bounds[2] > bounds[0] && bounds[3] > bounds[1])) return true;
35300
+ const matrix = multiplyMatrices(nums("Matrix", [1, 0, 0, 1, 0, 0]), st.initialCtm);
35301
+ const type = doc.resolve(dictGet(dict, "PatternType"));
35302
+ stateStack.push({ ...st, clipRect: bounds, clipPaths: [...st.clipPaths ?? [], { segments, fillRule }] });
35303
+ try {
35304
+ if (type?.kind === "number" && type.value === 2) {
35305
+ const shading = doc.resolve(dictGet(dict, "Shading"));
35306
+ const shadingDict = shading?.kind === "stream" ? shading.dict : shading?.kind === "dict" ? shading : void 0;
35307
+ if (!shadingDict) return false;
35308
+ const image = renderShadingDictToImage(
35309
+ doc,
35310
+ shadingDict,
35311
+ matrix,
35312
+ bounds,
35313
+ st.fillAlpha,
35314
+ "PatternShading_" + st.fillPatternName,
35315
+ bounds,
35316
+ shading?.kind === "stream" ? shading : void 0,
35317
+ st.blendMode
35318
+ );
35319
+ if (image) emit({ kind: "image", value: image });
35320
+ return !!image;
35321
+ }
35322
+ if (pattern?.kind !== "stream") return false;
35323
+ const xStepNode = doc.resolve(dictGet(dict, "XStep"));
35324
+ const yStepNode = doc.resolve(dictGet(dict, "YStep"));
35325
+ const xStep = xStepNode?.kind === "number" ? Math.abs(xStepNode.value) : 0;
35326
+ const yStep = yStepNode?.kind === "number" ? Math.abs(yStepNode.value) : 0;
35327
+ const determinant = matrix[0] * matrix[3] - matrix[1] * matrix[2];
35328
+ if (!xStep || !yStep || !determinant) return true;
35329
+ const inverse = [
35330
+ matrix[3] / determinant,
35331
+ -matrix[1] / determinant,
35332
+ -matrix[2] / determinant,
35333
+ matrix[0] / determinant,
35334
+ (matrix[2] * matrix[5] - matrix[3] * matrix[4]) / determinant,
35335
+ (matrix[1] * matrix[4] - matrix[0] * matrix[5]) / determinant
35336
+ ];
35337
+ const corners = [[bounds[0], bounds[1]], [bounds[2], bounds[1]], [bounds[2], bounds[3]], [bounds[0], bounds[3]]].map(([x, y]) => transformPoint(inverse, x, y));
35338
+ const box = nums("BBox", [0, 0, xStep, yStep]);
35339
+ const ix0 = Math.floor((Math.min(...corners.map((p) => p[0])) - box[2]) / xStep) + 1;
35340
+ const ix1 = Math.ceil((Math.max(...corners.map((p) => p[0])) - box[0]) / xStep) - 1;
35341
+ const iy0 = Math.floor((Math.min(...corners.map((p) => p[1])) - box[3]) / yStep) + 1;
35342
+ const iy1 = Math.ceil((Math.max(...corners.map((p) => p[1])) - box[1]) / yStep) - 1;
35343
+ if ((ix1 - ix0 + 1) * (iy1 - iy0 + 1) > 2e4) throw new PdfError("E_LIMIT", "Pattern tile count exceeds 20000");
35344
+ const nodes = parseContentStream(doc.decodeStream(pattern));
35345
+ const patternResources = doc.resolveDict(dictGet(dict, "Resources")) ?? resources;
35346
+ const patternFonts = new Map(activeFonts);
35347
+ for (const [key, font] of resolvePageFonts(doc, patternResources)) patternFonts.set(key, font);
35348
+ for (let iy = iy0; iy <= iy1; iy++) {
35349
+ for (let ix = ix0; ix <= ix1; ix++) {
35350
+ const tileCtm = multiplyMatrices([1, 0, 0, 1, ix * xStep, iy * yStep], matrix);
35351
+ const points = [[box[0], box[1]], [box[2], box[1]], [box[2], box[3]], [box[0], box[3]]].map(([x, y]) => transformPoint(tileCtm, x, y));
35352
+ const tileClip = [
35353
+ ...points.map(([x, y], i) => ({ kind: i === 0 ? "move" : "line", x, y })),
35354
+ { kind: "close" }
35355
+ ];
35356
+ stateStack.push({
35357
+ ...curState(),
35358
+ fillPatternName: void 0,
35359
+ ctm: tileCtm,
35360
+ initialCtm: tileCtm,
35361
+ clipPaths: [...curState().clipPaths ?? [], tileClip]
35362
+ });
35363
+ try {
35364
+ walkNodes(nodes, mcid, actualText, patternResources, patternFonts, depth + 1);
35365
+ } finally {
35366
+ stateStack.pop();
35367
+ }
35368
+ }
35369
+ }
35370
+ return true;
35371
+ } finally {
35372
+ stateStack.pop();
35373
+ }
35374
+ };
35248
35375
  const paintForm = (form, activeResources, activeFonts, depth, mcid, actualText, maskGroup = false) => {
35249
35376
  const st = curState();
35250
35377
  const group = params.cosDoc.resolveDict(dictGet(form.dict, "Group"));
@@ -35303,7 +35430,7 @@ function evaluateContentStreamToDisplayList(params) {
35303
35430
  }
35304
35431
  const parentOperations = capturedOperations;
35305
35432
  const children = [];
35306
- const nextState = { ...st, ctm: nextCtm };
35433
+ const nextState = { ...st, ctm: nextCtm, initialCtm: nextCtm };
35307
35434
  if (compositeGroup) {
35308
35435
  capturedOperations = children;
35309
35436
  nextState.fillAlpha = nextState.strokeAlpha = 1;
@@ -35461,136 +35588,15 @@ function evaluateContentStreamToDisplayList(params) {
35461
35588
  }
35462
35589
  const isFill = ["f", "F", "f*", "B", "B*", "b", "b*"].includes(node.paint);
35463
35590
  const isStroke = ["S", "s", "B", "B*", "b", "b*"].includes(node.paint);
35464
- let evaluatedFillPattern = false;
35465
- if (isFill && st.fillPatternName && params.cosDoc && activeResources && depth < 6) {
35466
- const patMap = params.cosDoc.resolveDict(dictGet(activeResources, "Pattern"));
35467
- const patNode = patMap ? params.cosDoc.resolve(dictGet(patMap, st.fillPatternName)) : void 0;
35468
- const patDict = patNode?.kind === "stream" ? patNode.dict : patNode?.kind === "dict" ? patNode : void 0;
35469
- const patTypeNode = patDict && params.cosDoc ? params.cosDoc.resolve(dictGet(patDict, "PatternType")) : void 0;
35470
- const patType = patTypeNode?.kind === "number" ? patTypeNode.value : patNode?.kind === "stream" ? 1 : 0;
35471
- if (patDict && patType === 2 && params.cosDoc) {
35472
- let pMinX = Infinity, pMinY = Infinity, pMaxX = -Infinity, pMaxY = -Infinity;
35473
- for (const s of transformedSegments) {
35474
- if (s.kind === "move" || s.kind === "line") {
35475
- pMinX = Math.min(pMinX, s.x);
35476
- pMinY = Math.min(pMinY, s.y);
35477
- pMaxX = Math.max(pMaxX, s.x);
35478
- pMaxY = Math.max(pMaxY, s.y);
35479
- } else if (s.kind === "cubic") {
35480
- pMinX = Math.min(pMinX, s.x1, s.x2, s.x);
35481
- pMinY = Math.min(pMinY, s.y1, s.y2, s.y);
35482
- pMaxX = Math.max(pMaxX, s.x1, s.x2, s.x);
35483
- pMaxY = Math.max(pMaxY, s.y1, s.y2, s.y);
35484
- } else if (s.kind === "rect") {
35485
- pMinX = Math.min(pMinX, s.x);
35486
- pMinY = Math.min(pMinY, s.y);
35487
- pMaxX = Math.max(pMaxX, s.x + s.width);
35488
- pMaxY = Math.max(pMaxY, s.y + s.height);
35489
- }
35490
- }
35491
- if (Number.isFinite(pMinX) && Number.isFinite(pMinY) && pMaxX > pMinX && pMaxY > pMinY) {
35492
- const shading = params.cosDoc.resolve(dictGet(patDict, "Shading"));
35493
- const shDict = shading?.kind === "stream" ? shading.dict : shading?.kind === "dict" ? shading : void 0;
35494
- if (shDict) {
35495
- let patMatrix = [1, 0, 0, 1, 0, 0];
35496
- const pmArr = params.cosDoc.resolveArray(dictGet(patDict, "Matrix"));
35497
- if (pmArr && pmArr.items.length >= 6) {
35498
- const mn = (idx, fb = 0) => {
35499
- const r = params.cosDoc.resolve(pmArr.items[idx]);
35500
- return r?.kind === "number" ? r.value : fb;
35501
- };
35502
- patMatrix = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
35503
- }
35504
- const patClip = st.clipRect ? [
35505
- Math.max(st.clipRect[0], pMinX),
35506
- Math.max(st.clipRect[1], pMinY),
35507
- Math.min(st.clipRect[2], pMaxX),
35508
- Math.min(st.clipRect[3], pMaxY)
35509
- ] : [pMinX, pMinY, pMaxX, pMaxY];
35510
- const shImg = renderShadingDictToImage(
35511
- params.cosDoc,
35512
- shDict,
35513
- patMatrix,
35514
- patClip,
35515
- st.fillAlpha,
35516
- "PatternShading_" + st.fillPatternName,
35517
- patClip,
35518
- shading?.kind === "stream" ? shading : void 0,
35519
- st.blendMode
35520
- );
35521
- if (shImg) {
35522
- emit({ kind: "image", value: shImg });
35523
- evaluatedFillPattern = true;
35524
- }
35525
- }
35526
- }
35527
- } else if (patNode?.kind === "stream") {
35528
- let pMinX = Infinity, pMinY = Infinity, pMaxX = -Infinity, pMaxY = -Infinity;
35529
- for (const s of transformedSegments) {
35530
- if (s.kind === "move" || s.kind === "line") {
35531
- pMinX = Math.min(pMinX, s.x);
35532
- pMinY = Math.min(pMinY, s.y);
35533
- pMaxX = Math.max(pMaxX, s.x);
35534
- pMaxY = Math.max(pMaxY, s.y);
35535
- } else if (s.kind === "cubic") {
35536
- pMinX = Math.min(pMinX, s.x1, s.x2, s.x);
35537
- pMinY = Math.min(pMinY, s.y1, s.y2, s.y);
35538
- pMaxX = Math.max(pMaxX, s.x1, s.x2, s.x);
35539
- pMaxY = Math.max(pMaxY, s.y1, s.y2, s.y);
35540
- } else if (s.kind === "rect") {
35541
- pMinX = Math.min(pMinX, s.x);
35542
- pMinY = Math.min(pMinY, s.y);
35543
- pMaxX = Math.max(pMaxX, s.x + s.width);
35544
- pMaxY = Math.max(pMaxY, s.y + s.height);
35545
- }
35546
- }
35547
- if (Number.isFinite(pMinX) && Number.isFinite(pMinY) && pMaxX > pMinX && pMaxY > pMinY) {
35548
- const xsNode = params.cosDoc.resolve(dictGet(patNode.dict, "XStep"));
35549
- const ysNode = params.cosDoc.resolve(dictGet(patNode.dict, "YStep"));
35550
- const xStep = xsNode?.kind === "number" && Math.abs(xsNode.value) > 1e-3 ? Math.abs(xsNode.value) : 40;
35551
- const yStep = ysNode?.kind === "number" && Math.abs(ysNode.value) > 1e-3 ? Math.abs(ysNode.value) : 40;
35552
- let patMatrix = [1, 0, 0, 1, 0, 0];
35553
- const pmArr = params.cosDoc.resolveArray(dictGet(patNode.dict, "Matrix"));
35554
- if (pmArr && pmArr.items.length >= 6) {
35555
- const mn = (idx, fb = 0) => {
35556
- const r = params.cosDoc.resolve(pmArr.items[idx]);
35557
- return r?.kind === "number" ? r.value : fb;
35558
- };
35559
- patMatrix = [mn(0, 1), mn(1, 0), mn(2, 0), mn(3, 1), mn(4, 0), mn(5, 0)];
35560
- }
35561
- const tileClip = st.clipRect ? [
35562
- Math.max(st.clipRect[0], pMinX),
35563
- Math.max(st.clipRect[1], pMinY),
35564
- Math.min(st.clipRect[2], pMaxX),
35565
- Math.min(st.clipRect[3], pMaxY)
35566
- ] : [pMinX, pMinY, pMaxX, pMaxY];
35567
- const patNodes = parseContentStream(params.cosDoc.decodeStream(patNode));
35568
- const patResDict = params.cosDoc.resolveDict(dictGet(patNode.dict, "Resources")) ?? activeResources;
35569
- const patFonts = new Map(activeFonts);
35570
- for (const [fk, fv] of resolvePageFonts(params.cosDoc, patResDict).entries()) {
35571
- patFonts.set(fk, fv);
35572
- }
35573
- const ixStart = Math.floor(pMinX / xStep);
35574
- const ixEnd = Math.min(ixStart + 8, Math.ceil(pMaxX / xStep) - 1);
35575
- const iyStart = Math.floor(pMinY / yStep);
35576
- const iyEnd = Math.min(iyStart + 8, Math.ceil(pMaxY / yStep) - 1);
35577
- for (let iy = iyStart; iy <= iyEnd; iy++) {
35578
- for (let ix = ixStart; ix <= ixEnd; ix++) {
35579
- const tileCtm = multiplyMatrices([1, 0, 0, 1, ix * xStep, iy * yStep], patMatrix);
35580
- stateStack.push({
35581
- ...st,
35582
- fillPatternName: void 0,
35583
- ctm: tileCtm,
35584
- clipRect: tileClip
35585
- });
35586
- walkNodes(patNodes, mcid, actualText, patResDict, patFonts, depth + 1);
35587
- if (stateStack.length > 1) stateStack.pop();
35588
- }
35589
- }
35590
- evaluatedFillPattern = true;
35591
- }
35592
- }
35593
- }
35591
+ const evaluatedFillPattern = isFill && paintPattern(
35592
+ transformedSegments,
35593
+ node.paint.includes("*") ? "evenodd" : "nonzero",
35594
+ activeResources,
35595
+ activeFonts,
35596
+ depth,
35597
+ mcid,
35598
+ actualText
35599
+ );
35594
35600
  if (evaluatedFillPattern && !isStroke) {
35595
35601
  applyClip();
35596
35602
  break;
@@ -35791,10 +35797,19 @@ function evaluateContentStreamToDisplayList(params) {
35791
35797
  if (st.textRenderMode >= 4 && st.textRenderMode <= 7) pendingTextClip.push(...transformedGlyphSegs);
35792
35798
  const isFillGlyph = st.textRenderMode === 0 || st.textRenderMode === 2 || st.textRenderMode === 4 || st.textRenderMode === 6;
35793
35799
  const isStrokeGlyph = st.textRenderMode === 1 || st.textRenderMode === 2 || st.textRenderMode === 5 || st.textRenderMode === 6;
35800
+ const patterned = isFillGlyph && paintPattern(
35801
+ transformedGlyphSegs,
35802
+ "nonzero",
35803
+ activeResources,
35804
+ activeFonts,
35805
+ depth,
35806
+ mcid,
35807
+ actualText
35808
+ );
35794
35809
  const paint = {
35795
35810
  segments: transformedGlyphSegs,
35796
- fillColor: isFillGlyph ? st.fillColor : void 0,
35797
- fillAlpha: isFillGlyph ? st.fillAlpha : void 0,
35811
+ fillColor: isFillGlyph && !patterned ? st.fillColor : void 0,
35812
+ fillAlpha: isFillGlyph && !patterned ? st.fillAlpha : void 0,
35798
35813
  strokeColor: isStrokeGlyph ? st.strokeColor : void 0,
35799
35814
  strokeAlpha: isStrokeGlyph ? st.strokeAlpha : void 0,
35800
35815
  strokeWidth: isStrokeGlyph ? st.strokeWidth : 0,
@@ -37831,10 +37846,14 @@ function computePdfBlendRgb(cbR, cbG, cbB, csR, csG, csB, mode) {
37831
37846
  blendChannelSeparable(cbB, csB, mode)
37832
37847
  ];
37833
37848
  }
37834
- function blendPixel(rgba, width, height, px, py, color, alpha, blendMode, clipMask) {
37849
+ function blendPixel(rgba, width, height, px, py, color, alpha, blendMode, clipMask, groupAlpha) {
37835
37850
  if (px < 0 || py < 0 || px >= width || py >= height || alpha <= 0) return;
37836
37851
  const a = Math.min(1, Math.max(0, alpha)) * (clipMask ? clipMask[(py * width + px) * 4 + 3] / 255 : 1);
37837
37852
  const idx = (py * width + px) * 4;
37853
+ if (groupAlpha) {
37854
+ const pixel = py * width + px;
37855
+ groupAlpha[pixel] = a + groupAlpha[pixel] * (1 - a);
37856
+ }
37838
37857
  const csR = Math.min(1, Math.max(0, color.r));
37839
37858
  const csG = Math.min(1, Math.max(0, color.g));
37840
37859
  const csB = Math.min(1, Math.max(0, color.b));
@@ -37966,7 +37985,7 @@ function pathsToEdges(paths, closeSubpaths = false) {
37966
37985
  }
37967
37986
  return edges;
37968
37987
  }
37969
- function fillEdgesScanline4x4(rgba, width, height, edges, color, alpha = 1, fillRule = "nonzero", clipScreen, antialias = true, blendMode, clipMask) {
37988
+ function fillEdgesScanline4x4(rgba, width, height, edges, color, alpha = 1, fillRule = "nonzero", clipScreen, antialias = true, blendMode, clipMask, groupAlpha) {
37970
37989
  if (edges.length === 0) return;
37971
37990
  let minY = Infinity;
37972
37991
  let maxY = -Infinity;
@@ -38032,7 +38051,7 @@ function fillEdgesScanline4x4(rgba, width, height, edges, color, alpha = 1, fill
38032
38051
  const count = rowCounts[px];
38033
38052
  if (count > 0) {
38034
38053
  const cov = antialias ? count / 16 : count >= 8 ? 1 : 0;
38035
- blendPixel(rgba, width, height, px, py, color, cov * alpha, blendMode, clipMask);
38054
+ blendPixel(rgba, width, height, px, py, color, cov * alpha, blendMode, clipMask, groupAlpha);
38036
38055
  }
38037
38056
  }
38038
38057
  }
@@ -38111,19 +38130,16 @@ function hasCompositingEffects(operations, includeSoftMasks = false) {
38111
38130
  return operations.some((operation) => includeSoftMasks && !!operation.value.softMask || !!operation.value.blendMode && operation.value.blendMode !== "Normal" && operation.value.blendMode !== "Compatible" || operation.kind === "group" && hasCompositingEffects(operation.value.operations, includeSoftMasks));
38112
38131
  }
38113
38132
  function needsGroupBackdrop(group) {
38114
- return group.isolated === false && !!group.softMask && hasCompositingEffects(group.operations, true);
38133
+ return group.isolated === false && hasCompositingEffects(group.operations, true);
38115
38134
  }
38116
- function renderDisplayListToBitmap(displayList, options = {}) {
38117
- const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
38118
- const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
38119
- const scaleY = options.dpiY !== void 0 ? options.dpiY / 72 : baseScale;
38120
- const scale = scaleX;
38135
+ function renderDisplayListLayer(displayList, options, scale, backdrop) {
38121
38136
  const [originX, originY] = displayList.origin ?? [0, 0];
38122
38137
  const pageTop = originY + displayList.height;
38123
38138
  const toScreen = (x, y) => [(x - originX) * scale, (pageTop - y) * scale];
38124
38139
  const width = Math.max(1, Math.round(displayList.width * scale));
38125
38140
  const height = Math.max(1, Math.round(displayList.height * scale));
38126
- const rgba = new Uint8Array(width * height * 4);
38141
+ const rgba = backdrop ? backdrop.slice() : new Uint8Array(width * height * 4);
38142
+ const groupAlpha = backdrop ? new Float32Array(width * height) : void 0;
38127
38143
  const deferBackground = !options.transparent && hasCompositingEffects(paintOperations(displayList));
38128
38144
  const transparent = options.transparent || deferBackground;
38129
38145
  const bg = options.background ?? { r: 1, g: 1, b: 1 };
@@ -38131,7 +38147,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
38131
38147
  const bgG = transparent ? 0 : Math.round(bg.g * 255);
38132
38148
  const bgB = transparent ? 0 : Math.round(bg.b * 255);
38133
38149
  const bgA = transparent ? 0 : 255;
38134
- for (let i = 0; i < width * height; i++) {
38150
+ for (let i = 0; !backdrop && i < width * height; i++) {
38135
38151
  rgba[i * 4] = bgR;
38136
38152
  rgba[i * 4 + 1] = bgG;
38137
38153
  rgba[i * 4 + 2] = bgB;
@@ -38149,20 +38165,12 @@ function renderDisplayListToBitmap(displayList, options = {}) {
38149
38165
  let operation = original.kind === "glyph" ? { kind: "path", value: glyphPaint(original.value) } : original;
38150
38166
  if (operation.kind === "group") {
38151
38167
  const group = operation.value;
38152
- let operations = group.operations;
38153
- if (needsGroupBackdrop(group)) {
38154
- operations = [{ kind: "image", value: {
38155
- name: "GroupBackdrop",
38156
- width,
38157
- height,
38158
- decodedRgba: rgba.slice(),
38159
- matrix: [width / scale, 0, 0, height / scale, originX, pageTop - height / scale],
38160
- colorSpace: "DeviceRGB",
38161
- bitsPerComponent: 8,
38162
- ...group.bboxClip ? { clipPaths: [group.bboxClip] } : {}
38163
- } }, ...operations];
38164
- }
38165
- const bitmap = renderDisplayListToBitmap({ ...displayList, rotation: 0, operations }, { ...options, scale, dpiX: void 0, dpiY: void 0, cropRect: void 0, useCropBox: false, transparent: true });
38168
+ const bitmap = renderDisplayListLayer(
38169
+ { ...displayList, operations: group.operations },
38170
+ { ...options, transparent: true },
38171
+ scale,
38172
+ needsGroupBackdrop(group) ? rgba : void 0
38173
+ );
38166
38174
  for (let i = 3; i < bitmap.data.length; i += 4) bitmap.data[i] = Math.round(bitmap.data[i] * group.alpha);
38167
38175
  operation = { kind: "image", value: {
38168
38176
  name: "TransparencyGroup",
@@ -38232,7 +38240,7 @@ function renderDisplayListToBitmap(displayList, options = {}) {
38232
38240
  if (path.fillColor) {
38233
38241
  const edges = pathsToEdges(segmentsToScreenPaths(path.segments, displayList.height, scale, toScreen), true);
38234
38242
  const clipScreen = path.clipRect ? [(path.clipRect[0] - originX) * scale, (pageTop - path.clipRect[3]) * scale, (path.clipRect[2] - originX) * scale, (pageTop - path.clipRect[1]) * scale] : void 0;
38235
- fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask);
38243
+ fillEdgesScanline4x4(rgba, width, height, edges, path.fillColor, path.fillAlpha ?? 1, path.fillRule ?? "nonzero", clipScreen, original.kind === "glyph" ? aaTxt : aaVec, path.blendMode, clipMask, groupAlpha);
38236
38244
  }
38237
38245
  if (path.strokeColor) {
38238
38246
  const rawSw = path.strokeWidth * scale * (path.strokeMatrix ? Math.hypot(path.strokeMatrix[0], path.strokeMatrix[1]) : 1);
@@ -38250,7 +38258,8 @@ function renderDisplayListToBitmap(displayList, options = {}) {
38250
38258
  clipScreen,
38251
38259
  original.kind === "glyph" ? aaTxt : aaVec,
38252
38260
  path.blendMode,
38253
- clipMask
38261
+ clipMask,
38262
+ groupAlpha
38254
38263
  );
38255
38264
  }
38256
38265
  } else if (operation.kind === "image") {
@@ -38314,12 +38323,31 @@ function renderDisplayListToBitmap(displayList, options = {}) {
38314
38323
  },
38315
38324
  sample[3] / 255,
38316
38325
  img.blendMode,
38317
- clipMask
38326
+ clipMask,
38327
+ groupAlpha
38318
38328
  );
38319
38329
  }
38320
38330
  }
38321
38331
  }
38322
38332
  }
38333
+ if (backdrop && groupAlpha) {
38334
+ for (let i = 0; i < rgba.length; i += 4) {
38335
+ const alpha = groupAlpha[i / 4];
38336
+ if (alpha === 0) {
38337
+ rgba.fill(0, i, i + 4);
38338
+ continue;
38339
+ }
38340
+ const factor = backdrop[i + 3] / 255 * (1 / alpha - 1);
38341
+ for (let channel = 0; channel < 3; channel++) {
38342
+ const color = rgba[i + channel];
38343
+ rgba[i + channel] = Math.max(0, Math.min(
38344
+ 255,
38345
+ Math.round(color + (color - backdrop[i + channel]) * factor)
38346
+ ));
38347
+ }
38348
+ rgba[i + 3] = Math.round(alpha * 255);
38349
+ }
38350
+ }
38323
38351
  if (deferBackground) {
38324
38352
  for (let i = 0; i < rgba.length; i += 4) {
38325
38353
  const alpha = rgba[i + 3] / 255;
@@ -38329,7 +38357,14 @@ function renderDisplayListToBitmap(displayList, options = {}) {
38329
38357
  rgba[i + 3] = 255;
38330
38358
  }
38331
38359
  }
38332
- let result = { width, height, data: rgba };
38360
+ return { width, height, data: rgba };
38361
+ }
38362
+ function renderDisplayListToBitmap(displayList, options = {}) {
38363
+ const baseScale = options.scale ?? (options.dpi ? options.dpi / 72 : 1.5);
38364
+ const scaleX = options.dpiX !== void 0 ? options.dpiX / 72 : baseScale;
38365
+ const scaleY = options.dpiY !== void 0 ? options.dpiY / 72 : baseScale;
38366
+ let result = renderDisplayListLayer(displayList, options, scaleX);
38367
+ const { width, height, data: rgba } = result;
38333
38368
  if (Math.abs(scaleX - scaleY) > 1e-6) {
38334
38369
  const targetW = Math.max(1, Math.round(displayList.width * scaleX));
38335
38370
  const targetH = Math.max(1, Math.round(displayList.height * scaleY));