@vvfx/svg2ir 0.0.1-beta.0 → 0.0.1-beta.12

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 (57) hide show
  1. package/README.md +86 -48
  2. package/dist/{svg2ge-adapter → adapter/svg2ge}/assemble.d.ts +2 -2
  3. package/dist/adapter/svg2ge/convert.d.ts +7 -0
  4. package/dist/{svg2ge-adapter → adapter/svg2ge}/normalize-shape-animation.d.ts +1 -1
  5. package/dist/{svg2ge-adapter → adapter/svg2ge}/post-process/apply-shape-geometry-animation.d.ts +1 -1
  6. package/dist/{svg2ge-adapter → adapter/svg2ge}/post-process/apply-shape-paint-animation.d.ts +1 -1
  7. package/dist/{svg2ge-adapter → adapter/svg2ge}/post-process/rewrite-text-components.d.ts +1 -1
  8. package/dist/{svg2ge-adapter → adapter/svg2ge}/pre-process.d.ts +1 -1
  9. package/dist/{svg2ge-adapter → adapter/svg2ge}/types.d.ts +2 -2
  10. package/dist/adapter/svg2layers/assemble.d.ts +23 -0
  11. package/dist/adapter/svg2layers/baking/build-baked-layers.d.ts +13 -0
  12. package/dist/adapter/svg2layers/baking/normalize-layer-blending.d.ts +10 -0
  13. package/dist/adapter/svg2layers/baking/plan-graphic-baking.d.ts +18 -0
  14. package/dist/adapter/svg2layers/baking/resolve-baking-warnings.d.ts +4 -0
  15. package/dist/adapter/svg2layers/convert.d.ts +4 -0
  16. package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/diagnostics/collect-warnings.d.ts +1 -1
  17. package/dist/adapter/svg2layers/converter/image/inspect-mask.d.ts +3 -0
  18. package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/layers/build-layers.d.ts +1 -1
  19. package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/layers/conversion-session.d.ts +2 -2
  20. package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/text/parse-text-runs.d.ts +1 -1
  21. package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/text/text-layout.d.ts +2 -2
  22. package/dist/{svg2layers-adapter → adapter/svg2layers}/matrix.d.ts +1 -1
  23. package/dist/adapter/svg2layers/strip-layer-animation.d.ts +5 -0
  24. package/dist/{svg2layers-adapter → adapter/svg2layers}/types.d.ts +8 -1
  25. package/dist/common/types.d.ts +7 -3
  26. package/dist/index.d.ts +6 -6
  27. package/dist/index.js +1324 -103
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +1323 -103
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/node.js +1326 -105
  32. package/dist/node.js.map +1 -1
  33. package/dist/node.mjs +1325 -105
  34. package/dist/node.mjs.map +1 -1
  35. package/dist/parse-svg/build-element-tree-path.d.ts +2 -0
  36. package/dist/svg-rasterizer/prepare-snapshot.d.ts +9 -0
  37. package/dist/svg-rasterizer/rasterize-svg.d.ts +11 -0
  38. package/dist/svg2ir/assemble.d.ts +3 -1
  39. package/dist/svg2ir/convert.d.ts +5 -2
  40. package/dist/svg2ir/converter/layers/conversion-session.d.ts +2 -0
  41. package/dist/svg2ir/converter/text/font-metrics.d.ts +2 -0
  42. package/package.json +5 -5
  43. package/dist/convert.d.ts +0 -19
  44. package/dist/svg2ge-adapter/convert.d.ts +0 -5
  45. package/dist/svg2layers-adapter/assemble.d.ts +0 -8
  46. package/dist/svg2layers-adapter/convert.d.ts +0 -4
  47. /package/dist/{svg2ge-adapter → adapter/svg2ge}/converter/animation.d.ts +0 -0
  48. /package/dist/{svg2ge-adapter → adapter/svg2ge}/converter/data-path.d.ts +0 -0
  49. /package/dist/{svg2ge-adapter → adapter/svg2ge}/post-process/apply-fonts.d.ts +0 -0
  50. /package/dist/{svg2ge-adapter → adapter/svg2ge}/post-process/paint-animation-sampling.d.ts +0 -0
  51. /package/dist/{svg2ge-adapter → adapter/svg2ge}/post-process/restore-gradient-uv.d.ts +0 -0
  52. /package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/image/convert-image-layer.d.ts +0 -0
  53. /package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/layers/registry.d.ts +0 -0
  54. /package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/layers/resolve-visual-state.d.ts +0 -0
  55. /package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/text/convert-text-layer.d.ts +0 -0
  56. /package/dist/{svg2layers-adapter → adapter/svg2layers}/converter/transform/build-transform.d.ts +0 -0
  57. /package/dist/{svg2layers-adapter → adapter/svg2layers}/post-process/inline-image-resources.d.ts +0 -0
package/dist/node.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  * Description: SVG to Animation IR and Galacean Effects conversion engine
4
4
  * Author: Ant Group CO., Ltd.
5
5
  * Contributors: 鳞息
6
- * Version: v0.0.1-beta.0
6
+ * Version: v0.0.1-beta.12
7
7
  */
8
8
 
9
9
  import { createSVGWindow } from 'svgdom';
@@ -79,11 +79,10 @@ function readInlineStyleProperty(style, propertyName) {
79
79
 
80
80
  var ParseableSVG = /*#__PURE__*/ function() {
81
81
  function ParseableSVG(svgStr, _options) {
82
- var _ref, _SVG;
83
- var _svgStr_match;
84
- // 从字符串里抠出首个 <svg>...</svg> 再交给 svg.js(兼容前导注释/doctype)。
82
+ var _SVG;
83
+ // svg.js parses a fragment; remove only the prolog and let the DOM handle nested markup.
84
+ var content = svgStr.replace(/^\uFEFF/, '').replace(/^(?:\s|<\?xml\b[\s\S]*?\?>|<!DOCTYPE\b[^>]*>|<!--[\s\S]*?-->)+/i, '');
85
85
  // svg.js SVG(string) 的 d.ts 标为 Element,但对完整 <svg> 文档运行时返回根 SVG 文档实例。
86
- var content = typeof svgStr === 'string' ? (_ref = (_svgStr_match = svgStr.match(RegExp("<svg\\s+.*?>.*?<\\/svg>", "s"))) == null ? void 0 : _svgStr_match[0]) != null ? _ref : svgStr : svgStr;
87
86
  // svg.js 对非 SVG 字符串(如 'not svg')解析返 null。兜底空 svg:让 svg2ir 上层
88
87
  // hasSVGRootElement 检查(非 svg 抛 INVALID_SVG)生效,而非在构造期抛错。
89
88
  this.svg = (_SVG = SVG(content)) != null ? _SVG : SVG('<svg xmlns="http://www.w3.org/2000/svg"/>');
@@ -225,10 +224,10 @@ var editableSVGModule = /*#__PURE__*/Object.freeze({
225
224
  default: ParseableSVG
226
225
  });
227
226
 
228
- var window = createSVGWindow();
227
+ var window$1 = createSVGWindow();
229
228
  // svgdom 的 window 是最小 DOM stub(非完整 Window),运行时被 svg.js registerWindow 接受;
230
229
  // d.ts 标 Window 类型过严,svgdom 的 window 是最小 DOM stub,这里断言对齐运行时用法。
231
- registerWindow(window, window.document);
230
+ registerWindow(window$1, window$1.document);
232
231
 
233
232
  var editableSVGNodeModule = /*#__PURE__*/Object.freeze({
234
233
  __proto__: null,
@@ -1725,7 +1724,7 @@ function parseHexColor(raw) {
1725
1724
  return null;
1726
1725
  }
1727
1726
  var hex = match[1];
1728
- var expanded = hex.length <= 4 ? [].concat(hex).map(function(char) {
1727
+ var expanded = hex.length <= 4 ? Array.from(hex).map(function(char) {
1729
1728
  return "" + char + char;
1730
1729
  }).join('') : hex;
1731
1730
  var r = parseInt(expanded.slice(0, 2), 16) / 255;
@@ -2826,7 +2825,24 @@ function parseSMILTag(tag, root, beginCache, comparisonDuration, valueParser, un
2826
2825
  return maxEnd;
2827
2826
  }
2828
2827
 
2829
- /** SVG 转换诊断码。不支持的特性按降级和 warning 处理。 */ var SVG2IR_WARNING_CODES = {
2828
+ /** Structural source identity, independent of optional or duplicate SVG IDs. */ function buildElementTreePath(element) {
2829
+ var indices = [];
2830
+ var current = element;
2831
+ while(isElementNode(current.parentNode)){
2832
+ var parent = current.parentNode;
2833
+ indices.unshift(Array.from(parent.children).indexOf(current));
2834
+ current = parent;
2835
+ }
2836
+ return indices.join('/');
2837
+ }
2838
+ function isElementNode(node) {
2839
+ return (node == null ? void 0 : node.nodeType) === 1;
2840
+ }
2841
+
2842
+ /** SVG 转换诊断码;用于报告烘焙、降级和不支持的特性。 */ var SVG2IR_WARNING_CODES = {
2843
+ /** 图形或图形组已栅格化,矢量编辑能力变化通过 warning 报告。 */ LAYERS_GRAPHIC_BAKED: 'svg2ge_layers_graphic_baked',
2844
+ LAYERS_BLEND_MODE_DOWNGRADED: 'svg2ge_layers_blend_mode_downgraded',
2845
+ LAYERS_ANIMATION_STRIPPED: 'svg2ge_layers_animation_stripped',
2830
2846
  LAYERS_UNSUPPORTED_TYPE: 'svg2ge_layers_unsupported_type',
2831
2847
  LAYERS_UNSUPPORTED_FEATURE: 'svg2ge_layers_unsupported_feature',
2832
2848
  LAYERS_INVALID_DATA: 'svg2ge_layers_invalid_data',
@@ -4181,7 +4197,7 @@ function distPointToSegment(p, a, b) {
4181
4197
  return transformVector(gChain, t);
4182
4198
  });
4183
4199
  return {
4184
- mode: "add",
4200
+ mode: 'add',
4185
4201
  path: {
4186
4202
  points: pts,
4187
4203
  inTangents: inTangents,
@@ -6108,12 +6124,16 @@ function applyClipMask(es, el, layer, clipMasks) {
6108
6124
  }
6109
6125
  if (isClip) {
6110
6126
  return _extends({}, layer, {
6111
- mask: baseMask
6127
+ masks: [
6128
+ baseMask
6129
+ ]
6112
6130
  });
6113
6131
  }
6114
6132
  var rebased = rebaseMaskToLocal(baseMask, layer);
6115
6133
  return rebased ? _extends({}, layer, {
6116
- mask: rebased
6134
+ masks: [
6135
+ rebased
6136
+ ]
6117
6137
  }) : layer;
6118
6138
  }
6119
6139
  /** 将 SVG 绝对 mask 点转换为 image 的 asset-local 坐标。 */ function rebaseMaskToLocal(mask, layer) {
@@ -6151,7 +6171,7 @@ function applyClipMask(es, el, layer, clipMasks) {
6151
6171
  outTangents: mask.path.outTangents,
6152
6172
  closed: mask.path.closed
6153
6173
  },
6154
- mode: "add"
6174
+ mode: 'add'
6155
6175
  };
6156
6176
  }
6157
6177
  // shape 没有 asset 尺寸,mask 需要转换到以 layer anchor 为基准的 element-local 空间。
@@ -6181,7 +6201,7 @@ function applyClipMask(es, el, layer, clipMasks) {
6181
6201
  outTangents: mask.path.outTangents,
6182
6202
  closed: mask.path.closed
6183
6203
  },
6184
- mode: "add"
6204
+ mode: 'add'
6185
6205
  };
6186
6206
  }
6187
6207
  /** shape layer 的 element-local bbox(以 layer.transform.anchor=localCenter 为原点)。
@@ -6316,8 +6336,9 @@ function readVec3(channel) {
6316
6336
  node
6317
6337
  ], Array.from(node.querySelectorAll('*')));
6318
6338
  var hasUnsupportedRule = ruleNodes.some(function(candidate) {
6339
+ var _ref, _ref1;
6319
6340
  var _candidate_getAttribute, _candidate_getAttribute1;
6320
- return ((_candidate_getAttribute = candidate.getAttribute('clip-rule')) == null ? void 0 : _candidate_getAttribute.trim()) !== '' || ((_candidate_getAttribute1 = candidate.getAttribute('fill-rule')) == null ? void 0 : _candidate_getAttribute1.trim()) !== '';
6341
+ return ((_ref = (_candidate_getAttribute = candidate.getAttribute('clip-rule')) == null ? void 0 : _candidate_getAttribute.trim()) != null ? _ref : '') !== '' || ((_ref1 = (_candidate_getAttribute1 = candidate.getAttribute('fill-rule')) == null ? void 0 : _candidate_getAttribute1.trim()) != null ? _ref1 : '') !== '';
6321
6342
  });
6322
6343
  if (hasUnsupportedRule) {
6323
6344
  warn(SVG2IR_WARNING_CODES.CLIP_RULE_DROPPED, "" + tag + " 内显式 clip-rule/fill-rule 未映射,IR 只保留 mask 几何,不保留该规则。");
@@ -7149,7 +7170,7 @@ function createSVGConversionSession(es, options) {
7149
7170
  };
7150
7171
  var withGroupParent = function withGroupParent(layer, element) {
7151
7172
  var parentIndex = nearestMaskedGroupAncestor(element);
7152
- if (parentIndex == null || layer.mask != null) {
7173
+ if (parentIndex == null) {
7153
7174
  return layer;
7154
7175
  }
7155
7176
  return _extends({}, layer, {
@@ -7158,8 +7179,10 @@ function createSVGConversionSession(es, options) {
7158
7179
  };
7159
7180
  var appendLayer = function appendLayer(layer, element, applyElementClip) {
7160
7181
  if (applyElementClip === void 0) applyElementClip = true;
7182
+ var _options_layerSourceCollector;
7161
7183
  var clippedLayer = applyElementClip ? applyClipMask(es, element, layer, clipMasks) : layer;
7162
7184
  layers.push(withGroupParent(clippedLayer, element));
7185
+ (_options_layerSourceCollector = options.layerSourceCollector) == null ? void 0 : _options_layerSourceCollector.set(layer.id, buildElementTreePath(element.node));
7163
7186
  };
7164
7187
  var appendAsset = function appendAsset(asset) {
7165
7188
  if (registeredAssetIds.has(asset.id)) {
@@ -7502,7 +7525,9 @@ function convertGroupElement(element, context) {
7502
7525
  value: 1
7503
7526
  }
7504
7527
  },
7505
- mask: groupMask
7528
+ masks: [
7529
+ groupMask
7530
+ ]
7506
7531
  };
7507
7532
  context.appendLayer(nullLayer, element, false);
7508
7533
  context.groupMaskGNodeToIndex.set(element.node, layerIndex);
@@ -10567,7 +10592,7 @@ function mapFontWeight(raw, fontFamily) {
10567
10592
  seen.set(Math.round(w * 100), ch);
10568
10593
  }
10569
10594
  }
10570
- return [].concat(seen.entries()).map(function(param) {
10595
+ return Array.from(seen.entries()).map(function(param) {
10571
10596
  var k = param[0], ch = param[1];
10572
10597
  return {
10573
10598
  ch: ch,
@@ -10617,6 +10642,9 @@ function mapFontWeight(raw, fontFamily) {
10617
10642
  // latin / digit / 标点:典型比例字体 sans-serif 大写字母约 0.65em,数字稍窄。
10618
10643
  return /[0-9]/.test(ch) ? 0.55 : 0.62;
10619
10644
  }
10645
+ /** 去除单个字体族名的 CSS 字符串引号。 */ function normalizeFontFamilyName(fontFamily) {
10646
+ return fontFamily.trim().replace(/^(['"])(.*)\1$/, '$2');
10647
+ }
10620
10648
  /** 构造与 Effects Runtime getFontDesc 一致的 CSS font 简写字符串,用于 Canvas measureText。 */ function buildCanvasFontDesc(fontSize, fontFamily, fontWeight, fontStyle) {
10621
10649
  var weightStr = String(fontWeight);
10622
10650
  var genericFamilies = [
@@ -10625,7 +10653,8 @@ function mapFontWeight(raw, fontFamily) {
10625
10653
  'monospace',
10626
10654
  'courier'
10627
10655
  ];
10628
- var familyName = genericFamilies.includes(fontFamily) ? fontFamily : '"' + fontFamily + '"';
10656
+ var family = normalizeFontFamilyName(fontFamily);
10657
+ var familyName = genericFamilies.includes(family) ? family : '"' + family + '"';
10629
10658
  var desc = fontSize + "px " + familyName;
10630
10659
  if (weightStr !== 'normal' && weightStr !== '') {
10631
10660
  desc = weightStr + " " + desc;
@@ -10636,13 +10665,13 @@ function mapFontWeight(raw, fontFamily) {
10636
10665
  return desc;
10637
10666
  }
10638
10667
  /** 文本宽度估算。优先使用调用方提供的 Canvas measureText,否则使用字符级启发式系数。 */ function estimateTextWidth(content, fontSize, letterSpacing, measureText, fontFamily, fontWeight, fontStyle) {
10639
- var len = [].concat(content).length;
10668
+ var chars = Array.from(content);
10669
+ var len = chars.length;
10640
10670
  if (measureText != null && fontFamily !== '') {
10641
10671
  var fontDesc = buildCanvasFontDesc(fontSize, fontFamily, fontWeight, fontStyle);
10642
10672
  var width = measureText(fontDesc, content).width;
10643
10673
  return width + letterSpacing * Math.max(len - 1, 0);
10644
10674
  }
10645
- var chars = [].concat(content);
10646
10675
  var width1 = chars.reduce(function(s, ch) {
10647
10676
  return s + charWidthCoef(ch) * fontSize;
10648
10677
  }, 0);
@@ -12239,7 +12268,16 @@ function createSVGElementConverterRegistry(session) {
12239
12268
  }
12240
12269
 
12241
12270
  function buildSVGLayers(es, options) {
12242
- var session = createSVGConversionSession(es, options);
12271
+ var currentPath;
12272
+ var warningSourceCollector = options.warningSourceCollector;
12273
+ var session = createSVGConversionSession(es, warningSourceCollector == null ? options : _extends({}, options, {
12274
+ emit: function emit(warning) {
12275
+ if (currentPath != null) {
12276
+ warningSourceCollector.set(warning, currentPath);
12277
+ }
12278
+ options.emit(warning);
12279
+ }
12280
+ }));
12243
12281
  var converters = createSVGElementConverterRegistry(session);
12244
12282
  for(var _iterator = _create_for_of_iterator_helper_loose(session.all), _step; !(_step = _iterator()).done;){
12245
12283
  var element = _step.value;
@@ -12247,6 +12285,9 @@ function buildSVGLayers(es, options) {
12247
12285
  var _element_node_tagName, _element_node;
12248
12286
  var tag = (_ref = (_element_node = element.node) == null ? void 0 : (_element_node_tagName = _element_node.tagName) == null ? void 0 : _element_node_tagName.toLowerCase()) != null ? _ref : '';
12249
12287
  var selector = describeElement(element);
12288
+ if (warningSourceCollector != null) {
12289
+ currentPath = buildElementTreePath(element.node);
12290
+ }
12250
12291
  if (isInInactiveSwitchBranch(element)) {
12251
12292
  continue;
12252
12293
  }
@@ -12312,6 +12353,8 @@ function parseSVGToIRScene(svgString, options) {
12312
12353
  value: scannedSmilDuration
12313
12354
  };
12314
12355
  var layerBuildOptions = {
12356
+ layerSourceCollector: options == null ? void 0 : options.layerSourceCollector,
12357
+ warningSourceCollector: options == null ? void 0 : options.warningSourceCollector,
12315
12358
  frameRate: frameRate,
12316
12359
  durationSeconds: effectiveDuration,
12317
12360
  emit: emit,
@@ -12491,6 +12534,8 @@ function parseSVGToIRWithPreservedData(source, options, collectors) {
12491
12534
  var svgString = readSVGString(source);
12492
12535
  var irScene = parseSVGToIRScene(svgString, _extends({}, options, {
12493
12536
  onWarning: emitWarning,
12537
+ layerSourceCollector: collectors == null ? void 0 : collectors.layerSourceCollector,
12538
+ warningSourceCollector: collectors == null ? void 0 : collectors.warningSourceCollector,
12494
12539
  textDataCollector: collectors == null ? void 0 : collectors.textDataByLayerId,
12495
12540
  paintAnimationsCollector: collectors == null ? void 0 : collectors.paintAnimationsByLayerId,
12496
12541
  shapeAnimationCollector: collectors == null ? void 0 : collectors.shapeAnimationsByLayerId
@@ -12666,7 +12711,8 @@ function collectLayerWarning(warnings, options, code, message, selector) {
12666
12711
  });
12667
12712
  warnings.push(warning);
12668
12713
  options.onWarning == null ? void 0 : options.onWarning.call(options, warning);
12669
- if (options.strict === true && code !== SVG2IR_WARNING_CODES.LAYERS_TEXT_BOUNDS_ESTIMATED) {
12714
+ var advisory = code === SVG2IR_WARNING_CODES.LAYERS_TEXT_BOUNDS_ESTIMATED || code === SVG2IR_WARNING_CODES.LAYERS_GRAPHIC_BAKED;
12715
+ if (options.strict === true && !advisory) {
12670
12716
  throw new SVGConverterError(SVG_CONVERTER_ERROR_CODES.LAYERS_CONVERSION_FAILED, warning.message, {
12671
12717
  stage: 'layers',
12672
12718
  sourceId: selector,
@@ -12710,21 +12756,36 @@ function transformBoxCorners(matrix, box) {
12710
12756
  transformPoint(matrix, box[0], box[3])
12711
12757
  ];
12712
12758
  }
12713
- function mapPointsToBBox(points) {
12759
+ function mapPointsToBBox(points, roundCoordinates) {
12760
+ if (roundCoordinates === void 0) roundCoordinates = true;
12714
12761
  var _Math, _Math1, _Math2, _Math3;
12715
- return [
12716
- roundPixel((_Math = Math).min.apply(_Math, [].concat(points.map(function(point) {
12762
+ var bbox = [
12763
+ (_Math = Math).min.apply(_Math, [].concat(points.map(function(point) {
12717
12764
  return point[0];
12718
- })))),
12719
- roundPixel((_Math1 = Math).min.apply(_Math1, [].concat(points.map(function(point) {
12765
+ }))),
12766
+ (_Math1 = Math).min.apply(_Math1, [].concat(points.map(function(point) {
12720
12767
  return point[1];
12721
- })))),
12722
- roundPixel((_Math2 = Math).max.apply(_Math2, [].concat(points.map(function(point) {
12768
+ }))),
12769
+ (_Math2 = Math).max.apply(_Math2, [].concat(points.map(function(point) {
12723
12770
  return point[0];
12724
- })))),
12725
- roundPixel((_Math3 = Math).max.apply(_Math3, [].concat(points.map(function(point) {
12771
+ }))),
12772
+ (_Math3 = Math).max.apply(_Math3, [].concat(points.map(function(point) {
12726
12773
  return point[1];
12727
- }))))
12774
+ })))
12775
+ ];
12776
+ if (bbox.some(function(value) {
12777
+ return !Number.isFinite(value);
12778
+ })) {
12779
+ throwInvalidLayerData('Non-finite pixel geometry.');
12780
+ }
12781
+ if (!roundCoordinates) {
12782
+ return bbox;
12783
+ }
12784
+ return [
12785
+ roundPixel(bbox[0]),
12786
+ roundPixel(bbox[1]),
12787
+ roundPixel(bbox[2]),
12788
+ roundPixel(bbox[3])
12728
12789
  ];
12729
12790
  }
12730
12791
  function roundPixel(value) {
@@ -12932,7 +12993,7 @@ function parseTextRuns(layer, font, preserved) {
12932
12993
  return spans.filter(function(span) {
12933
12994
  return span.text !== '' || span.newLine;
12934
12995
  }).map(function(span) {
12935
- var fontSize = span.fontSize == null || span.fontSize === '' ? base.fontSize : Number.parseInt(span.fontSize, 10);
12996
+ var fontSize = span.fontSize == null || span.fontSize === '' ? base.fontSize : Number.parseFloat(span.fontSize);
12936
12997
  if (!Number.isFinite(fontSize) || fontSize <= 0) {
12937
12998
  throwInvalidLayerData('Invalid text fragment font size.');
12938
12999
  }
@@ -12961,7 +13022,7 @@ function mapTextColor(color) {
12961
13022
  };
12962
13023
  }
12963
13024
 
12964
- function buildTextRunLayout(runs, family, spacing, content, size, conversionOptions, warnings, id, segmented) {
13025
+ function buildTextRunLayout(runs, family, spacing, content, size, conversionOptions, warnings, id, segmented, renderScale) {
12965
13026
  var _loop = function() {
12966
13027
  var run = _step.value;
12967
13028
  run.text.split('\n').forEach(function(text, index) {
@@ -12976,6 +13037,10 @@ function buildTextRunLayout(runs, family, spacing, content, size, conversionOpti
12976
13037
  });
12977
13038
  };
12978
13039
  if (segmented === void 0) segmented = false;
13040
+ if (renderScale === void 0) renderScale = [
13041
+ 1,
13042
+ 1
13043
+ ];
12979
13044
  var _Math;
12980
13045
  var rows = [
12981
13046
  []
@@ -12988,33 +13053,44 @@ function buildTextRunLayout(runs, family, spacing, content, size, conversionOpti
12988
13053
  }).map(function(row) {
12989
13054
  var _Math, _Math1;
12990
13055
  var parts = row.map(function(run) {
12991
- // 分段文字使用统一参考字号度量字宽和字体边界,再按片段字号缩放。
13056
+ // 基线沿用参考字号指标,字宽按实际输出字号单独测量。
12992
13057
  var measurementSize = segmented ? 10 : run.fontSize;
12993
13058
  var scale = run.fontSize / measurementSize;
12994
- var font = (run.italic ? 'italic' : 'normal') + " " + (run.bold ? 'bold' : 'normal') + " " + measurementSize + "px" + (' "' + family + '"');
13059
+ var weight = run.bold ? 'bold' : 'normal';
13060
+ var style = run.italic ? 'italic' : 'normal';
13061
+ var font = buildCanvasFontDesc(measurementSize, family, weight, style);
12995
13062
  var metrics = conversionOptions.measureText == null ? void 0 : conversionOptions.measureText.call(conversionOptions, font, segmented ? 'x' : run.text);
12996
- var chunks = segmented ? run.text.split('') : [
12997
- run.text
12998
- ];
12999
- var advance = 0;
13000
- for(var _iterator = _create_for_of_iterator_helper_loose(chunks), _step; !(_step = _iterator()).done;){
13001
- var chunk = _step.value;
13002
- var width = segmented ? conversionOptions.measureText == null ? void 0 : conversionOptions.measureText.call(conversionOptions, font, chunk).width : metrics == null ? void 0 : metrics.width;
13003
- var valid = width != null && Number.isFinite(width) && width >= 0;
13004
- estimated || (estimated = !valid);
13005
- advance += valid ? width : Array.from(chunk).length * measurementSize * 0.6;
13006
- }
13007
- var characterCount = segmented ? run.text.length : Array.from(run.text).length;
13008
- var width1 = advance * scale + Math.max(0, characterCount - 1) * spacing;
13009
- var ascent = (metrics == null ? void 0 : metrics.fontBoundingBoxAscent) == null ? run.fontSize * 0.8 : metrics.fontBoundingBoxAscent * scale;
13010
- var descent = (metrics == null ? void 0 : metrics.fontBoundingBoxDescent) == null ? run.fontSize * 0.2 : metrics.fontBoundingBoxDescent * scale;
13063
+ var characters = Array.from(run.text);
13064
+ // 片段协议不输出额外字重和斜体,测宽使用同样的普通样式。
13065
+ var widthFontSize = run.fontSize * renderScale[1];
13066
+ var widthFont = buildCanvasFontDesc(widthFontSize, family, 'normal', 'normal');
13067
+ var measureWidth = function measureWidth(text) {
13068
+ var width = conversionOptions.measureText == null ? void 0 : conversionOptions.measureText.call(conversionOptions, widthFont, text).width;
13069
+ if (width != null && Number.isFinite(width) && width >= 0) {
13070
+ return width;
13071
+ }
13072
+ estimated = true;
13073
+ return estimateTextWidth(text, widthFontSize, 0, undefined, family, 'normal', 'normal');
13074
+ };
13075
+ // 字距和字宽交替累加,保持与 Artis 逐字测宽的计算顺序一致。
13076
+ var renderedWidth = 0;
13077
+ characters.forEach(function(character, index) {
13078
+ if (index > 0) {
13079
+ renderedWidth += spacing * renderScale[0];
13080
+ }
13081
+ renderedWidth += measureWidth(character);
13082
+ });
13083
+ var width = renderedWidth / renderScale[0];
13084
+ var fallback = resolveFontMetrics(undefined, family, weight, style, run.fontSize);
13085
+ var ascent = (metrics == null ? void 0 : metrics.fontBoundingBoxAscent) == null ? fallback.asc : metrics.fontBoundingBoxAscent * scale;
13086
+ var descent = (metrics == null ? void 0 : metrics.fontBoundingBoxDescent) == null ? fallback.desc : metrics.fontBoundingBoxDescent * scale;
13011
13087
  estimated || (estimated = (metrics == null ? void 0 : metrics.fontBoundingBoxAscent) == null || metrics.fontBoundingBoxDescent == null);
13012
- if (!Number.isFinite(width1) || width1 < 0 || !Number.isFinite(ascent) || !Number.isFinite(descent)) {
13088
+ if (!Number.isFinite(width) || width < 0 || !Number.isFinite(ascent) || !Number.isFinite(descent)) {
13013
13089
  throwInvalidLayerData('Text measurement returned invalid metrics.');
13014
13090
  }
13015
13091
  return {
13016
13092
  run: run,
13017
- width: width1,
13093
+ width: width,
13018
13094
  ascent: ascent,
13019
13095
  descent: descent
13020
13096
  };
@@ -13127,7 +13203,10 @@ function convertIRTextLayer(layer, state, session, id) {
13127
13203
  var positioned = buildTextRunLayout(runs, font.family, layer.content.letterSpacing, layer.content, [
13128
13204
  bounds.width,
13129
13205
  height
13130
- ], options, warnings, id, preserved != null);
13206
+ ], options, warnings, id, preserved != null, [
13207
+ scaleX,
13208
+ scaleY
13209
+ ]);
13131
13210
  if (positioned.length === 0) {
13132
13211
  return undefined;
13133
13212
  }
@@ -13141,25 +13220,25 @@ function convertIRTextLayer(layer, state, session, id) {
13141
13220
  part.box[3] + centerY
13142
13221
  ]);
13143
13222
  });
13144
- var bbox = mapPointsToBBox(polygons.flat());
13145
- var rotation = roundPixel(Math.atan2(matrix.b, matrix.a) * 180 / Math.PI);
13223
+ var bbox = mapPointsToBBox(polygons.flat(), false);
13224
+ var rotation = Math.atan2(matrix.b, matrix.a) * 180 / Math.PI;
13146
13225
  var fragments = positioned.map(function(part, index) {
13147
13226
  var polygon = polygons[index].map(function(point) {
13148
13227
  return [
13149
- roundPixel(point[0] - bbox[0]),
13150
- roundPixel(point[1] - bbox[1])
13228
+ point[0] - bbox[0],
13229
+ point[1] - bbox[1]
13151
13230
  ];
13152
13231
  });
13153
13232
  return {
13154
13233
  content: part.run.text,
13155
- bbox: mapPointsToBBox(polygon),
13234
+ bbox: mapPointsToBBox(polygon, false),
13156
13235
  polygon: polygon,
13157
- font_family: font.family,
13158
- font_size: roundPixel(part.run.fontSize * scaleY),
13236
+ font_family: normalizeFontFamilyName(font.family),
13237
+ font_size: part.run.fontSize * scaleY,
13159
13238
  color: part.run.color,
13160
- letter_spacing: roundPixel(layer.content.letterSpacing * scaleX),
13239
+ letter_spacing: layer.content.letterSpacing * scaleX,
13161
13240
  direction: 'horizontal',
13162
- rotation: rotation
13241
+ rotation: rotation === 0 ? 0 : rotation
13163
13242
  };
13164
13243
  });
13165
13244
  return {
@@ -13198,7 +13277,43 @@ function createLayerConverterRegistry(session) {
13198
13277
  ]);
13199
13278
  }
13200
13279
 
13280
+ /** 完全覆盖图片的直边矩形 mask 不改变可见内容。 */ function maskCoversImage(mask, bounds) {
13281
+ var _Math, _Math1, _Math2, _Math3;
13282
+ var path = mask.path;
13283
+ var epsilon = 1e-6;
13284
+ if (mask.mode === 'subtract' || mask.inverted === true || !path.closed || path.points.length !== 4) {
13285
+ return false;
13286
+ }
13287
+ if (path.inTangents.length !== 4 || path.outTangents.length !== 4 || [].concat(path.inTangents, path.outTangents).some(function(tangent) {
13288
+ return tangent.x !== 0 || tangent.y !== 0;
13289
+ })) {
13290
+ return false;
13291
+ }
13292
+ var straightEdges = path.points.every(function(point, index) {
13293
+ var next = path.points[(index + 1) % 4];
13294
+ var opposite = path.points[(index + 2) % 4];
13295
+ var dx = Math.abs(next.x - point.x);
13296
+ var dy = Math.abs(next.y - point.y);
13297
+ return Number.isFinite(point.x) && Number.isFinite(point.y) && Math.abs(opposite.x - point.x) > epsilon && Math.abs(opposite.y - point.y) > epsilon && (dx <= epsilon && dy > epsilon || dy <= epsilon && dx > epsilon);
13298
+ });
13299
+ if (!straightEdges) {
13300
+ return false;
13301
+ }
13302
+ var xs = path.points.map(function(point) {
13303
+ return point.x;
13304
+ });
13305
+ var ys = path.points.map(function(point) {
13306
+ return point.y;
13307
+ });
13308
+ var left = (_Math = Math).min.apply(_Math, [].concat(xs));
13309
+ var right = (_Math1 = Math).max.apply(_Math1, [].concat(xs));
13310
+ var top = (_Math2 = Math).min.apply(_Math2, [].concat(ys));
13311
+ var bottom = (_Math3 = Math).max.apply(_Math3, [].concat(ys));
13312
+ return bounds.width > 0 && bounds.height > 0 && left <= bounds.x + epsilon && right >= bounds.x + bounds.width - epsilon && top <= bounds.y + epsilon && bottom >= bounds.y + bounds.height - epsilon;
13313
+ }
13314
+
13201
13315
  function resolveIRVisualState(layer, session) {
13316
+ var _layer_masks;
13202
13317
  if (!layer.visible) {
13203
13318
  return undefined;
13204
13319
  }
@@ -13206,19 +13321,22 @@ function resolveIRVisualState(layer, session) {
13206
13321
  if (!state.visible || state.opacity <= 0) {
13207
13322
  return undefined;
13208
13323
  }
13209
- if (layer.mask != null || layer.matte != null) {
13324
+ var unsupportedMask = ((_layer_masks = layer.masks) != null ? _layer_masks : []).some(function(mask) {
13325
+ return layer.type !== 'image' || !maskCoversImage(mask, layer.localBounds);
13326
+ });
13327
+ if (unsupportedMask || layer.matte != null) {
13210
13328
  throwUnsupportedLayerFeature('Mask or clipping is not supported by the flat layer protocol.');
13211
13329
  }
13212
13330
  if (Math.abs(state.opacity - 1) > 1e-6) {
13213
13331
  throwUnsupportedLayerFeature('Layer opacity cannot be expressed by the target protocol.');
13214
13332
  }
13215
13333
  if (layer.blendMode != null && layer.blendMode !== IRBlendMode.Normal) {
13216
- throwUnsupportedLayerFeature('Non-default blending cannot be expressed by the target protocol.');
13334
+ collectLayerWarning(session.warnings, session.options, SVG2IR_WARNING_CODES.LAYERS_BLEND_MODE_DOWNGRADED, 'Blend mode "' + String(layer.blendMode) + '" was downgraded to "normal"; the layer is retained.', layer.id);
13217
13335
  }
13218
13336
  return state;
13219
13337
  }
13220
13338
 
13221
- function buildIRStaticLayers(session) {
13339
+ function buildIRStaticLayers(session, sourceIds) {
13222
13340
  var composition = session.composition, maskSourceIds = session.maskSourceIds, options = session.options, warnings = session.warnings;
13223
13341
  var registry = createLayerConverterRegistry(session);
13224
13342
  var result = [];
@@ -13243,6 +13361,7 @@ function buildIRStaticLayers(session) {
13243
13361
  var converted = converter.convert(layer, state, converter.layerType + "_" + String(index).padStart(4, '0'));
13244
13362
  if (converted != null) {
13245
13363
  result.push(converted);
13364
+ sourceIds == null ? void 0 : sourceIds.set(converted, layer.id);
13246
13365
  layerCounts.set(converter.layerType, index);
13247
13366
  }
13248
13367
  } catch (error) {
@@ -13255,9 +13374,9 @@ function buildIRStaticLayers(session) {
13255
13374
  return result;
13256
13375
  }
13257
13376
 
13258
- function assembleSVGStaticLayers(scene, options, warnings, preservedData) {
13377
+ function assembleSVGStaticLayers(scene, options, warnings, preservedData, sourceIds) {
13259
13378
  var session = buildLayerConversionSession(scene, options, warnings, preservedData);
13260
- var data = buildIRStaticLayers(session);
13379
+ var data = buildIRStaticLayers(session, sourceIds);
13261
13380
  var composition = session.composition;
13262
13381
  if (composition.backgroundColor != null) {
13263
13382
  collectLayerWarning(warnings, options, SVG2IR_WARNING_CODES.LAYERS_UNSUPPORTED_TYPE, 'Composition background color is not an image or text layer.');
@@ -13270,6 +13389,1035 @@ function assembleSVGStaticLayers(scene, options, warnings, preservedData) {
13270
13389
  data: data
13271
13390
  };
13272
13391
  }
13392
+ /** Replace baked sources, combine native and raster layers in painter order, then report final diagnostics. */ function assembleSVGLayers(input) {
13393
+ var _warnings, _ordered;
13394
+ var _input_context = input.context, scene = _input_context.ir, contextWarnings = _input_context.warnings, preservedData = _input_context.preservedData, layerSources = _input_context.layerSources, warningSources = _input_context.warningSources;
13395
+ var options = input.options, baking = input.baking;
13396
+ var warnings = contextWarnings.filter(function(warning) {
13397
+ return !baking.resolvesWarning(warning, warningSources.get(warning));
13398
+ });
13399
+ var composition = getIRSceneEntryComposition(scene);
13400
+ var nativeScene = _extends({}, scene, {
13401
+ compositions: scene.compositions.map(function(candidate) {
13402
+ return candidate === composition ? _extends({}, candidate, {
13403
+ layers: candidate.layers.filter(function(layer) {
13404
+ return !baking.replacesSource(layerSources.get(layer.id));
13405
+ })
13406
+ }) : candidate;
13407
+ })
13408
+ });
13409
+ var sourceIds = new Map();
13410
+ (_warnings = warnings).push.apply(_warnings, [].concat(baking.warnings));
13411
+ var native = assembleSVGStaticLayers(nativeScene, _extends({}, options, {
13412
+ strict: false,
13413
+ onWarning: undefined
13414
+ }), warnings, preservedData, sourceIds);
13415
+ var ordered = native.data.map(function(layer) {
13416
+ var _layerSources_get, _sourceIds_get;
13417
+ return {
13418
+ path: (_layerSources_get = layerSources.get((_sourceIds_get = sourceIds.get(layer)) != null ? _sourceIds_get : '')) != null ? _layerSources_get : '',
13419
+ layer: layer
13420
+ };
13421
+ });
13422
+ (_ordered = ordered).push.apply(_ordered, [].concat(baking.layers));
13423
+ ordered.sort(function(left, right) {
13424
+ return comparePaths(left.path, right.path);
13425
+ });
13426
+ var counts = {
13427
+ image: 0,
13428
+ text: 0
13429
+ };
13430
+ var data = ordered.map(function(param) {
13431
+ var layer = param.layer;
13432
+ return _extends({}, layer, {
13433
+ id: layer.type + "_" + String(++counts[layer.type]).padStart(4, '0')
13434
+ });
13435
+ });
13436
+ for(var _iterator = _create_for_of_iterator_helper_loose(warnings), _step; !(_step = _iterator()).done;){
13437
+ var warning = _step.value;
13438
+ options.onWarning == null ? void 0 : options.onWarning.call(options, warning);
13439
+ if (options.strict === true) {
13440
+ var message = warning.message.replace(/^\[svg2ge:layers\] /, '');
13441
+ collectLayerWarning([], _extends({}, options, {
13442
+ onWarning: undefined
13443
+ }), warning.code, message, warning.elementSelector);
13444
+ }
13445
+ }
13446
+ return {
13447
+ size: native.size,
13448
+ data: data,
13449
+ warnings: warnings
13450
+ };
13451
+ }
13452
+ function comparePaths(left, right) {
13453
+ var a = left.split('/').map(Number);
13454
+ var b = right.split('/').map(Number);
13455
+ for(var index = 0; index < Math.min(a.length, b.length); index++){
13456
+ if (a[index] !== b[index]) {
13457
+ return a[index] - b[index];
13458
+ }
13459
+ }
13460
+ return a.length - b.length;
13461
+ }
13462
+
13463
+ var animatedElements = new Set([
13464
+ 'animate',
13465
+ 'animatetransform',
13466
+ 'animatemotion',
13467
+ 'set'
13468
+ ]);
13469
+ var declarations$1 = new Set([
13470
+ 'defs',
13471
+ 'style',
13472
+ 'title',
13473
+ 'desc',
13474
+ 'metadata',
13475
+ 'symbol',
13476
+ 'clippath',
13477
+ 'mask',
13478
+ 'filter',
13479
+ 'lineargradient',
13480
+ 'radialgradient',
13481
+ 'pattern',
13482
+ 'marker'
13483
+ ]);
13484
+ /** Preserve selector context until styles are frozen, then isolate the requested paint subtree. */ function prepareSVGSnapshot(source, path, size, inspect) {
13485
+ var parsed = new DOMParser().parseFromString(source, 'image/svg+xml');
13486
+ if (parsed.querySelector('parsererror') != null) {
13487
+ throw new Error('Invalid SVG document.');
13488
+ }
13489
+ var root = parsed.documentElement;
13490
+ var elements = [].concat([
13491
+ root
13492
+ ], Array.from(root.querySelectorAll('*')));
13493
+ var selected = elements.find(function(element) {
13494
+ return buildElementTreePath(element) === path;
13495
+ });
13496
+ if (selected == null) {
13497
+ throw new Error('The graphic source element could not be located.');
13498
+ }
13499
+ if (root.querySelector('script, foreignObject') != null) {
13500
+ throw new Error('Scripts and foreignObject are outside static graphic baking support.');
13501
+ }
13502
+ if (Array.from(root.querySelectorAll('style')).some(function(element) {
13503
+ var _element_textContent;
13504
+ return /@import|@font-face/i.test((_element_textContent = element.textContent) != null ? _element_textContent : '');
13505
+ })) {
13506
+ throw new Error('External stylesheets and fonts require explicit resource preparation.');
13507
+ }
13508
+ for(var _iterator = _create_for_of_iterator_helper_loose(elements), _step; !(_step = _iterator()).done;){
13509
+ var element = _step.value;
13510
+ for(var _iterator1 = _create_for_of_iterator_helper_loose(Array.from(element.attributes)), _step1; !(_step1 = _iterator1()).done;){
13511
+ var attribute = _step1.value;
13512
+ if (/^on/i.test(attribute.name)) {
13513
+ element.removeAttributeNode(attribute);
13514
+ }
13515
+ }
13516
+ }
13517
+ var frame = document.createElement('iframe');
13518
+ frame.setAttribute('sandbox', 'allow-same-origin');
13519
+ frame.style.cssText = "position:fixed;left:-100000px;top:0;width:" + size[0] + "px;height:" + size[1] + "px;border:0;";
13520
+ document.body.appendChild(frame);
13521
+ try {
13522
+ var _loop = function() {
13523
+ var element = _step3.value;
13524
+ var _element_getAttribute;
13525
+ var computed = frameWindow.getComputedStyle(element);
13526
+ var inside = target.contains(element);
13527
+ var ancestor = element !== target && element.contains(target);
13528
+ if ((inside || ancestor) && (computed.animationName !== 'none' || hasAnimationChildren(element))) {
13529
+ throw new Error('Animated graphics require an explicit sampling policy.');
13530
+ }
13531
+ // Freezing inherited defaults on a definition changes <use> instance inheritance.
13532
+ // Freeze only authored declarations, after matching selectors in the intact source tree.
13533
+ var authored = frameDocument.createElement('div').style;
13534
+ authored.cssText = (_element_getAttribute = element.getAttribute('style')) != null ? _element_getAttribute : '';
13535
+ var names = new Set(Array.from(authored));
13536
+ for(var _iterator = _create_for_of_iterator_helper_loose(styleRules), _step; !(_step = _iterator()).done;){
13537
+ var rule = _step.value;
13538
+ if (element.matches(rule.selectorText)) {
13539
+ for(var _iterator1 = _create_for_of_iterator_helper_loose(Array.from(rule.style)), _step1; !(_step1 = _iterator1()).done;){
13540
+ var name = _step1.value;
13541
+ names.add(name);
13542
+ }
13543
+ }
13544
+ }
13545
+ var properties = Array.from(names, function(name) {
13546
+ var value = computed.getPropertyValue(name);
13547
+ value = value.replace(/url\(["']?([^)'"\s]+)["']?\)/g, function(_match, url) {
13548
+ return 'url("' + normalizeReference(url) + '")';
13549
+ });
13550
+ return name + ":" + value + " !important;";
13551
+ });
13552
+ var isTemplate = templateRoots.some(function(template) {
13553
+ return template.contains(element);
13554
+ });
13555
+ frozenStyles.push(isTemplate ? null : properties.join(''));
13556
+ };
13557
+ var frameDocument = frame.contentDocument;
13558
+ var frameWindow = frame.contentWindow;
13559
+ if (frameDocument == null || frameWindow == null) {
13560
+ throw new Error('Unable to create isolated SVG context.');
13561
+ }
13562
+ frameDocument.body.style.cssText = 'margin:0;';
13563
+ var mounted = frameDocument.importNode(root, true);
13564
+ mounted.setAttribute('width', String(size[0]));
13565
+ mounted.setAttribute('height', String(size[1]));
13566
+ frameDocument.body.appendChild(mounted);
13567
+ var mountedElements = [].concat([
13568
+ mounted
13569
+ ], Array.from(mounted.querySelectorAll('*')));
13570
+ var selectedIndex = elements.indexOf(selected);
13571
+ var target = mountedElements[selectedIndex];
13572
+ var normalizeReference = function normalizeReference(url) {
13573
+ if (url.startsWith('#')) {
13574
+ return url;
13575
+ }
13576
+ var hash = url.indexOf('#');
13577
+ if (hash >= 0 && url.slice(0, hash) === frameDocument.baseURI.split('#')[0]) {
13578
+ return url.slice(hash);
13579
+ }
13580
+ throw new Error('External paint resources require explicit resource preparation.');
13581
+ };
13582
+ var frozenStyles = [];
13583
+ var templateRoots = Array.from(mounted.querySelectorAll('use')).flatMap(function(element) {
13584
+ var _ref, _element_getAttribute;
13585
+ var href = (_ref = (_element_getAttribute = element.getAttribute('href')) != null ? _element_getAttribute : element.getAttribute('xlink:href')) != null ? _ref : '';
13586
+ var template = href.startsWith('#') ? mountedElements.find(function(candidate) {
13587
+ return candidate.id === href.slice(1);
13588
+ }) : null;
13589
+ return template == null ? [] : [
13590
+ template
13591
+ ];
13592
+ });
13593
+ var styleRules = [];
13594
+ var collectRules = function collectRules1(rules) {
13595
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(rules)), _step; !(_step = _iterator()).done;){
13596
+ var rule = _step.value;
13597
+ if (isStyleRule$2(rule)) {
13598
+ styleRules.push(rule);
13599
+ } else if (hasNestedRules$1(rule)) {
13600
+ if (isMediaRule(rule) && !frameWindow.matchMedia(rule.conditionText).matches) {
13601
+ continue;
13602
+ }
13603
+ collectRules(rule.cssRules);
13604
+ }
13605
+ }
13606
+ };
13607
+ for(var _iterator2 = _create_for_of_iterator_helper_loose(Array.from(frameDocument.styleSheets)), _step2; !(_step2 = _iterator2()).done;){
13608
+ var sheet = _step2.value;
13609
+ collectRules(sheet.cssRules);
13610
+ }
13611
+ for(var _iterator3 = _create_for_of_iterator_helper_loose(mountedElements), _step3; !(_step3 = _iterator3()).done;)_loop();
13612
+ for(var index = 0; index < mountedElements.length; index++){
13613
+ var style = frozenStyles[index];
13614
+ if (style != null) {
13615
+ mountedElements[index].setAttribute('style', style);
13616
+ }
13617
+ }
13618
+ var byId = new Map(mountedElements.filter(function(element) {
13619
+ return element.id !== '';
13620
+ }).map(function(element) {
13621
+ return [
13622
+ element.id,
13623
+ element
13624
+ ];
13625
+ }));
13626
+ var seen = new Set();
13627
+ var checkDependencies = function checkDependencies1(element) {
13628
+ if (seen.has(element)) {
13629
+ return;
13630
+ }
13631
+ seen.add(element);
13632
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(element.attributes)), _step; !(_step = _iterator()).done;){
13633
+ var attribute = _step.value;
13634
+ if (attribute.localName === 'href' && element.tagName.toLowerCase() === 'a') {
13635
+ continue;
13636
+ }
13637
+ if (attribute.localName === 'href' && !attribute.value.startsWith('#') && !([
13638
+ 'image',
13639
+ 'feimage'
13640
+ ].includes(element.tagName.toLowerCase()) && /^data:image\//i.test(attribute.value))) {
13641
+ throw new Error('External SVG references require explicit resource preparation.');
13642
+ }
13643
+ var normalized = attribute.value.replace(/url\(\s*["']?([^)'"\s]+)["']?\s*\)/g, function(_match, url) {
13644
+ return 'url("' + normalizeReference(url) + '")';
13645
+ });
13646
+ var ids = Array.from(normalized.matchAll(/url\(["']?#([^)'"\s]+)["']?\)/g), function(match) {
13647
+ return match[1];
13648
+ });
13649
+ if (normalized !== attribute.value) {
13650
+ element.setAttribute(attribute.name, normalized);
13651
+ }
13652
+ if (attribute.localName === 'href' && attribute.value.startsWith('#')) {
13653
+ ids.push(attribute.value.slice(1));
13654
+ }
13655
+ for(var _iterator1 = _create_for_of_iterator_helper_loose(ids), _step1; !(_step1 = _iterator1()).done;){
13656
+ var id = _step1.value;
13657
+ var dependency = byId.get(id);
13658
+ if (dependency == null) {
13659
+ throw new Error("Missing SVG reference: #" + id + ".");
13660
+ }
13661
+ checkDependencies(dependency);
13662
+ }
13663
+ }
13664
+ for(var _iterator2 = _create_for_of_iterator_helper_loose(Array.from(element.children)), _step2; !(_step2 = _iterator2()).done;){
13665
+ var child = _step2.value;
13666
+ if (!declarations$1.has(child.tagName.toLowerCase())) {
13667
+ checkDependencies(child);
13668
+ }
13669
+ }
13670
+ };
13671
+ checkDependencies(target);
13672
+ for(var _iterator4 = _create_for_of_iterator_helper_loose(seen), _step4; !(_step4 = _iterator4()).done;){
13673
+ var dependency = _step4.value;
13674
+ if (frameWindow.getComputedStyle(dependency).animationName !== 'none' || hasAnimationChildren(dependency)) {
13675
+ throw new Error('Animated graphics require an explicit sampling policy.');
13676
+ }
13677
+ }
13678
+ inspect == null ? void 0 : inspect({
13679
+ root: mounted,
13680
+ target: target,
13681
+ elements: mountedElements,
13682
+ dependencies: seen,
13683
+ readStyle: function readStyle(element) {
13684
+ return frameWindow.getComputedStyle(element);
13685
+ }
13686
+ });
13687
+ var isolate = function isolate1(element) {
13688
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(element.children)), _step; !(_step = _iterator()).done;){
13689
+ var child = _step.value;
13690
+ var tag = child.tagName.toLowerCase();
13691
+ if (declarations$1.has(tag) || child === target || target.contains(child)) {
13692
+ continue;
13693
+ }
13694
+ if (child.contains(target)) {
13695
+ isolate(child);
13696
+ } else {
13697
+ var definitions = frameDocument.createElementNS('http://www.w3.org/2000/svg', 'defs');
13698
+ child.replaceWith(definitions);
13699
+ definitions.appendChild(child);
13700
+ }
13701
+ }
13702
+ };
13703
+ if (target !== mounted) {
13704
+ isolate(mounted);
13705
+ }
13706
+ return new XMLSerializer().serializeToString(mounted);
13707
+ } finally{
13708
+ frame.remove();
13709
+ }
13710
+ }
13711
+ /** Only animations attached to this element reject its own bake scope, not unrelated subtrees. */ function hasAnimationChildren(element) {
13712
+ return Array.from(element.children).some(function(child) {
13713
+ return animatedElements.has(child.tagName.toLowerCase());
13714
+ });
13715
+ }
13716
+ function isStyleRule$2(rule) {
13717
+ return rule.type === 1;
13718
+ }
13719
+ function hasNestedRules$1(rule) {
13720
+ return 'cssRules' in rule;
13721
+ }
13722
+ function isMediaRule(rule) {
13723
+ return rule.type === 4;
13724
+ }
13725
+
13726
+ /** Render an SVG subtree as a cropped PNG, or return null if it has no visible pixels. */ function rasterizeSVG(source, path, size, scale, inspect) {
13727
+ if (scale === void 0) scale = 2;
13728
+ return _async_to_generator(function() {
13729
+ var snapshot, canvas;
13730
+ return _ts_generator(this, function(_state) {
13731
+ switch(_state.label){
13732
+ case 0:
13733
+ if (!Number.isFinite(scale) || scale <= 0) {
13734
+ throw new RangeError('rasterScale must be finite and positive.');
13735
+ }
13736
+ if (Math.ceil(size[0] * scale) * Math.ceil(size[1] * scale) > 16777216) {
13737
+ throw new RangeError('SVG rasterization exceeds the 16 megapixel working limit; reduce rasterScale.');
13738
+ }
13739
+ snapshot = prepareSVGSnapshot(source, path, size, inspect);
13740
+ return [
13741
+ 4,
13742
+ renderSVG(snapshot, size, scale)
13743
+ ];
13744
+ case 1:
13745
+ canvas = _state.sent();
13746
+ return [
13747
+ 2,
13748
+ cropRasterImage(canvas, scale)
13749
+ ];
13750
+ }
13751
+ });
13752
+ })();
13753
+ }
13754
+ /** No DOM access at module initialization: the Node entry also imports this module. */ function canRasterizeSVG() {
13755
+ return typeof window !== 'undefined' && typeof document !== 'undefined' && typeof window.HTMLCanvasElement === 'function' && typeof window.Image === 'function' && typeof window.getComputedStyle === 'function';
13756
+ }
13757
+ function renderSVG(svg, size, scale) {
13758
+ return _async_to_generator(function() {
13759
+ var canvas, context, image, url;
13760
+ return _ts_generator(this, function(_state) {
13761
+ switch(_state.label){
13762
+ case 0:
13763
+ canvas = document.createElement('canvas');
13764
+ canvas.width = Math.ceil(size[0] * scale);
13765
+ canvas.height = Math.ceil(size[1] * scale);
13766
+ context = canvas.getContext('2d');
13767
+ if (context == null) {
13768
+ throw new Error('A 2D canvas context is required for SVG rasterization.');
13769
+ }
13770
+ image = new Image();
13771
+ url = URL.createObjectURL(new Blob([
13772
+ svg
13773
+ ], {
13774
+ type: 'image/svg+xml'
13775
+ }));
13776
+ _state.label = 1;
13777
+ case 1:
13778
+ _state.trys.push([
13779
+ 1,
13780
+ ,
13781
+ 3,
13782
+ 4
13783
+ ]);
13784
+ return [
13785
+ 4,
13786
+ new Promise(function(resolve, reject) {
13787
+ image.onload = function() {
13788
+ return resolve();
13789
+ };
13790
+ image.onerror = function() {
13791
+ return reject(new Error('The prepared SVG could not be decoded.'));
13792
+ };
13793
+ image.src = url;
13794
+ })
13795
+ ];
13796
+ case 2:
13797
+ _state.sent();
13798
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
13799
+ return [
13800
+ 2,
13801
+ canvas
13802
+ ];
13803
+ case 3:
13804
+ URL.revokeObjectURL(url);
13805
+ return [
13806
+ 7
13807
+ ];
13808
+ case 4:
13809
+ return [
13810
+ 2
13811
+ ];
13812
+ }
13813
+ });
13814
+ })();
13815
+ }
13816
+ /** Trim transparent pixels after rendering, retaining strokes, blur and filter extents. */ function cropRasterImage(canvas, scale) {
13817
+ var context = canvas.getContext('2d');
13818
+ if (context == null) {
13819
+ throw new Error('A 2D canvas context is required for SVG rasterization.');
13820
+ }
13821
+ var data = context.getImageData(0, 0, canvas.width, canvas.height).data;
13822
+ var left = canvas.width;
13823
+ var top = canvas.height;
13824
+ var right = 0;
13825
+ var bottom = 0;
13826
+ for(var y = 0; y < canvas.height; y++){
13827
+ for(var x = 0; x < canvas.width; x++){
13828
+ if (data[(y * canvas.width + x) * 4 + 3] === 0) {
13829
+ continue;
13830
+ }
13831
+ left = Math.min(left, x);
13832
+ top = Math.min(top, y);
13833
+ right = Math.max(right, x + 1);
13834
+ bottom = Math.max(bottom, y + 1);
13835
+ }
13836
+ }
13837
+ if (right <= left || bottom <= top) {
13838
+ return null;
13839
+ }
13840
+ var cropped = document.createElement('canvas');
13841
+ cropped.width = right - left;
13842
+ cropped.height = bottom - top;
13843
+ var croppedContext = cropped.getContext('2d');
13844
+ if (croppedContext == null) {
13845
+ throw new Error('A 2D canvas context is required for SVG rasterization.');
13846
+ }
13847
+ croppedContext.drawImage(canvas, left, top, cropped.width, cropped.height, 0, 0, cropped.width, cropped.height);
13848
+ return {
13849
+ url: cropped.toDataURL('image/png'),
13850
+ bbox: [
13851
+ left / scale,
13852
+ top / scale,
13853
+ right / scale,
13854
+ bottom / scale
13855
+ ]
13856
+ };
13857
+ }
13858
+
13859
+ var normalValues = new Set([
13860
+ 'normal',
13861
+ 'initial',
13862
+ 'inherit',
13863
+ 'unset',
13864
+ 'revert',
13865
+ 'revert-layer'
13866
+ ]);
13867
+ /** Replace non-normal mix-blend-mode declarations with normal and report each downgrade. */ function normalizeLayerBlending(source) {
13868
+ var _loop = function() {
13869
+ var element = _step.value;
13870
+ var _element_getAttribute;
13871
+ var _readPresentationAttribute;
13872
+ var tag = element.tagName.toLowerCase();
13873
+ var id = (_element_getAttribute = element.getAttribute('id')) != null ? _element_getAttribute : '';
13874
+ var selector = id === '' ? tag : tag + "#" + id;
13875
+ var mode = (_readPresentationAttribute = readPresentationAttribute(element, 'mix-blend-mode')) == null ? void 0 : _readPresentationAttribute.replace(/\/\*[\s\S]*?\*\//g, '').trim();
13876
+ if (mode != null && !normalValues.has(mode.toLowerCase())) {
13877
+ downgrades.push({
13878
+ mode: mode,
13879
+ selector: selector
13880
+ });
13881
+ }
13882
+ var style = element.getAttribute('style');
13883
+ if (style != null) {
13884
+ var normalized = normalizeBlendDeclarations(style);
13885
+ if (normalized !== style) {
13886
+ element.setAttribute('style', normalized);
13887
+ changed = true;
13888
+ }
13889
+ }
13890
+ var attribute = element.getAttribute('mix-blend-mode');
13891
+ if (attribute != null && !normalValues.has(attribute.trim().toLowerCase())) {
13892
+ element.setAttribute('mix-blend-mode', 'normal');
13893
+ changed = true;
13894
+ }
13895
+ if (tag === 'style') {
13896
+ var _element_textContent;
13897
+ var text = (_element_textContent = element.textContent) != null ? _element_textContent : '';
13898
+ var normalized1 = normalizeBlendDeclarations(text, function(value) {
13899
+ return downgrades.push({
13900
+ mode: value,
13901
+ selector: selector
13902
+ });
13903
+ });
13904
+ if (normalized1 !== text) {
13905
+ element.textContent = normalized1;
13906
+ changed = true;
13907
+ }
13908
+ }
13909
+ };
13910
+ var svg = SVG(source);
13911
+ var downgrades = [];
13912
+ var changed = false;
13913
+ for(var _iterator = _create_for_of_iterator_helper_loose([].concat([
13914
+ svg.node
13915
+ ], Array.from(svg.node.querySelectorAll('*')))), _step; !(_step = _iterator()).done;)_loop();
13916
+ return {
13917
+ source: changed ? svg.svg() : source,
13918
+ downgrades: downgrades
13919
+ };
13920
+ }
13921
+ /** Match declaration boundaries without changing strings, comments or function arguments. */ function normalizeBlendDeclarations(source, onDowngrade) {
13922
+ var replacements = [];
13923
+ var start = 0;
13924
+ var colon = -1;
13925
+ var parentheses = 0;
13926
+ var quote;
13927
+ var comment = false;
13928
+ var finish = function finish(end) {
13929
+ if (colon < start) {
13930
+ return;
13931
+ }
13932
+ var name = source.slice(start, colon).replace(/\/\*[\s\S]*?\*\//g, '').trim().toLowerCase();
13933
+ if (name !== 'mix-blend-mode') {
13934
+ return;
13935
+ }
13936
+ var value = source.slice(colon + 1, end).replace(/\/\*[\s\S]*?\*\//g, '').trim();
13937
+ var mode = value.replace(/\s*!important\s*$/i, '').trim();
13938
+ if (mode === '' || normalValues.has(mode.toLowerCase())) {
13939
+ return;
13940
+ }
13941
+ onDowngrade == null ? void 0 : onDowngrade(mode);
13942
+ replacements.push({
13943
+ start: colon + 1,
13944
+ end: end,
13945
+ value: /!important\s*$/i.test(value) ? ' normal !important' : ' normal'
13946
+ });
13947
+ };
13948
+ for(var index = 0; index < source.length; index++){
13949
+ var character = source[index];
13950
+ var next = source[index + 1];
13951
+ if (comment) {
13952
+ if (character === '*' && next === '/') {
13953
+ comment = false;
13954
+ index++;
13955
+ }
13956
+ continue;
13957
+ }
13958
+ if (quote != null) {
13959
+ if (character === '\\') {
13960
+ index++;
13961
+ } else if (character === quote) {
13962
+ quote = undefined;
13963
+ }
13964
+ continue;
13965
+ }
13966
+ if (character === '/' && next === '*') {
13967
+ comment = true;
13968
+ index++;
13969
+ continue;
13970
+ }
13971
+ if (character === '"' || character === "'") {
13972
+ quote = character;
13973
+ continue;
13974
+ }
13975
+ if (character === '(') {
13976
+ parentheses++;
13977
+ continue;
13978
+ }
13979
+ if (character === ')') {
13980
+ parentheses = Math.max(0, parentheses - 1);
13981
+ continue;
13982
+ }
13983
+ if (parentheses > 0) {
13984
+ continue;
13985
+ }
13986
+ if (character === ':' && colon < start) {
13987
+ colon = index;
13988
+ }
13989
+ if (character === ';' || character === '}' || character === '{') {
13990
+ if (character !== '{') {
13991
+ finish(index);
13992
+ }
13993
+ start = index + 1;
13994
+ colon = -1;
13995
+ }
13996
+ }
13997
+ finish(source.length);
13998
+ var result = '';
13999
+ var cursor = 0;
14000
+ for(var _iterator = _create_for_of_iterator_helper_loose(replacements), _step; !(_step = _iterator()).done;){
14001
+ var replacement = _step.value;
14002
+ result += source.slice(cursor, replacement.start) + replacement.value;
14003
+ cursor = replacement.end;
14004
+ }
14005
+ return result + source.slice(cursor);
14006
+ }
14007
+
14008
+ var declarations = new Set([
14009
+ 'defs',
14010
+ 'style',
14011
+ 'title',
14012
+ 'desc',
14013
+ 'metadata',
14014
+ 'symbol',
14015
+ 'clippath',
14016
+ 'mask',
14017
+ 'filter',
14018
+ 'lineargradient',
14019
+ 'radialgradient',
14020
+ 'pattern',
14021
+ 'marker'
14022
+ ]);
14023
+ var graphics = new Set([
14024
+ 'path',
14025
+ 'rect',
14026
+ 'circle',
14027
+ 'ellipse',
14028
+ 'line',
14029
+ 'polyline',
14030
+ 'polygon',
14031
+ 'use'
14032
+ ]);
14033
+ var containers = new Set([
14034
+ 'svg',
14035
+ 'g',
14036
+ 'a',
14037
+ 'switch'
14038
+ ]);
14039
+ var groupEffects = [
14040
+ 'opacity',
14041
+ 'filter',
14042
+ 'mask',
14043
+ 'clip-path'
14044
+ ];
14045
+ var native = new Set([
14046
+ 'text',
14047
+ 'image',
14048
+ 'foreignobject'
14049
+ ]);
14050
+ /** Select graphic-only subtrees; keep native text and images as separate layers. */ function planGraphicBaking(source) {
14051
+ var root = SVG(source).node;
14052
+ var scopes = [];
14053
+ var warnings = [];
14054
+ var effectRules = collectGroupEffectRules(root);
14055
+ var byId = new Map(Array.from(root.querySelectorAll('[id]')).map(function(element) {
14056
+ var _element_getAttribute;
14057
+ return [
14058
+ (_element_getAttribute = element.getAttribute('id')) != null ? _element_getAttribute : '',
14059
+ element
14060
+ ];
14061
+ }));
14062
+ var tagOf = function tagOf(element) {
14063
+ return element.tagName.toLowerCase();
14064
+ };
14065
+ var selectorOf = function selectorOf(element) {
14066
+ var _element_getAttribute;
14067
+ var id = (_element_getAttribute = element.getAttribute('id')) != null ? _element_getAttribute : '';
14068
+ return "" + tagOf(element) + (id === '' ? '' : "#" + id);
14069
+ };
14070
+ var references = function references(element) {
14071
+ var ids = Array.from(element.attributes).flatMap(function(attribute) {
14072
+ var values = Array.from(attribute.value.matchAll(/url\(\s*['"]?#([^)'"\s]+)['"]?\s*\)/g), function(match) {
14073
+ return match[1];
14074
+ });
14075
+ if (attribute.localName === 'href' && attribute.value.startsWith('#')) {
14076
+ values.push(attribute.value.slice(1));
14077
+ }
14078
+ return values;
14079
+ });
14080
+ return ids.flatMap(function(id) {
14081
+ var target = byId.get(id);
14082
+ return target == null ? [] : [
14083
+ target
14084
+ ];
14085
+ });
14086
+ };
14087
+ var containsNative = function containsNative1(element, seen) {
14088
+ if (seen === void 0) seen = new Set();
14089
+ if (seen.has(element)) {
14090
+ return false;
14091
+ }
14092
+ seen.add(element);
14093
+ if (native.has(tagOf(element))) {
14094
+ return true;
14095
+ }
14096
+ return Array.from(element.children).some(function(child) {
14097
+ return !declarations.has(tagOf(child)) && containsNative(child, seen);
14098
+ }) || references(element).some(function(target) {
14099
+ return containsNative(target, seen);
14100
+ });
14101
+ };
14102
+ var hasGraphics = function hasGraphics1(element) {
14103
+ return graphics.has(tagOf(element)) || Array.from(element.children).some(function(child) {
14104
+ return !declarations.has(tagOf(child)) && hasGraphics(child);
14105
+ });
14106
+ };
14107
+ var hasGroupEffect = function hasGroupEffect(element) {
14108
+ var _element_getAttribute;
14109
+ var style = (_element_getAttribute = element.getAttribute('style')) != null ? _element_getAttribute : '';
14110
+ return effectRules.some(function(rule) {
14111
+ return element.matches(rule.selectorText);
14112
+ }) || hasGraphicGroupEffect(function(name) {
14113
+ var _element_getAttribute;
14114
+ var _exec_, _exec;
14115
+ return (_element_getAttribute = element.getAttribute(name)) != null ? _element_getAttribute : (_exec = new RegExp("(?:^|;)\\s*" + name + "\\s*:\\s*([^;]+)").exec(style)) == null ? void 0 : (_exec_ = _exec[1]) == null ? void 0 : _exec_.trim();
14116
+ });
14117
+ };
14118
+ var visit = function visit1(element) {
14119
+ var _element_getAttribute, _ref;
14120
+ var _exec_, _exec;
14121
+ var tag = tagOf(element);
14122
+ var style = (_element_getAttribute = element.getAttribute('style')) != null ? _element_getAttribute : '';
14123
+ var display = (_ref = (_exec = /(?:^|;)\s*display\s*:\s*([^;]+)/.exec(style)) == null ? void 0 : (_exec_ = _exec[1]) == null ? void 0 : _exec_.trim()) != null ? _ref : element.getAttribute('display');
14124
+ if (display === 'none') {
14125
+ return;
14126
+ }
14127
+ if (declarations.has(tag) || native.has(tag)) {
14128
+ return;
14129
+ }
14130
+ if (!containers.has(tag) && !graphics.has(tag)) {
14131
+ return;
14132
+ }
14133
+ if (!hasGraphics(element)) {
14134
+ return;
14135
+ }
14136
+ if ((graphics.has(tag) || tag === 'switch') && !containsNative(element)) {
14137
+ scopes.push({
14138
+ path: buildElementTreePath(element),
14139
+ selector: selectorOf(element),
14140
+ isGroup: containers.has(tag)
14141
+ });
14142
+ return;
14143
+ }
14144
+ if (hasGroupEffect(element) && !containsNative(element)) {
14145
+ scopes.push({
14146
+ path: buildElementTreePath(element),
14147
+ selector: selectorOf(element),
14148
+ isGroup: containers.has(tag)
14149
+ });
14150
+ return;
14151
+ }
14152
+ if (hasGroupEffect(element)) {
14153
+ warnings.push({
14154
+ message: 'A compositing group contains native text or images; its graphics cannot be baked separately.',
14155
+ selector: selectorOf(element)
14156
+ });
14157
+ return;
14158
+ }
14159
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(element.children)), _step; !(_step = _iterator()).done;){
14160
+ var child = _step.value;
14161
+ visit(child);
14162
+ }
14163
+ };
14164
+ visit(root);
14165
+ return {
14166
+ scopes: scopes,
14167
+ warnings: warnings
14168
+ };
14169
+ }
14170
+ function collectGroupEffectRules(root) {
14171
+ var result = [];
14172
+ if (typeof CSSStyleSheet !== 'function') {
14173
+ return result;
14174
+ }
14175
+ var visit = function visit1(rules) {
14176
+ var _loop = function() {
14177
+ var rule = _step.value;
14178
+ if (isStyleRule$1(rule)) {
14179
+ var affectsGroup = hasGraphicGroupEffect(function(name) {
14180
+ var value = rule.style.getPropertyValue(name).trim();
14181
+ return value === '' || value === 'initial' || value === 'unset' ? undefined : value;
14182
+ });
14183
+ if (affectsGroup) {
14184
+ result.push(rule);
14185
+ }
14186
+ } else if (hasNestedRules(rule)) {
14187
+ visit(rule.cssRules);
14188
+ }
14189
+ };
14190
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(rules)), _step; !(_step = _iterator()).done;)_loop();
14191
+ };
14192
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(root.querySelectorAll('style'))), _step; !(_step = _iterator()).done;){
14193
+ var style = _step.value;
14194
+ var _style_textContent;
14195
+ var sheet = new CSSStyleSheet();
14196
+ sheet.replaceSync((_style_textContent = style.textContent) != null ? _style_textContent : '');
14197
+ visit(sheet.cssRules);
14198
+ }
14199
+ return result;
14200
+ }
14201
+ /** Reject text/image dependencies and effects that cannot be rendered independently. */ function validateGraphicSnapshot(context) {
14202
+ var _loop = function() {
14203
+ var element = _step1.value;
14204
+ var computed = readStyle(element);
14205
+ var ancestor = element !== target && element.contains(target);
14206
+ var groupEffect = ancestor && hasGraphicGroupEffect(function(name) {
14207
+ return name === 'mask' ? computed.maskImage : computed.getPropertyValue(name);
14208
+ });
14209
+ if (ancestor && (groupEffect || computed.mixBlendMode !== 'normal')) {
14210
+ throw new Error('A mixed group effect cannot be applied independently to its graphics.');
14211
+ }
14212
+ if (target.contains(element) && target !== root && computed.mixBlendMode !== 'normal') {
14213
+ throw new Error('Blend modes that depend on an external backdrop cannot be baked independently.');
14214
+ }
14215
+ };
14216
+ var root = context.root, target = context.target, elements = context.elements, dependencies = context.dependencies, readStyle = context.readStyle;
14217
+ for(var _iterator = _create_for_of_iterator_helper_loose(dependencies), _step; !(_step = _iterator()).done;){
14218
+ var element = _step.value;
14219
+ if ([
14220
+ 'text',
14221
+ 'image',
14222
+ 'foreignobject'
14223
+ ].includes(element.tagName.toLowerCase())) {
14224
+ throw new Error('Graphic dependencies contain native text or images; they must remain editable.');
14225
+ }
14226
+ }
14227
+ for(var _iterator1 = _create_for_of_iterator_helper_loose(elements), _step1; !(_step1 = _iterator1()).done;)_loop();
14228
+ }
14229
+ function isStyleRule$1(rule) {
14230
+ return rule.type === 1;
14231
+ }
14232
+ function hasNestedRules(rule) {
14233
+ return 'cssRules' in rule;
14234
+ }
14235
+ function hasGraphicGroupEffect(readValue) {
14236
+ return groupEffects.some(function(name) {
14237
+ var value = readValue(name);
14238
+ return value != null && value !== 'none' && value !== 'normal' && value !== '1';
14239
+ });
14240
+ }
14241
+
14242
+ /** Mask and clipPath definitions do not produce visible layers. */ function collectNonRenderingDeclarationPaths(source) {
14243
+ var root = SVG(source).node;
14244
+ var elements = Array.from(root.querySelectorAll('*')).filter(function(element) {
14245
+ var tag = element.tagName.toLowerCase();
14246
+ return tag === 'mask' || tag === 'clippath';
14247
+ });
14248
+ return new Set(elements.map(buildElementTreePath));
14249
+ }
14250
+ /** A stylesheet diagnostic is resolved only when every element it can affect was baked. */ function collectBakedStylesheetPaths(source, isBaked) {
14251
+ var resolved = new Set();
14252
+ if (typeof DOMParser === 'undefined' || typeof CSSStyleSheet !== 'function') {
14253
+ return resolved;
14254
+ }
14255
+ var root = new DOMParser().parseFromString(source, 'image/svg+xml').documentElement;
14256
+ var allUsesBaked = Array.from(root.querySelectorAll('use')).every(function(element) {
14257
+ return isBaked(buildElementTreePath(element));
14258
+ });
14259
+ var isHandled = function isHandled(element) {
14260
+ if (isBaked(buildElementTreePath(element))) {
14261
+ return true;
14262
+ }
14263
+ if (element.closest('defs, symbol, marker, pattern, clipPath, mask, filter') != null) {
14264
+ return allUsesBaked;
14265
+ }
14266
+ return false;
14267
+ };
14268
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(root.querySelectorAll('style'))), _step; !(_step = _iterator()).done;){
14269
+ var style = _step.value;
14270
+ var _style_textContent;
14271
+ var sheet = new CSSStyleSheet();
14272
+ sheet.replaceSync((_style_textContent = style.textContent) != null ? _style_textContent : '');
14273
+ var rules = Array.from(sheet.cssRules);
14274
+ var handled = rules.every(function(rule) {
14275
+ if (!isStyleRule(rule)) {
14276
+ return false;
14277
+ }
14278
+ if (Array.from(rule.style).every(function(name) {
14279
+ return name === 'mix-blend-mode';
14280
+ })) {
14281
+ return true;
14282
+ }
14283
+ var matched = [].concat([
14284
+ root
14285
+ ], Array.from(root.querySelectorAll('*'))).filter(function(element) {
14286
+ return element.matches(rule.selectorText);
14287
+ });
14288
+ return matched.every(isHandled);
14289
+ });
14290
+ if (handled) {
14291
+ resolved.add(buildElementTreePath(style));
14292
+ }
14293
+ }
14294
+ return resolved;
14295
+ }
14296
+ function isStyleRule(rule) {
14297
+ return rule.type === 1;
14298
+ }
14299
+
14300
+ /** Rasterize graphics and track the source layers and warnings they replace. */ function buildBakedLayers(source, size, options, rasterScale) {
14301
+ return _async_to_generator(function() {
14302
+ var deferredOptions, bakedPaths, baked, bakingWarnings, blending, plan, _iterator, _step, downgrade, _iterator1, _step1, warning, _iterator2, _step2, scope, image, message, _image_bbox, left, top, right, bottom, width, height, error, reason, replacesSource, handledStyles, declarations;
14303
+ return _ts_generator(this, function(_state) {
14304
+ switch(_state.label){
14305
+ case 0:
14306
+ deferredOptions = _extends({}, options, {
14307
+ strict: false,
14308
+ onWarning: undefined
14309
+ });
14310
+ bakedPaths = [];
14311
+ baked = [];
14312
+ bakingWarnings = [];
14313
+ blending = normalizeLayerBlending(source);
14314
+ plan = planGraphicBaking(blending.source);
14315
+ for(_iterator = _create_for_of_iterator_helper_loose(blending.downgrades); !(_step = _iterator()).done;){
14316
+ downgrade = _step.value;
14317
+ collectLayerWarning(bakingWarnings, deferredOptions, SVG2IR_WARNING_CODES.LAYERS_BLEND_MODE_DOWNGRADED, 'mix-blend-mode "' + downgrade.mode + '" was downgraded to "normal"; the layer is retained.', downgrade.selector);
14318
+ }
14319
+ for(_iterator1 = _create_for_of_iterator_helper_loose(plan.warnings); !(_step1 = _iterator1()).done;){
14320
+ warning = _step1.value;
14321
+ collectLayerWarning(bakingWarnings, deferredOptions, SVG2IR_WARNING_CODES.LAYERS_UNSUPPORTED_FEATURE, warning.message, warning.selector);
14322
+ }
14323
+ _iterator2 = _create_for_of_iterator_helper_loose(plan.scopes);
14324
+ _state.label = 1;
14325
+ case 1:
14326
+ if (!!(_step2 = _iterator2()).done) return [
14327
+ 3,
14328
+ 6
14329
+ ];
14330
+ scope = _step2.value;
14331
+ _state.label = 2;
14332
+ case 2:
14333
+ _state.trys.push([
14334
+ 2,
14335
+ 4,
14336
+ ,
14337
+ 5
14338
+ ]);
14339
+ if (!canRasterizeSVG()) {
14340
+ throw new Error('Graphic baking requires a browser with SVG and Canvas support.');
14341
+ }
14342
+ return [
14343
+ 4,
14344
+ rasterizeSVG(blending.source, scope.path, size, rasterScale, validateGraphicSnapshot)
14345
+ ];
14346
+ case 3:
14347
+ image = _state.sent();
14348
+ bakedPaths.push(scope.path);
14349
+ message = image == null ? 'Graphic rasterization produced no visible pixels; no image layer was emitted.' : scope.isGroup ? 'Graphic group baked into a single PNG; child graphics and paint/effect parameters are no longer editable.' : 'Graphic baked into a PNG; vector geometry and paint/effect parameters are no longer editable.';
14350
+ collectLayerWarning(bakingWarnings, deferredOptions, SVG2IR_WARNING_CODES.LAYERS_GRAPHIC_BAKED, message, scope.selector);
14351
+ if (image == null) {
14352
+ return [
14353
+ 3,
14354
+ 5
14355
+ ];
14356
+ }
14357
+ _image_bbox = image.bbox, left = _image_bbox[0], top = _image_bbox[1], right = _image_bbox[2], bottom = _image_bbox[3];
14358
+ width = right - left;
14359
+ height = bottom - top;
14360
+ baked.push({
14361
+ path: scope.path,
14362
+ layer: {
14363
+ id: '',
14364
+ type: 'image',
14365
+ role: 'content',
14366
+ bbox: image.bbox,
14367
+ size: [
14368
+ width,
14369
+ height
14370
+ ],
14371
+ rotation: [
14372
+ 0,
14373
+ 0,
14374
+ 0
14375
+ ],
14376
+ url: image.url,
14377
+ width: width,
14378
+ height: height
14379
+ }
14380
+ });
14381
+ return [
14382
+ 3,
14383
+ 5
14384
+ ];
14385
+ case 4:
14386
+ error = _state.sent();
14387
+ reason = _instanceof(error, Error) ? error.message : String(error);
14388
+ collectLayerWarning(bakingWarnings, deferredOptions, SVG2IR_WARNING_CODES.LAYERS_UNSUPPORTED_FEATURE, "Graphic baking failed: " + reason, scope.selector);
14389
+ return [
14390
+ 3,
14391
+ 5
14392
+ ];
14393
+ case 5:
14394
+ return [
14395
+ 3,
14396
+ 1
14397
+ ];
14398
+ case 6:
14399
+ replacesSource = function replacesSource(path) {
14400
+ return path != null && bakedPaths.some(function(scope) {
14401
+ return scope === '' || path === scope || path.startsWith("" + scope + "/");
14402
+ });
14403
+ };
14404
+ handledStyles = collectBakedStylesheetPaths(blending.source, replacesSource);
14405
+ declarations = collectNonRenderingDeclarationPaths(source);
14406
+ return [
14407
+ 2,
14408
+ {
14409
+ layers: baked,
14410
+ warnings: bakingWarnings,
14411
+ replacesSource: replacesSource,
14412
+ resolvesWarning: function resolvesWarning(warning, path) {
14413
+ return replacesSource(path) || warning.code === SVG2IR_WARNING_CODES.ELEMENT_DROPPED && path != null && (handledStyles.has(path) || declarations.has(path));
14414
+ }
14415
+ }
14416
+ ];
14417
+ }
14418
+ });
14419
+ })();
14420
+ }
13273
14421
 
13274
14422
  function encodeBase64(data) {
13275
14423
  var chunks = [];
@@ -13458,30 +14606,115 @@ function fetchImageResource(url) {
13458
14606
  }).apply(this, arguments);
13459
14607
  }
13460
14608
 
13461
- function convertSVGToLayers(source, options, loadImage, preservedData) {
13462
- return _async_to_generator(function() {
13463
- var splitResult, parsed, _assembleSVGStaticLayers, size, data, _tmp;
14609
+ var animatedTags = new Set([
14610
+ 'animate',
14611
+ 'animatetransform',
14612
+ 'animatemotion',
14613
+ 'set'
14614
+ ]);
14615
+ /** Static layers cannot sample animation; drop SMIL nodes so elements keep their authored state. */ function stripLayerAnimation(source) {
14616
+ var svg = SVG(source);
14617
+ if ((svg == null ? void 0 : svg.node) == null) {
14618
+ return {
14619
+ source: source,
14620
+ removed: 0
14621
+ };
14622
+ }
14623
+ var elements = Array.from(svg.node.querySelectorAll('*')).filter(function(element) {
14624
+ return animatedTags.has(element.tagName.toLowerCase());
14625
+ });
14626
+ if (elements.length === 0) {
14627
+ return {
14628
+ source: source,
14629
+ removed: 0
14630
+ };
14631
+ }
14632
+ for(var _iterator = _create_for_of_iterator_helper_loose(elements), _step; !(_step = _iterator()).done;){
14633
+ var element = _step.value;
14634
+ element.remove();
14635
+ }
14636
+ return {
14637
+ source: svg.svg(),
14638
+ removed: elements.length
14639
+ };
14640
+ }
14641
+
14642
+ function convertSVGToLayers() {
14643
+ return _async_to_generator(function(source, options, preservedData) {
14644
+ var loadImage, _options_rasterScale, rasterScale, conversionOptions, layerSources, warningSources, collected, stripped, staticSource, parsed, context, composition, baking, assembled, _tmp, _tmp1;
13464
14645
  return _ts_generator(this, function(_state) {
13465
14646
  switch(_state.label){
13466
14647
  case 0:
13467
- splitResult = preservedData == null ? splitSVG(source, options) : undefined;
13468
- parsed = splitResult != null ? splitResult : parseSVGToIRWithPreservedData(source, options);
13469
- _assembleSVGStaticLayers = assembleSVGStaticLayers(parsed.ir, options, parsed.warnings, preservedData != null ? preservedData : splitResult == null ? void 0 : splitResult.preservedData), size = _assembleSVGStaticLayers.size, data = _assembleSVGStaticLayers.data;
13470
- _tmp = {
13471
- size: size
14648
+ if (options === void 0) options = {};
14649
+ loadImage = options.loadImage, _options_rasterScale = options.rasterScale, rasterScale = _options_rasterScale === void 0 ? 2 : _options_rasterScale, conversionOptions = _object_without_properties_loose(options, [
14650
+ "loadImage",
14651
+ "rasterScale"
14652
+ ]);
14653
+ layerSources = new Map();
14654
+ warningSources = new Map();
14655
+ collected = {
14656
+ textDataByLayerId: new Map(),
14657
+ paintAnimationsByLayerId: new Map(),
14658
+ shapeAnimationsByLayerId: new Map()
14659
+ };
14660
+ stripped = stripLayerAnimation(source);
14661
+ staticSource = stripped.source;
14662
+ // Preserve original layer IDs while gathering the source identities required by baking and assembly.
14663
+ parsed = parseSVGToIRWithPreservedData(staticSource, _extends({}, conversionOptions, {
14664
+ strict: false,
14665
+ onWarning: undefined
14666
+ }), _extends({}, collected, {
14667
+ layerSourceCollector: layerSources,
14668
+ warningSourceCollector: warningSources
14669
+ }));
14670
+ context = {
14671
+ source: staticSource,
14672
+ ir: parsed.ir,
14673
+ warnings: parsed.warnings,
14674
+ preservedData: preservedData != null ? preservedData : collected,
14675
+ layerSources: layerSources,
14676
+ warningSources: warningSources
13472
14677
  };
14678
+ if (stripped.removed > 0) {
14679
+ collectLayerWarning(context.warnings, _extends({}, conversionOptions, {
14680
+ strict: false,
14681
+ onWarning: undefined
14682
+ }), SVG2IR_WARNING_CODES.LAYERS_ANIMATION_STRIPPED, "" + stripped.removed + " animated element(s) were removed; static layers output does not sample animation.");
14683
+ }
14684
+ composition = context.ir.compositions[0];
13473
14685
  return [
13474
14686
  4,
13475
- inlineImageResources(data, loadImage)
14687
+ buildBakedLayers(context.source, [
14688
+ composition.width,
14689
+ composition.height
14690
+ ], conversionOptions, rasterScale)
13476
14691
  ];
13477
14692
  case 1:
14693
+ baking = _state.sent();
14694
+ assembled = assembleSVGLayers({
14695
+ context: context,
14696
+ options: conversionOptions,
14697
+ baking: baking
14698
+ });
14699
+ _tmp = [
14700
+ {},
14701
+ assembled
14702
+ ];
14703
+ _tmp1 = {};
14704
+ return [
14705
+ 4,
14706
+ inlineImageResources(assembled.data, loadImage)
14707
+ ];
14708
+ case 2:
13478
14709
  return [
13479
14710
  2,
13480
- (_tmp.data = _state.sent(), _tmp.warnings = parsed.warnings, _tmp)
14711
+ _extends.apply(void 0, _tmp.concat([
14712
+ (_tmp1.data = _state.sent(), _tmp1)
14713
+ ]))
13481
14714
  ];
13482
14715
  }
13483
14716
  });
13484
- })();
14717
+ }).apply(this, arguments);
13485
14718
  }
13486
14719
 
13487
14720
  /**
@@ -13506,7 +14739,8 @@ function convertSVGToLayers(source, options, loadImage, preservedData) {
13506
14739
  JSONSceneVersion["3_4"] = "3.4";
13507
14740
  JSONSceneVersion["3_5"] = "3.5";
13508
14741
  JSONSceneVersion["3_6"] = "3.6";
13509
- JSONSceneVersion["LATEST"] = "3.6";
14742
+ JSONSceneVersion["3_7"] = "3.7";
14743
+ JSONSceneVersion["LATEST"] = "3.7";
13510
14744
  })(JSONSceneVersion || (JSONSceneVersion = {}));
13511
14745
 
13512
14746
  /*********************************************/ /* 元素属性参数类型 */ /*********************************************/ /**
@@ -13821,10 +15055,12 @@ var CameraClipMode;
13821
15055
  * 直线
13822
15056
  */ ValueType[ValueType["LINE"] = 5] = "LINE";
13823
15057
  /**
13824
- * 曲线
15058
+ * 曲线(Hermite 曲线)
15059
+ * @deprecated 使用 BEZIER_CURVE 替代,此类型仅用于旧数据迁移兼容
13825
15060
  */ ValueType[ValueType["CURVE"] = 6] = "CURVE";
13826
15061
  /**
13827
15062
  * 贝塞尔路径
15063
+ * @deprecated 使用 BEZIER_CURVE_PATH 替代,此类型仅用于旧数据迁移兼容
13828
15064
  */ ValueType[ValueType["BEZIER_PATH"] = 7] = "BEZIER_PATH";
13829
15065
  /**
13830
15066
  * 颜色
@@ -14261,6 +15497,7 @@ var DataType;
14261
15497
  DataType["AnimationGraphAsset"] = "AnimationGraphAsset";
14262
15498
  DataType["CompositionComponent"] = "CompositionComponent";
14263
15499
  DataType["FFDComponent"] = "FFDComponent";
15500
+ DataType["FrameComponent"] = "FrameComponent";
14264
15501
  DataType["Animator"] = "Animator";
14265
15502
  // Non-EffectObject
14266
15503
  DataType["TimelineClip"] = "TimelineClip";
@@ -15885,7 +17122,8 @@ function asRecordArray(value) {
15885
17122
  }
15886
17123
 
15887
17124
  /** 从已解析的 IR 和 SVG 保留数据生成 GE 场景。 */ function assembleSVGGE(parsed, options, preservedData) {
15888
- var ir = parsed.ir, warnings = parsed.warnings;
17125
+ var ir = parsed.ir;
17126
+ var warnings = [].concat(parsed.warnings);
15889
17127
  var fonts = (options != null ? options : {}).fonts;
15890
17128
  var irForGE = expandIRHoldTransitions(ir);
15891
17129
  if ((preservedData == null ? void 0 : preservedData.shapeAnimationsByLayerId) != null) {
@@ -15993,33 +17231,15 @@ function cleanFontName(raw) {
15993
17231
  return value;
15994
17232
  }
15995
17233
 
15996
- /** SVG→GE 显式入口。传入 preservedData 时应用 SVG 专属后处理。 */ function convertSVGToGE(source, options, preservedData) {
17234
+ function convertSVGToGE(sourceOrContext, options, preservedData) {
15997
17235
  var _ref = options != null ? options : {}; _ref.fonts; var parserOptions = _object_without_properties_loose(_ref, [
15998
17236
  "fonts"
15999
17237
  ]);
16000
- var parsed = parseSVGToIRWithPreservedData(source, parserOptions);
16001
- return assembleSVGGE(parsed, options, preservedData);
16002
- }
16003
-
16004
- function convertSVG(source, options, preservedData) {
16005
- var _ref = options != null ? options : {}, _ref_outputFormat = _ref.outputFormat, outputFormat = _ref_outputFormat === void 0 ? 'ge' : _ref_outputFormat;
16006
- if (outputFormat !== 'ge' && outputFormat !== 'layers') {
16007
- throw new TypeError('[svg2ir] outputFormat must be ge or layers.');
16008
- }
16009
- if ((options == null ? void 0 : options.outputFormat) === 'layers') {
16010
- options.outputFormat; var loadImage = options.loadImage, parserOptions = _object_without_properties_loose(options, [
16011
- "outputFormat",
16012
- "loadImage"
16013
- ]);
16014
- return convertSVGToLayers(source, parserOptions, loadImage, preservedData);
16015
- }
16016
- var _ref1 = options != null ? options : {}; _ref1.outputFormat; var geOptions = _object_without_properties_loose(_ref1, [
16017
- "outputFormat"
16018
- ]);
16019
- return convertSVGToGE(source, geOptions, preservedData);
17238
+ var context = typeof sourceOrContext === 'string' ? parseSVGToIRWithPreservedData(sourceOrContext, parserOptions) : sourceOrContext;
17239
+ return assembleSVGGE(context, options, preservedData != null ? preservedData : typeof sourceOrContext === 'string' ? undefined : sourceOrContext.preservedData);
16020
17240
  }
16021
17241
 
16022
17242
  setEditableSVGConstructor(resolveEditableSVGConstructor(editableSVGNodeModule));
16023
17243
 
16024
- export { convertSVG, convertSVGToGE, convertSVGToIR, splitSVG };
17244
+ export { convertSVGToGE, convertSVGToIR, convertSVGToLayers, inferNumericWeightFromFamily, splitSVG };
16025
17245
  //# sourceMappingURL=node.mjs.map