@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/index.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 { IRPaintType, IRLineJoin, IRLineCap, IRShapePrimitiveType, IRLayerType, ANIMATION_IR_SCHEMA_VERSION, validateIRScene, IRBlendMode } from '@vvfx/animation-ir';
@@ -1505,7 +1505,7 @@ function parseHexColor(raw) {
1505
1505
  return null;
1506
1506
  }
1507
1507
  var hex = match[1];
1508
- var expanded = hex.length <= 4 ? [].concat(hex).map(function(char) {
1508
+ var expanded = hex.length <= 4 ? Array.from(hex).map(function(char) {
1509
1509
  return "" + char + char;
1510
1510
  }).join('') : hex;
1511
1511
  var r = parseInt(expanded.slice(0, 2), 16) / 255;
@@ -2606,7 +2606,24 @@ function parseSMILTag(tag, root, beginCache, comparisonDuration, valueParser, un
2606
2606
  return maxEnd;
2607
2607
  }
2608
2608
 
2609
- /** SVG 转换诊断码。不支持的特性按降级和 warning 处理。 */ var SVG2IR_WARNING_CODES = {
2609
+ /** Structural source identity, independent of optional or duplicate SVG IDs. */ function buildElementTreePath(element) {
2610
+ var indices = [];
2611
+ var current = element;
2612
+ while(isElementNode(current.parentNode)){
2613
+ var parent = current.parentNode;
2614
+ indices.unshift(Array.from(parent.children).indexOf(current));
2615
+ current = parent;
2616
+ }
2617
+ return indices.join('/');
2618
+ }
2619
+ function isElementNode(node) {
2620
+ return (node == null ? void 0 : node.nodeType) === 1;
2621
+ }
2622
+
2623
+ /** SVG 转换诊断码;用于报告烘焙、降级和不支持的特性。 */ var SVG2IR_WARNING_CODES = {
2624
+ /** 图形或图形组已栅格化,矢量编辑能力变化通过 warning 报告。 */ LAYERS_GRAPHIC_BAKED: 'svg2ge_layers_graphic_baked',
2625
+ LAYERS_BLEND_MODE_DOWNGRADED: 'svg2ge_layers_blend_mode_downgraded',
2626
+ LAYERS_ANIMATION_STRIPPED: 'svg2ge_layers_animation_stripped',
2610
2627
  LAYERS_UNSUPPORTED_TYPE: 'svg2ge_layers_unsupported_type',
2611
2628
  LAYERS_UNSUPPORTED_FEATURE: 'svg2ge_layers_unsupported_feature',
2612
2629
  LAYERS_INVALID_DATA: 'svg2ge_layers_invalid_data',
@@ -3961,7 +3978,7 @@ function distPointToSegment(p, a, b) {
3961
3978
  return transformVector(gChain, t);
3962
3979
  });
3963
3980
  return {
3964
- mode: "add",
3981
+ mode: 'add',
3965
3982
  path: {
3966
3983
  points: pts,
3967
3984
  inTangents: inTangents,
@@ -5918,12 +5935,16 @@ function applyClipMask(es, el, layer, clipMasks) {
5918
5935
  }
5919
5936
  if (isClip) {
5920
5937
  return _extends({}, layer, {
5921
- mask: baseMask
5938
+ masks: [
5939
+ baseMask
5940
+ ]
5922
5941
  });
5923
5942
  }
5924
5943
  var rebased = rebaseMaskToLocal(baseMask, layer);
5925
5944
  return rebased ? _extends({}, layer, {
5926
- mask: rebased
5945
+ masks: [
5946
+ rebased
5947
+ ]
5927
5948
  }) : layer;
5928
5949
  }
5929
5950
  /** 将 SVG 绝对 mask 点转换为 image 的 asset-local 坐标。 */ function rebaseMaskToLocal(mask, layer) {
@@ -5961,7 +5982,7 @@ function applyClipMask(es, el, layer, clipMasks) {
5961
5982
  outTangents: mask.path.outTangents,
5962
5983
  closed: mask.path.closed
5963
5984
  },
5964
- mode: "add"
5985
+ mode: 'add'
5965
5986
  };
5966
5987
  }
5967
5988
  // shape 没有 asset 尺寸,mask 需要转换到以 layer anchor 为基准的 element-local 空间。
@@ -5991,7 +6012,7 @@ function applyClipMask(es, el, layer, clipMasks) {
5991
6012
  outTangents: mask.path.outTangents,
5992
6013
  closed: mask.path.closed
5993
6014
  },
5994
- mode: "add"
6015
+ mode: 'add'
5995
6016
  };
5996
6017
  }
5997
6018
  /** shape layer 的 element-local bbox(以 layer.transform.anchor=localCenter 为原点)。
@@ -6126,8 +6147,9 @@ function readVec3(channel) {
6126
6147
  node
6127
6148
  ], Array.from(node.querySelectorAll('*')));
6128
6149
  var hasUnsupportedRule = ruleNodes.some(function(candidate) {
6150
+ var _ref, _ref1;
6129
6151
  var _candidate_getAttribute, _candidate_getAttribute1;
6130
- 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()) !== '';
6152
+ 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 : '') !== '';
6131
6153
  });
6132
6154
  if (hasUnsupportedRule) {
6133
6155
  warn(SVG2IR_WARNING_CODES.CLIP_RULE_DROPPED, "" + tag + " 内显式 clip-rule/fill-rule 未映射,IR 只保留 mask 几何,不保留该规则。");
@@ -6959,7 +6981,7 @@ function createSVGConversionSession(es, options) {
6959
6981
  };
6960
6982
  var withGroupParent = function withGroupParent(layer, element) {
6961
6983
  var parentIndex = nearestMaskedGroupAncestor(element);
6962
- if (parentIndex == null || layer.mask != null) {
6984
+ if (parentIndex == null) {
6963
6985
  return layer;
6964
6986
  }
6965
6987
  return _extends({}, layer, {
@@ -6968,8 +6990,10 @@ function createSVGConversionSession(es, options) {
6968
6990
  };
6969
6991
  var appendLayer = function appendLayer(layer, element, applyElementClip) {
6970
6992
  if (applyElementClip === void 0) applyElementClip = true;
6993
+ var _options_layerSourceCollector;
6971
6994
  var clippedLayer = applyElementClip ? applyClipMask(es, element, layer, clipMasks) : layer;
6972
6995
  layers.push(withGroupParent(clippedLayer, element));
6996
+ (_options_layerSourceCollector = options.layerSourceCollector) == null ? void 0 : _options_layerSourceCollector.set(layer.id, buildElementTreePath(element.node));
6973
6997
  };
6974
6998
  var appendAsset = function appendAsset(asset) {
6975
6999
  if (registeredAssetIds.has(asset.id)) {
@@ -7312,7 +7336,9 @@ function convertGroupElement(element, context) {
7312
7336
  value: 1
7313
7337
  }
7314
7338
  },
7315
- mask: groupMask
7339
+ masks: [
7340
+ groupMask
7341
+ ]
7316
7342
  };
7317
7343
  context.appendLayer(nullLayer, element, false);
7318
7344
  context.groupMaskGNodeToIndex.set(element.node, layerIndex);
@@ -10377,7 +10403,7 @@ function mapFontWeight(raw, fontFamily) {
10377
10403
  seen.set(Math.round(w * 100), ch);
10378
10404
  }
10379
10405
  }
10380
- return [].concat(seen.entries()).map(function(param) {
10406
+ return Array.from(seen.entries()).map(function(param) {
10381
10407
  var k = param[0], ch = param[1];
10382
10408
  return {
10383
10409
  ch: ch,
@@ -10427,6 +10453,9 @@ function mapFontWeight(raw, fontFamily) {
10427
10453
  // latin / digit / 标点:典型比例字体 sans-serif 大写字母约 0.65em,数字稍窄。
10428
10454
  return /[0-9]/.test(ch) ? 0.55 : 0.62;
10429
10455
  }
10456
+ /** 去除单个字体族名的 CSS 字符串引号。 */ function normalizeFontFamilyName(fontFamily) {
10457
+ return fontFamily.trim().replace(/^(['"])(.*)\1$/, '$2');
10458
+ }
10430
10459
  /** 构造与 Effects Runtime getFontDesc 一致的 CSS font 简写字符串,用于 Canvas measureText。 */ function buildCanvasFontDesc(fontSize, fontFamily, fontWeight, fontStyle) {
10431
10460
  var weightStr = String(fontWeight);
10432
10461
  var genericFamilies = [
@@ -10435,7 +10464,8 @@ function mapFontWeight(raw, fontFamily) {
10435
10464
  'monospace',
10436
10465
  'courier'
10437
10466
  ];
10438
- var familyName = genericFamilies.includes(fontFamily) ? fontFamily : '"' + fontFamily + '"';
10467
+ var family = normalizeFontFamilyName(fontFamily);
10468
+ var familyName = genericFamilies.includes(family) ? family : '"' + family + '"';
10439
10469
  var desc = fontSize + "px " + familyName;
10440
10470
  if (weightStr !== 'normal' && weightStr !== '') {
10441
10471
  desc = weightStr + " " + desc;
@@ -10446,13 +10476,13 @@ function mapFontWeight(raw, fontFamily) {
10446
10476
  return desc;
10447
10477
  }
10448
10478
  /** 文本宽度估算。优先使用调用方提供的 Canvas measureText,否则使用字符级启发式系数。 */ function estimateTextWidth(content, fontSize, letterSpacing, measureText, fontFamily, fontWeight, fontStyle) {
10449
- var len = [].concat(content).length;
10479
+ var chars = Array.from(content);
10480
+ var len = chars.length;
10450
10481
  if (measureText != null && fontFamily !== '') {
10451
10482
  var fontDesc = buildCanvasFontDesc(fontSize, fontFamily, fontWeight, fontStyle);
10452
10483
  var width = measureText(fontDesc, content).width;
10453
10484
  return width + letterSpacing * Math.max(len - 1, 0);
10454
10485
  }
10455
- var chars = [].concat(content);
10456
10486
  var width1 = chars.reduce(function(s, ch) {
10457
10487
  return s + charWidthCoef(ch) * fontSize;
10458
10488
  }, 0);
@@ -12049,7 +12079,16 @@ function createSVGElementConverterRegistry(session) {
12049
12079
  }
12050
12080
 
12051
12081
  function buildSVGLayers(es, options) {
12052
- var session = createSVGConversionSession(es, options);
12082
+ var currentPath;
12083
+ var warningSourceCollector = options.warningSourceCollector;
12084
+ var session = createSVGConversionSession(es, warningSourceCollector == null ? options : _extends({}, options, {
12085
+ emit: function emit(warning) {
12086
+ if (currentPath != null) {
12087
+ warningSourceCollector.set(warning, currentPath);
12088
+ }
12089
+ options.emit(warning);
12090
+ }
12091
+ }));
12053
12092
  var converters = createSVGElementConverterRegistry(session);
12054
12093
  for(var _iterator = _create_for_of_iterator_helper_loose(session.all), _step; !(_step = _iterator()).done;){
12055
12094
  var element = _step.value;
@@ -12057,6 +12096,9 @@ function buildSVGLayers(es, options) {
12057
12096
  var _element_node_tagName, _element_node;
12058
12097
  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 : '';
12059
12098
  var selector = describeElement(element);
12099
+ if (warningSourceCollector != null) {
12100
+ currentPath = buildElementTreePath(element.node);
12101
+ }
12060
12102
  if (isInInactiveSwitchBranch(element)) {
12061
12103
  continue;
12062
12104
  }
@@ -12090,11 +12132,10 @@ function buildSVGLayers(es, options) {
12090
12132
 
12091
12133
  var ParseableSVG = /*#__PURE__*/ function() {
12092
12134
  function ParseableSVG(svgStr, _options) {
12093
- var _ref, _SVG;
12094
- var _svgStr_match;
12095
- // 从字符串里抠出首个 <svg>...</svg> 再交给 svg.js(兼容前导注释/doctype)。
12135
+ var _SVG;
12136
+ // svg.js parses a fragment; remove only the prolog and let the DOM handle nested markup.
12137
+ var content = svgStr.replace(/^\uFEFF/, '').replace(/^(?:\s|<\?xml\b[\s\S]*?\?>|<!DOCTYPE\b[^>]*>|<!--[\s\S]*?-->)+/i, '');
12096
12138
  // svg.js SVG(string) 的 d.ts 标为 Element,但对完整 <svg> 文档运行时返回根 SVG 文档实例。
12097
- 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;
12098
12139
  // svg.js 对非 SVG 字符串(如 'not svg')解析返 null。兜底空 svg:让 svg2ir 上层
12099
12140
  // hasSVGRootElement 检查(非 svg 抛 INVALID_SVG)生效,而非在构造期抛错。
12100
12141
  this.svg = (_SVG = SVG(content)) != null ? _SVG : SVG('<svg xmlns="http://www.w3.org/2000/svg"/>');
@@ -12297,6 +12338,8 @@ function parseSVGToIRScene(svgString, options) {
12297
12338
  value: scannedSmilDuration
12298
12339
  };
12299
12340
  var layerBuildOptions = {
12341
+ layerSourceCollector: options == null ? void 0 : options.layerSourceCollector,
12342
+ warningSourceCollector: options == null ? void 0 : options.warningSourceCollector,
12300
12343
  frameRate: frameRate,
12301
12344
  durationSeconds: effectiveDuration,
12302
12345
  emit: emit,
@@ -12476,6 +12519,8 @@ function parseSVGToIRWithPreservedData(source, options, collectors) {
12476
12519
  var svgString = readSVGString(source);
12477
12520
  var irScene = parseSVGToIRScene(svgString, _extends({}, options, {
12478
12521
  onWarning: emitWarning,
12522
+ layerSourceCollector: collectors == null ? void 0 : collectors.layerSourceCollector,
12523
+ warningSourceCollector: collectors == null ? void 0 : collectors.warningSourceCollector,
12479
12524
  textDataCollector: collectors == null ? void 0 : collectors.textDataByLayerId,
12480
12525
  paintAnimationsCollector: collectors == null ? void 0 : collectors.paintAnimationsByLayerId,
12481
12526
  shapeAnimationCollector: collectors == null ? void 0 : collectors.shapeAnimationsByLayerId
@@ -12651,7 +12696,8 @@ function collectLayerWarning(warnings, options, code, message, selector) {
12651
12696
  });
12652
12697
  warnings.push(warning);
12653
12698
  options.onWarning == null ? void 0 : options.onWarning.call(options, warning);
12654
- if (options.strict === true && code !== SVG2IR_WARNING_CODES.LAYERS_TEXT_BOUNDS_ESTIMATED) {
12699
+ var advisory = code === SVG2IR_WARNING_CODES.LAYERS_TEXT_BOUNDS_ESTIMATED || code === SVG2IR_WARNING_CODES.LAYERS_GRAPHIC_BAKED;
12700
+ if (options.strict === true && !advisory) {
12655
12701
  throw new SVGConverterError(SVG_CONVERTER_ERROR_CODES.LAYERS_CONVERSION_FAILED, warning.message, {
12656
12702
  stage: 'layers',
12657
12703
  sourceId: selector,
@@ -12695,21 +12741,36 @@ function transformBoxCorners(matrix, box) {
12695
12741
  transformPoint(matrix, box[0], box[3])
12696
12742
  ];
12697
12743
  }
12698
- function mapPointsToBBox(points) {
12744
+ function mapPointsToBBox(points, roundCoordinates) {
12745
+ if (roundCoordinates === void 0) roundCoordinates = true;
12699
12746
  var _Math, _Math1, _Math2, _Math3;
12700
- return [
12701
- roundPixel((_Math = Math).min.apply(_Math, [].concat(points.map(function(point) {
12747
+ var bbox = [
12748
+ (_Math = Math).min.apply(_Math, [].concat(points.map(function(point) {
12702
12749
  return point[0];
12703
- })))),
12704
- roundPixel((_Math1 = Math).min.apply(_Math1, [].concat(points.map(function(point) {
12750
+ }))),
12751
+ (_Math1 = Math).min.apply(_Math1, [].concat(points.map(function(point) {
12705
12752
  return point[1];
12706
- })))),
12707
- roundPixel((_Math2 = Math).max.apply(_Math2, [].concat(points.map(function(point) {
12753
+ }))),
12754
+ (_Math2 = Math).max.apply(_Math2, [].concat(points.map(function(point) {
12708
12755
  return point[0];
12709
- })))),
12710
- roundPixel((_Math3 = Math).max.apply(_Math3, [].concat(points.map(function(point) {
12756
+ }))),
12757
+ (_Math3 = Math).max.apply(_Math3, [].concat(points.map(function(point) {
12711
12758
  return point[1];
12712
- }))))
12759
+ })))
12760
+ ];
12761
+ if (bbox.some(function(value) {
12762
+ return !Number.isFinite(value);
12763
+ })) {
12764
+ throwInvalidLayerData('Non-finite pixel geometry.');
12765
+ }
12766
+ if (!roundCoordinates) {
12767
+ return bbox;
12768
+ }
12769
+ return [
12770
+ roundPixel(bbox[0]),
12771
+ roundPixel(bbox[1]),
12772
+ roundPixel(bbox[2]),
12773
+ roundPixel(bbox[3])
12713
12774
  ];
12714
12775
  }
12715
12776
  function roundPixel(value) {
@@ -12917,7 +12978,7 @@ function parseTextRuns(layer, font, preserved) {
12917
12978
  return spans.filter(function(span) {
12918
12979
  return span.text !== '' || span.newLine;
12919
12980
  }).map(function(span) {
12920
- var fontSize = span.fontSize == null || span.fontSize === '' ? base.fontSize : Number.parseInt(span.fontSize, 10);
12981
+ var fontSize = span.fontSize == null || span.fontSize === '' ? base.fontSize : Number.parseFloat(span.fontSize);
12921
12982
  if (!Number.isFinite(fontSize) || fontSize <= 0) {
12922
12983
  throwInvalidLayerData('Invalid text fragment font size.');
12923
12984
  }
@@ -12946,7 +13007,7 @@ function mapTextColor(color) {
12946
13007
  };
12947
13008
  }
12948
13009
 
12949
- function buildTextRunLayout(runs, family, spacing, content, size, conversionOptions, warnings, id, segmented) {
13010
+ function buildTextRunLayout(runs, family, spacing, content, size, conversionOptions, warnings, id, segmented, renderScale) {
12950
13011
  var _loop = function() {
12951
13012
  var run = _step.value;
12952
13013
  run.text.split('\n').forEach(function(text, index) {
@@ -12961,6 +13022,10 @@ function buildTextRunLayout(runs, family, spacing, content, size, conversionOpti
12961
13022
  });
12962
13023
  };
12963
13024
  if (segmented === void 0) segmented = false;
13025
+ if (renderScale === void 0) renderScale = [
13026
+ 1,
13027
+ 1
13028
+ ];
12964
13029
  var _Math;
12965
13030
  var rows = [
12966
13031
  []
@@ -12973,33 +13038,44 @@ function buildTextRunLayout(runs, family, spacing, content, size, conversionOpti
12973
13038
  }).map(function(row) {
12974
13039
  var _Math, _Math1;
12975
13040
  var parts = row.map(function(run) {
12976
- // 分段文字使用统一参考字号度量字宽和字体边界,再按片段字号缩放。
13041
+ // 基线沿用参考字号指标,字宽按实际输出字号单独测量。
12977
13042
  var measurementSize = segmented ? 10 : run.fontSize;
12978
13043
  var scale = run.fontSize / measurementSize;
12979
- var font = (run.italic ? 'italic' : 'normal') + " " + (run.bold ? 'bold' : 'normal') + " " + measurementSize + "px" + (' "' + family + '"');
13044
+ var weight = run.bold ? 'bold' : 'normal';
13045
+ var style = run.italic ? 'italic' : 'normal';
13046
+ var font = buildCanvasFontDesc(measurementSize, family, weight, style);
12980
13047
  var metrics = conversionOptions.measureText == null ? void 0 : conversionOptions.measureText.call(conversionOptions, font, segmented ? 'x' : run.text);
12981
- var chunks = segmented ? run.text.split('') : [
12982
- run.text
12983
- ];
12984
- var advance = 0;
12985
- for(var _iterator = _create_for_of_iterator_helper_loose(chunks), _step; !(_step = _iterator()).done;){
12986
- var chunk = _step.value;
12987
- var width = segmented ? conversionOptions.measureText == null ? void 0 : conversionOptions.measureText.call(conversionOptions, font, chunk).width : metrics == null ? void 0 : metrics.width;
12988
- var valid = width != null && Number.isFinite(width) && width >= 0;
12989
- estimated || (estimated = !valid);
12990
- advance += valid ? width : Array.from(chunk).length * measurementSize * 0.6;
12991
- }
12992
- var characterCount = segmented ? run.text.length : Array.from(run.text).length;
12993
- var width1 = advance * scale + Math.max(0, characterCount - 1) * spacing;
12994
- var ascent = (metrics == null ? void 0 : metrics.fontBoundingBoxAscent) == null ? run.fontSize * 0.8 : metrics.fontBoundingBoxAscent * scale;
12995
- var descent = (metrics == null ? void 0 : metrics.fontBoundingBoxDescent) == null ? run.fontSize * 0.2 : metrics.fontBoundingBoxDescent * scale;
13048
+ var characters = Array.from(run.text);
13049
+ // 片段协议不输出额外字重和斜体,测宽使用同样的普通样式。
13050
+ var widthFontSize = run.fontSize * renderScale[1];
13051
+ var widthFont = buildCanvasFontDesc(widthFontSize, family, 'normal', 'normal');
13052
+ var measureWidth = function measureWidth(text) {
13053
+ var width = conversionOptions.measureText == null ? void 0 : conversionOptions.measureText.call(conversionOptions, widthFont, text).width;
13054
+ if (width != null && Number.isFinite(width) && width >= 0) {
13055
+ return width;
13056
+ }
13057
+ estimated = true;
13058
+ return estimateTextWidth(text, widthFontSize, 0, undefined, family, 'normal', 'normal');
13059
+ };
13060
+ // 字距和字宽交替累加,保持与 Artis 逐字测宽的计算顺序一致。
13061
+ var renderedWidth = 0;
13062
+ characters.forEach(function(character, index) {
13063
+ if (index > 0) {
13064
+ renderedWidth += spacing * renderScale[0];
13065
+ }
13066
+ renderedWidth += measureWidth(character);
13067
+ });
13068
+ var width = renderedWidth / renderScale[0];
13069
+ var fallback = resolveFontMetrics(undefined, family, weight, style, run.fontSize);
13070
+ var ascent = (metrics == null ? void 0 : metrics.fontBoundingBoxAscent) == null ? fallback.asc : metrics.fontBoundingBoxAscent * scale;
13071
+ var descent = (metrics == null ? void 0 : metrics.fontBoundingBoxDescent) == null ? fallback.desc : metrics.fontBoundingBoxDescent * scale;
12996
13072
  estimated || (estimated = (metrics == null ? void 0 : metrics.fontBoundingBoxAscent) == null || metrics.fontBoundingBoxDescent == null);
12997
- if (!Number.isFinite(width1) || width1 < 0 || !Number.isFinite(ascent) || !Number.isFinite(descent)) {
13073
+ if (!Number.isFinite(width) || width < 0 || !Number.isFinite(ascent) || !Number.isFinite(descent)) {
12998
13074
  throwInvalidLayerData('Text measurement returned invalid metrics.');
12999
13075
  }
13000
13076
  return {
13001
13077
  run: run,
13002
- width: width1,
13078
+ width: width,
13003
13079
  ascent: ascent,
13004
13080
  descent: descent
13005
13081
  };
@@ -13112,7 +13188,10 @@ function convertIRTextLayer(layer, state, session, id) {
13112
13188
  var positioned = buildTextRunLayout(runs, font.family, layer.content.letterSpacing, layer.content, [
13113
13189
  bounds.width,
13114
13190
  height
13115
- ], options, warnings, id, preserved != null);
13191
+ ], options, warnings, id, preserved != null, [
13192
+ scaleX,
13193
+ scaleY
13194
+ ]);
13116
13195
  if (positioned.length === 0) {
13117
13196
  return undefined;
13118
13197
  }
@@ -13126,25 +13205,25 @@ function convertIRTextLayer(layer, state, session, id) {
13126
13205
  part.box[3] + centerY
13127
13206
  ]);
13128
13207
  });
13129
- var bbox = mapPointsToBBox(polygons.flat());
13130
- var rotation = roundPixel(Math.atan2(matrix.b, matrix.a) * 180 / Math.PI);
13208
+ var bbox = mapPointsToBBox(polygons.flat(), false);
13209
+ var rotation = Math.atan2(matrix.b, matrix.a) * 180 / Math.PI;
13131
13210
  var fragments = positioned.map(function(part, index) {
13132
13211
  var polygon = polygons[index].map(function(point) {
13133
13212
  return [
13134
- roundPixel(point[0] - bbox[0]),
13135
- roundPixel(point[1] - bbox[1])
13213
+ point[0] - bbox[0],
13214
+ point[1] - bbox[1]
13136
13215
  ];
13137
13216
  });
13138
13217
  return {
13139
13218
  content: part.run.text,
13140
- bbox: mapPointsToBBox(polygon),
13219
+ bbox: mapPointsToBBox(polygon, false),
13141
13220
  polygon: polygon,
13142
- font_family: font.family,
13143
- font_size: roundPixel(part.run.fontSize * scaleY),
13221
+ font_family: normalizeFontFamilyName(font.family),
13222
+ font_size: part.run.fontSize * scaleY,
13144
13223
  color: part.run.color,
13145
- letter_spacing: roundPixel(layer.content.letterSpacing * scaleX),
13224
+ letter_spacing: layer.content.letterSpacing * scaleX,
13146
13225
  direction: 'horizontal',
13147
- rotation: rotation
13226
+ rotation: rotation === 0 ? 0 : rotation
13148
13227
  };
13149
13228
  });
13150
13229
  return {
@@ -13183,7 +13262,43 @@ function createLayerConverterRegistry(session) {
13183
13262
  ]);
13184
13263
  }
13185
13264
 
13265
+ /** 完全覆盖图片的直边矩形 mask 不改变可见内容。 */ function maskCoversImage(mask, bounds) {
13266
+ var _Math, _Math1, _Math2, _Math3;
13267
+ var path = mask.path;
13268
+ var epsilon = 1e-6;
13269
+ if (mask.mode === 'subtract' || mask.inverted === true || !path.closed || path.points.length !== 4) {
13270
+ return false;
13271
+ }
13272
+ if (path.inTangents.length !== 4 || path.outTangents.length !== 4 || [].concat(path.inTangents, path.outTangents).some(function(tangent) {
13273
+ return tangent.x !== 0 || tangent.y !== 0;
13274
+ })) {
13275
+ return false;
13276
+ }
13277
+ var straightEdges = path.points.every(function(point, index) {
13278
+ var next = path.points[(index + 1) % 4];
13279
+ var opposite = path.points[(index + 2) % 4];
13280
+ var dx = Math.abs(next.x - point.x);
13281
+ var dy = Math.abs(next.y - point.y);
13282
+ 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);
13283
+ });
13284
+ if (!straightEdges) {
13285
+ return false;
13286
+ }
13287
+ var xs = path.points.map(function(point) {
13288
+ return point.x;
13289
+ });
13290
+ var ys = path.points.map(function(point) {
13291
+ return point.y;
13292
+ });
13293
+ var left = (_Math = Math).min.apply(_Math, [].concat(xs));
13294
+ var right = (_Math1 = Math).max.apply(_Math1, [].concat(xs));
13295
+ var top = (_Math2 = Math).min.apply(_Math2, [].concat(ys));
13296
+ var bottom = (_Math3 = Math).max.apply(_Math3, [].concat(ys));
13297
+ 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;
13298
+ }
13299
+
13186
13300
  function resolveIRVisualState(layer, session) {
13301
+ var _layer_masks;
13187
13302
  if (!layer.visible) {
13188
13303
  return undefined;
13189
13304
  }
@@ -13191,19 +13306,22 @@ function resolveIRVisualState(layer, session) {
13191
13306
  if (!state.visible || state.opacity <= 0) {
13192
13307
  return undefined;
13193
13308
  }
13194
- if (layer.mask != null || layer.matte != null) {
13309
+ var unsupportedMask = ((_layer_masks = layer.masks) != null ? _layer_masks : []).some(function(mask) {
13310
+ return layer.type !== 'image' || !maskCoversImage(mask, layer.localBounds);
13311
+ });
13312
+ if (unsupportedMask || layer.matte != null) {
13195
13313
  throwUnsupportedLayerFeature('Mask or clipping is not supported by the flat layer protocol.');
13196
13314
  }
13197
13315
  if (Math.abs(state.opacity - 1) > 1e-6) {
13198
13316
  throwUnsupportedLayerFeature('Layer opacity cannot be expressed by the target protocol.');
13199
13317
  }
13200
13318
  if (layer.blendMode != null && layer.blendMode !== IRBlendMode.Normal) {
13201
- throwUnsupportedLayerFeature('Non-default blending cannot be expressed by the target protocol.');
13319
+ 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);
13202
13320
  }
13203
13321
  return state;
13204
13322
  }
13205
13323
 
13206
- function buildIRStaticLayers(session) {
13324
+ function buildIRStaticLayers(session, sourceIds) {
13207
13325
  var composition = session.composition, maskSourceIds = session.maskSourceIds, options = session.options, warnings = session.warnings;
13208
13326
  var registry = createLayerConverterRegistry(session);
13209
13327
  var result = [];
@@ -13228,6 +13346,7 @@ function buildIRStaticLayers(session) {
13228
13346
  var converted = converter.convert(layer, state, converter.layerType + "_" + String(index).padStart(4, '0'));
13229
13347
  if (converted != null) {
13230
13348
  result.push(converted);
13349
+ sourceIds == null ? void 0 : sourceIds.set(converted, layer.id);
13231
13350
  layerCounts.set(converter.layerType, index);
13232
13351
  }
13233
13352
  } catch (error) {
@@ -13240,9 +13359,9 @@ function buildIRStaticLayers(session) {
13240
13359
  return result;
13241
13360
  }
13242
13361
 
13243
- function assembleSVGStaticLayers(scene, options, warnings, preservedData) {
13362
+ function assembleSVGStaticLayers(scene, options, warnings, preservedData, sourceIds) {
13244
13363
  var session = buildLayerConversionSession(scene, options, warnings, preservedData);
13245
- var data = buildIRStaticLayers(session);
13364
+ var data = buildIRStaticLayers(session, sourceIds);
13246
13365
  var composition = session.composition;
13247
13366
  if (composition.backgroundColor != null) {
13248
13367
  collectLayerWarning(warnings, options, SVG2IR_WARNING_CODES.LAYERS_UNSUPPORTED_TYPE, 'Composition background color is not an image or text layer.');
@@ -13255,6 +13374,1035 @@ function assembleSVGStaticLayers(scene, options, warnings, preservedData) {
13255
13374
  data: data
13256
13375
  };
13257
13376
  }
13377
+ /** Replace baked sources, combine native and raster layers in painter order, then report final diagnostics. */ function assembleSVGLayers(input) {
13378
+ var _warnings, _ordered;
13379
+ 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;
13380
+ var options = input.options, baking = input.baking;
13381
+ var warnings = contextWarnings.filter(function(warning) {
13382
+ return !baking.resolvesWarning(warning, warningSources.get(warning));
13383
+ });
13384
+ var composition = getIRSceneEntryComposition(scene);
13385
+ var nativeScene = _extends({}, scene, {
13386
+ compositions: scene.compositions.map(function(candidate) {
13387
+ return candidate === composition ? _extends({}, candidate, {
13388
+ layers: candidate.layers.filter(function(layer) {
13389
+ return !baking.replacesSource(layerSources.get(layer.id));
13390
+ })
13391
+ }) : candidate;
13392
+ })
13393
+ });
13394
+ var sourceIds = new Map();
13395
+ (_warnings = warnings).push.apply(_warnings, [].concat(baking.warnings));
13396
+ var native = assembleSVGStaticLayers(nativeScene, _extends({}, options, {
13397
+ strict: false,
13398
+ onWarning: undefined
13399
+ }), warnings, preservedData, sourceIds);
13400
+ var ordered = native.data.map(function(layer) {
13401
+ var _layerSources_get, _sourceIds_get;
13402
+ return {
13403
+ path: (_layerSources_get = layerSources.get((_sourceIds_get = sourceIds.get(layer)) != null ? _sourceIds_get : '')) != null ? _layerSources_get : '',
13404
+ layer: layer
13405
+ };
13406
+ });
13407
+ (_ordered = ordered).push.apply(_ordered, [].concat(baking.layers));
13408
+ ordered.sort(function(left, right) {
13409
+ return comparePaths(left.path, right.path);
13410
+ });
13411
+ var counts = {
13412
+ image: 0,
13413
+ text: 0
13414
+ };
13415
+ var data = ordered.map(function(param) {
13416
+ var layer = param.layer;
13417
+ return _extends({}, layer, {
13418
+ id: layer.type + "_" + String(++counts[layer.type]).padStart(4, '0')
13419
+ });
13420
+ });
13421
+ for(var _iterator = _create_for_of_iterator_helper_loose(warnings), _step; !(_step = _iterator()).done;){
13422
+ var warning = _step.value;
13423
+ options.onWarning == null ? void 0 : options.onWarning.call(options, warning);
13424
+ if (options.strict === true) {
13425
+ var message = warning.message.replace(/^\[svg2ge:layers\] /, '');
13426
+ collectLayerWarning([], _extends({}, options, {
13427
+ onWarning: undefined
13428
+ }), warning.code, message, warning.elementSelector);
13429
+ }
13430
+ }
13431
+ return {
13432
+ size: native.size,
13433
+ data: data,
13434
+ warnings: warnings
13435
+ };
13436
+ }
13437
+ function comparePaths(left, right) {
13438
+ var a = left.split('/').map(Number);
13439
+ var b = right.split('/').map(Number);
13440
+ for(var index = 0; index < Math.min(a.length, b.length); index++){
13441
+ if (a[index] !== b[index]) {
13442
+ return a[index] - b[index];
13443
+ }
13444
+ }
13445
+ return a.length - b.length;
13446
+ }
13447
+
13448
+ var animatedElements = new Set([
13449
+ 'animate',
13450
+ 'animatetransform',
13451
+ 'animatemotion',
13452
+ 'set'
13453
+ ]);
13454
+ var declarations$1 = new Set([
13455
+ 'defs',
13456
+ 'style',
13457
+ 'title',
13458
+ 'desc',
13459
+ 'metadata',
13460
+ 'symbol',
13461
+ 'clippath',
13462
+ 'mask',
13463
+ 'filter',
13464
+ 'lineargradient',
13465
+ 'radialgradient',
13466
+ 'pattern',
13467
+ 'marker'
13468
+ ]);
13469
+ /** Preserve selector context until styles are frozen, then isolate the requested paint subtree. */ function prepareSVGSnapshot(source, path, size, inspect) {
13470
+ var parsed = new DOMParser().parseFromString(source, 'image/svg+xml');
13471
+ if (parsed.querySelector('parsererror') != null) {
13472
+ throw new Error('Invalid SVG document.');
13473
+ }
13474
+ var root = parsed.documentElement;
13475
+ var elements = [].concat([
13476
+ root
13477
+ ], Array.from(root.querySelectorAll('*')));
13478
+ var selected = elements.find(function(element) {
13479
+ return buildElementTreePath(element) === path;
13480
+ });
13481
+ if (selected == null) {
13482
+ throw new Error('The graphic source element could not be located.');
13483
+ }
13484
+ if (root.querySelector('script, foreignObject') != null) {
13485
+ throw new Error('Scripts and foreignObject are outside static graphic baking support.');
13486
+ }
13487
+ if (Array.from(root.querySelectorAll('style')).some(function(element) {
13488
+ var _element_textContent;
13489
+ return /@import|@font-face/i.test((_element_textContent = element.textContent) != null ? _element_textContent : '');
13490
+ })) {
13491
+ throw new Error('External stylesheets and fonts require explicit resource preparation.');
13492
+ }
13493
+ for(var _iterator = _create_for_of_iterator_helper_loose(elements), _step; !(_step = _iterator()).done;){
13494
+ var element = _step.value;
13495
+ for(var _iterator1 = _create_for_of_iterator_helper_loose(Array.from(element.attributes)), _step1; !(_step1 = _iterator1()).done;){
13496
+ var attribute = _step1.value;
13497
+ if (/^on/i.test(attribute.name)) {
13498
+ element.removeAttributeNode(attribute);
13499
+ }
13500
+ }
13501
+ }
13502
+ var frame = document.createElement('iframe');
13503
+ frame.setAttribute('sandbox', 'allow-same-origin');
13504
+ frame.style.cssText = "position:fixed;left:-100000px;top:0;width:" + size[0] + "px;height:" + size[1] + "px;border:0;";
13505
+ document.body.appendChild(frame);
13506
+ try {
13507
+ var _loop = function() {
13508
+ var element = _step3.value;
13509
+ var _element_getAttribute;
13510
+ var computed = frameWindow.getComputedStyle(element);
13511
+ var inside = target.contains(element);
13512
+ var ancestor = element !== target && element.contains(target);
13513
+ if ((inside || ancestor) && (computed.animationName !== 'none' || hasAnimationChildren(element))) {
13514
+ throw new Error('Animated graphics require an explicit sampling policy.');
13515
+ }
13516
+ // Freezing inherited defaults on a definition changes <use> instance inheritance.
13517
+ // Freeze only authored declarations, after matching selectors in the intact source tree.
13518
+ var authored = frameDocument.createElement('div').style;
13519
+ authored.cssText = (_element_getAttribute = element.getAttribute('style')) != null ? _element_getAttribute : '';
13520
+ var names = new Set(Array.from(authored));
13521
+ for(var _iterator = _create_for_of_iterator_helper_loose(styleRules), _step; !(_step = _iterator()).done;){
13522
+ var rule = _step.value;
13523
+ if (element.matches(rule.selectorText)) {
13524
+ for(var _iterator1 = _create_for_of_iterator_helper_loose(Array.from(rule.style)), _step1; !(_step1 = _iterator1()).done;){
13525
+ var name = _step1.value;
13526
+ names.add(name);
13527
+ }
13528
+ }
13529
+ }
13530
+ var properties = Array.from(names, function(name) {
13531
+ var value = computed.getPropertyValue(name);
13532
+ value = value.replace(/url\(["']?([^)'"\s]+)["']?\)/g, function(_match, url) {
13533
+ return 'url("' + normalizeReference(url) + '")';
13534
+ });
13535
+ return name + ":" + value + " !important;";
13536
+ });
13537
+ var isTemplate = templateRoots.some(function(template) {
13538
+ return template.contains(element);
13539
+ });
13540
+ frozenStyles.push(isTemplate ? null : properties.join(''));
13541
+ };
13542
+ var frameDocument = frame.contentDocument;
13543
+ var frameWindow = frame.contentWindow;
13544
+ if (frameDocument == null || frameWindow == null) {
13545
+ throw new Error('Unable to create isolated SVG context.');
13546
+ }
13547
+ frameDocument.body.style.cssText = 'margin:0;';
13548
+ var mounted = frameDocument.importNode(root, true);
13549
+ mounted.setAttribute('width', String(size[0]));
13550
+ mounted.setAttribute('height', String(size[1]));
13551
+ frameDocument.body.appendChild(mounted);
13552
+ var mountedElements = [].concat([
13553
+ mounted
13554
+ ], Array.from(mounted.querySelectorAll('*')));
13555
+ var selectedIndex = elements.indexOf(selected);
13556
+ var target = mountedElements[selectedIndex];
13557
+ var normalizeReference = function normalizeReference(url) {
13558
+ if (url.startsWith('#')) {
13559
+ return url;
13560
+ }
13561
+ var hash = url.indexOf('#');
13562
+ if (hash >= 0 && url.slice(0, hash) === frameDocument.baseURI.split('#')[0]) {
13563
+ return url.slice(hash);
13564
+ }
13565
+ throw new Error('External paint resources require explicit resource preparation.');
13566
+ };
13567
+ var frozenStyles = [];
13568
+ var templateRoots = Array.from(mounted.querySelectorAll('use')).flatMap(function(element) {
13569
+ var _ref, _element_getAttribute;
13570
+ var href = (_ref = (_element_getAttribute = element.getAttribute('href')) != null ? _element_getAttribute : element.getAttribute('xlink:href')) != null ? _ref : '';
13571
+ var template = href.startsWith('#') ? mountedElements.find(function(candidate) {
13572
+ return candidate.id === href.slice(1);
13573
+ }) : null;
13574
+ return template == null ? [] : [
13575
+ template
13576
+ ];
13577
+ });
13578
+ var styleRules = [];
13579
+ var collectRules = function collectRules1(rules) {
13580
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(rules)), _step; !(_step = _iterator()).done;){
13581
+ var rule = _step.value;
13582
+ if (isStyleRule$2(rule)) {
13583
+ styleRules.push(rule);
13584
+ } else if (hasNestedRules$1(rule)) {
13585
+ if (isMediaRule(rule) && !frameWindow.matchMedia(rule.conditionText).matches) {
13586
+ continue;
13587
+ }
13588
+ collectRules(rule.cssRules);
13589
+ }
13590
+ }
13591
+ };
13592
+ for(var _iterator2 = _create_for_of_iterator_helper_loose(Array.from(frameDocument.styleSheets)), _step2; !(_step2 = _iterator2()).done;){
13593
+ var sheet = _step2.value;
13594
+ collectRules(sheet.cssRules);
13595
+ }
13596
+ for(var _iterator3 = _create_for_of_iterator_helper_loose(mountedElements), _step3; !(_step3 = _iterator3()).done;)_loop();
13597
+ for(var index = 0; index < mountedElements.length; index++){
13598
+ var style = frozenStyles[index];
13599
+ if (style != null) {
13600
+ mountedElements[index].setAttribute('style', style);
13601
+ }
13602
+ }
13603
+ var byId = new Map(mountedElements.filter(function(element) {
13604
+ return element.id !== '';
13605
+ }).map(function(element) {
13606
+ return [
13607
+ element.id,
13608
+ element
13609
+ ];
13610
+ }));
13611
+ var seen = new Set();
13612
+ var checkDependencies = function checkDependencies1(element) {
13613
+ if (seen.has(element)) {
13614
+ return;
13615
+ }
13616
+ seen.add(element);
13617
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(element.attributes)), _step; !(_step = _iterator()).done;){
13618
+ var attribute = _step.value;
13619
+ if (attribute.localName === 'href' && element.tagName.toLowerCase() === 'a') {
13620
+ continue;
13621
+ }
13622
+ if (attribute.localName === 'href' && !attribute.value.startsWith('#') && !([
13623
+ 'image',
13624
+ 'feimage'
13625
+ ].includes(element.tagName.toLowerCase()) && /^data:image\//i.test(attribute.value))) {
13626
+ throw new Error('External SVG references require explicit resource preparation.');
13627
+ }
13628
+ var normalized = attribute.value.replace(/url\(\s*["']?([^)'"\s]+)["']?\s*\)/g, function(_match, url) {
13629
+ return 'url("' + normalizeReference(url) + '")';
13630
+ });
13631
+ var ids = Array.from(normalized.matchAll(/url\(["']?#([^)'"\s]+)["']?\)/g), function(match) {
13632
+ return match[1];
13633
+ });
13634
+ if (normalized !== attribute.value) {
13635
+ element.setAttribute(attribute.name, normalized);
13636
+ }
13637
+ if (attribute.localName === 'href' && attribute.value.startsWith('#')) {
13638
+ ids.push(attribute.value.slice(1));
13639
+ }
13640
+ for(var _iterator1 = _create_for_of_iterator_helper_loose(ids), _step1; !(_step1 = _iterator1()).done;){
13641
+ var id = _step1.value;
13642
+ var dependency = byId.get(id);
13643
+ if (dependency == null) {
13644
+ throw new Error("Missing SVG reference: #" + id + ".");
13645
+ }
13646
+ checkDependencies(dependency);
13647
+ }
13648
+ }
13649
+ for(var _iterator2 = _create_for_of_iterator_helper_loose(Array.from(element.children)), _step2; !(_step2 = _iterator2()).done;){
13650
+ var child = _step2.value;
13651
+ if (!declarations$1.has(child.tagName.toLowerCase())) {
13652
+ checkDependencies(child);
13653
+ }
13654
+ }
13655
+ };
13656
+ checkDependencies(target);
13657
+ for(var _iterator4 = _create_for_of_iterator_helper_loose(seen), _step4; !(_step4 = _iterator4()).done;){
13658
+ var dependency = _step4.value;
13659
+ if (frameWindow.getComputedStyle(dependency).animationName !== 'none' || hasAnimationChildren(dependency)) {
13660
+ throw new Error('Animated graphics require an explicit sampling policy.');
13661
+ }
13662
+ }
13663
+ inspect == null ? void 0 : inspect({
13664
+ root: mounted,
13665
+ target: target,
13666
+ elements: mountedElements,
13667
+ dependencies: seen,
13668
+ readStyle: function readStyle(element) {
13669
+ return frameWindow.getComputedStyle(element);
13670
+ }
13671
+ });
13672
+ var isolate = function isolate1(element) {
13673
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(element.children)), _step; !(_step = _iterator()).done;){
13674
+ var child = _step.value;
13675
+ var tag = child.tagName.toLowerCase();
13676
+ if (declarations$1.has(tag) || child === target || target.contains(child)) {
13677
+ continue;
13678
+ }
13679
+ if (child.contains(target)) {
13680
+ isolate(child);
13681
+ } else {
13682
+ var definitions = frameDocument.createElementNS('http://www.w3.org/2000/svg', 'defs');
13683
+ child.replaceWith(definitions);
13684
+ definitions.appendChild(child);
13685
+ }
13686
+ }
13687
+ };
13688
+ if (target !== mounted) {
13689
+ isolate(mounted);
13690
+ }
13691
+ return new XMLSerializer().serializeToString(mounted);
13692
+ } finally{
13693
+ frame.remove();
13694
+ }
13695
+ }
13696
+ /** Only animations attached to this element reject its own bake scope, not unrelated subtrees. */ function hasAnimationChildren(element) {
13697
+ return Array.from(element.children).some(function(child) {
13698
+ return animatedElements.has(child.tagName.toLowerCase());
13699
+ });
13700
+ }
13701
+ function isStyleRule$2(rule) {
13702
+ return rule.type === 1;
13703
+ }
13704
+ function hasNestedRules$1(rule) {
13705
+ return 'cssRules' in rule;
13706
+ }
13707
+ function isMediaRule(rule) {
13708
+ return rule.type === 4;
13709
+ }
13710
+
13711
+ /** Render an SVG subtree as a cropped PNG, or return null if it has no visible pixels. */ function rasterizeSVG(source, path, size, scale, inspect) {
13712
+ if (scale === void 0) scale = 2;
13713
+ return _async_to_generator(function() {
13714
+ var snapshot, canvas;
13715
+ return _ts_generator(this, function(_state) {
13716
+ switch(_state.label){
13717
+ case 0:
13718
+ if (!Number.isFinite(scale) || scale <= 0) {
13719
+ throw new RangeError('rasterScale must be finite and positive.');
13720
+ }
13721
+ if (Math.ceil(size[0] * scale) * Math.ceil(size[1] * scale) > 16777216) {
13722
+ throw new RangeError('SVG rasterization exceeds the 16 megapixel working limit; reduce rasterScale.');
13723
+ }
13724
+ snapshot = prepareSVGSnapshot(source, path, size, inspect);
13725
+ return [
13726
+ 4,
13727
+ renderSVG(snapshot, size, scale)
13728
+ ];
13729
+ case 1:
13730
+ canvas = _state.sent();
13731
+ return [
13732
+ 2,
13733
+ cropRasterImage(canvas, scale)
13734
+ ];
13735
+ }
13736
+ });
13737
+ })();
13738
+ }
13739
+ /** No DOM access at module initialization: the Node entry also imports this module. */ function canRasterizeSVG() {
13740
+ return typeof window !== 'undefined' && typeof document !== 'undefined' && typeof window.HTMLCanvasElement === 'function' && typeof window.Image === 'function' && typeof window.getComputedStyle === 'function';
13741
+ }
13742
+ function renderSVG(svg, size, scale) {
13743
+ return _async_to_generator(function() {
13744
+ var canvas, context, image, url;
13745
+ return _ts_generator(this, function(_state) {
13746
+ switch(_state.label){
13747
+ case 0:
13748
+ canvas = document.createElement('canvas');
13749
+ canvas.width = Math.ceil(size[0] * scale);
13750
+ canvas.height = Math.ceil(size[1] * scale);
13751
+ context = canvas.getContext('2d');
13752
+ if (context == null) {
13753
+ throw new Error('A 2D canvas context is required for SVG rasterization.');
13754
+ }
13755
+ image = new Image();
13756
+ url = URL.createObjectURL(new Blob([
13757
+ svg
13758
+ ], {
13759
+ type: 'image/svg+xml'
13760
+ }));
13761
+ _state.label = 1;
13762
+ case 1:
13763
+ _state.trys.push([
13764
+ 1,
13765
+ ,
13766
+ 3,
13767
+ 4
13768
+ ]);
13769
+ return [
13770
+ 4,
13771
+ new Promise(function(resolve, reject) {
13772
+ image.onload = function() {
13773
+ return resolve();
13774
+ };
13775
+ image.onerror = function() {
13776
+ return reject(new Error('The prepared SVG could not be decoded.'));
13777
+ };
13778
+ image.src = url;
13779
+ })
13780
+ ];
13781
+ case 2:
13782
+ _state.sent();
13783
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
13784
+ return [
13785
+ 2,
13786
+ canvas
13787
+ ];
13788
+ case 3:
13789
+ URL.revokeObjectURL(url);
13790
+ return [
13791
+ 7
13792
+ ];
13793
+ case 4:
13794
+ return [
13795
+ 2
13796
+ ];
13797
+ }
13798
+ });
13799
+ })();
13800
+ }
13801
+ /** Trim transparent pixels after rendering, retaining strokes, blur and filter extents. */ function cropRasterImage(canvas, scale) {
13802
+ var context = canvas.getContext('2d');
13803
+ if (context == null) {
13804
+ throw new Error('A 2D canvas context is required for SVG rasterization.');
13805
+ }
13806
+ var data = context.getImageData(0, 0, canvas.width, canvas.height).data;
13807
+ var left = canvas.width;
13808
+ var top = canvas.height;
13809
+ var right = 0;
13810
+ var bottom = 0;
13811
+ for(var y = 0; y < canvas.height; y++){
13812
+ for(var x = 0; x < canvas.width; x++){
13813
+ if (data[(y * canvas.width + x) * 4 + 3] === 0) {
13814
+ continue;
13815
+ }
13816
+ left = Math.min(left, x);
13817
+ top = Math.min(top, y);
13818
+ right = Math.max(right, x + 1);
13819
+ bottom = Math.max(bottom, y + 1);
13820
+ }
13821
+ }
13822
+ if (right <= left || bottom <= top) {
13823
+ return null;
13824
+ }
13825
+ var cropped = document.createElement('canvas');
13826
+ cropped.width = right - left;
13827
+ cropped.height = bottom - top;
13828
+ var croppedContext = cropped.getContext('2d');
13829
+ if (croppedContext == null) {
13830
+ throw new Error('A 2D canvas context is required for SVG rasterization.');
13831
+ }
13832
+ croppedContext.drawImage(canvas, left, top, cropped.width, cropped.height, 0, 0, cropped.width, cropped.height);
13833
+ return {
13834
+ url: cropped.toDataURL('image/png'),
13835
+ bbox: [
13836
+ left / scale,
13837
+ top / scale,
13838
+ right / scale,
13839
+ bottom / scale
13840
+ ]
13841
+ };
13842
+ }
13843
+
13844
+ var normalValues = new Set([
13845
+ 'normal',
13846
+ 'initial',
13847
+ 'inherit',
13848
+ 'unset',
13849
+ 'revert',
13850
+ 'revert-layer'
13851
+ ]);
13852
+ /** Replace non-normal mix-blend-mode declarations with normal and report each downgrade. */ function normalizeLayerBlending(source) {
13853
+ var _loop = function() {
13854
+ var element = _step.value;
13855
+ var _element_getAttribute;
13856
+ var _readPresentationAttribute;
13857
+ var tag = element.tagName.toLowerCase();
13858
+ var id = (_element_getAttribute = element.getAttribute('id')) != null ? _element_getAttribute : '';
13859
+ var selector = id === '' ? tag : tag + "#" + id;
13860
+ var mode = (_readPresentationAttribute = readPresentationAttribute(element, 'mix-blend-mode')) == null ? void 0 : _readPresentationAttribute.replace(/\/\*[\s\S]*?\*\//g, '').trim();
13861
+ if (mode != null && !normalValues.has(mode.toLowerCase())) {
13862
+ downgrades.push({
13863
+ mode: mode,
13864
+ selector: selector
13865
+ });
13866
+ }
13867
+ var style = element.getAttribute('style');
13868
+ if (style != null) {
13869
+ var normalized = normalizeBlendDeclarations(style);
13870
+ if (normalized !== style) {
13871
+ element.setAttribute('style', normalized);
13872
+ changed = true;
13873
+ }
13874
+ }
13875
+ var attribute = element.getAttribute('mix-blend-mode');
13876
+ if (attribute != null && !normalValues.has(attribute.trim().toLowerCase())) {
13877
+ element.setAttribute('mix-blend-mode', 'normal');
13878
+ changed = true;
13879
+ }
13880
+ if (tag === 'style') {
13881
+ var _element_textContent;
13882
+ var text = (_element_textContent = element.textContent) != null ? _element_textContent : '';
13883
+ var normalized1 = normalizeBlendDeclarations(text, function(value) {
13884
+ return downgrades.push({
13885
+ mode: value,
13886
+ selector: selector
13887
+ });
13888
+ });
13889
+ if (normalized1 !== text) {
13890
+ element.textContent = normalized1;
13891
+ changed = true;
13892
+ }
13893
+ }
13894
+ };
13895
+ var svg = SVG(source);
13896
+ var downgrades = [];
13897
+ var changed = false;
13898
+ for(var _iterator = _create_for_of_iterator_helper_loose([].concat([
13899
+ svg.node
13900
+ ], Array.from(svg.node.querySelectorAll('*')))), _step; !(_step = _iterator()).done;)_loop();
13901
+ return {
13902
+ source: changed ? svg.svg() : source,
13903
+ downgrades: downgrades
13904
+ };
13905
+ }
13906
+ /** Match declaration boundaries without changing strings, comments or function arguments. */ function normalizeBlendDeclarations(source, onDowngrade) {
13907
+ var replacements = [];
13908
+ var start = 0;
13909
+ var colon = -1;
13910
+ var parentheses = 0;
13911
+ var quote;
13912
+ var comment = false;
13913
+ var finish = function finish(end) {
13914
+ if (colon < start) {
13915
+ return;
13916
+ }
13917
+ var name = source.slice(start, colon).replace(/\/\*[\s\S]*?\*\//g, '').trim().toLowerCase();
13918
+ if (name !== 'mix-blend-mode') {
13919
+ return;
13920
+ }
13921
+ var value = source.slice(colon + 1, end).replace(/\/\*[\s\S]*?\*\//g, '').trim();
13922
+ var mode = value.replace(/\s*!important\s*$/i, '').trim();
13923
+ if (mode === '' || normalValues.has(mode.toLowerCase())) {
13924
+ return;
13925
+ }
13926
+ onDowngrade == null ? void 0 : onDowngrade(mode);
13927
+ replacements.push({
13928
+ start: colon + 1,
13929
+ end: end,
13930
+ value: /!important\s*$/i.test(value) ? ' normal !important' : ' normal'
13931
+ });
13932
+ };
13933
+ for(var index = 0; index < source.length; index++){
13934
+ var character = source[index];
13935
+ var next = source[index + 1];
13936
+ if (comment) {
13937
+ if (character === '*' && next === '/') {
13938
+ comment = false;
13939
+ index++;
13940
+ }
13941
+ continue;
13942
+ }
13943
+ if (quote != null) {
13944
+ if (character === '\\') {
13945
+ index++;
13946
+ } else if (character === quote) {
13947
+ quote = undefined;
13948
+ }
13949
+ continue;
13950
+ }
13951
+ if (character === '/' && next === '*') {
13952
+ comment = true;
13953
+ index++;
13954
+ continue;
13955
+ }
13956
+ if (character === '"' || character === "'") {
13957
+ quote = character;
13958
+ continue;
13959
+ }
13960
+ if (character === '(') {
13961
+ parentheses++;
13962
+ continue;
13963
+ }
13964
+ if (character === ')') {
13965
+ parentheses = Math.max(0, parentheses - 1);
13966
+ continue;
13967
+ }
13968
+ if (parentheses > 0) {
13969
+ continue;
13970
+ }
13971
+ if (character === ':' && colon < start) {
13972
+ colon = index;
13973
+ }
13974
+ if (character === ';' || character === '}' || character === '{') {
13975
+ if (character !== '{') {
13976
+ finish(index);
13977
+ }
13978
+ start = index + 1;
13979
+ colon = -1;
13980
+ }
13981
+ }
13982
+ finish(source.length);
13983
+ var result = '';
13984
+ var cursor = 0;
13985
+ for(var _iterator = _create_for_of_iterator_helper_loose(replacements), _step; !(_step = _iterator()).done;){
13986
+ var replacement = _step.value;
13987
+ result += source.slice(cursor, replacement.start) + replacement.value;
13988
+ cursor = replacement.end;
13989
+ }
13990
+ return result + source.slice(cursor);
13991
+ }
13992
+
13993
+ var declarations = new Set([
13994
+ 'defs',
13995
+ 'style',
13996
+ 'title',
13997
+ 'desc',
13998
+ 'metadata',
13999
+ 'symbol',
14000
+ 'clippath',
14001
+ 'mask',
14002
+ 'filter',
14003
+ 'lineargradient',
14004
+ 'radialgradient',
14005
+ 'pattern',
14006
+ 'marker'
14007
+ ]);
14008
+ var graphics = new Set([
14009
+ 'path',
14010
+ 'rect',
14011
+ 'circle',
14012
+ 'ellipse',
14013
+ 'line',
14014
+ 'polyline',
14015
+ 'polygon',
14016
+ 'use'
14017
+ ]);
14018
+ var containers = new Set([
14019
+ 'svg',
14020
+ 'g',
14021
+ 'a',
14022
+ 'switch'
14023
+ ]);
14024
+ var groupEffects = [
14025
+ 'opacity',
14026
+ 'filter',
14027
+ 'mask',
14028
+ 'clip-path'
14029
+ ];
14030
+ var native = new Set([
14031
+ 'text',
14032
+ 'image',
14033
+ 'foreignobject'
14034
+ ]);
14035
+ /** Select graphic-only subtrees; keep native text and images as separate layers. */ function planGraphicBaking(source) {
14036
+ var root = SVG(source).node;
14037
+ var scopes = [];
14038
+ var warnings = [];
14039
+ var effectRules = collectGroupEffectRules(root);
14040
+ var byId = new Map(Array.from(root.querySelectorAll('[id]')).map(function(element) {
14041
+ var _element_getAttribute;
14042
+ return [
14043
+ (_element_getAttribute = element.getAttribute('id')) != null ? _element_getAttribute : '',
14044
+ element
14045
+ ];
14046
+ }));
14047
+ var tagOf = function tagOf(element) {
14048
+ return element.tagName.toLowerCase();
14049
+ };
14050
+ var selectorOf = function selectorOf(element) {
14051
+ var _element_getAttribute;
14052
+ var id = (_element_getAttribute = element.getAttribute('id')) != null ? _element_getAttribute : '';
14053
+ return "" + tagOf(element) + (id === '' ? '' : "#" + id);
14054
+ };
14055
+ var references = function references(element) {
14056
+ var ids = Array.from(element.attributes).flatMap(function(attribute) {
14057
+ var values = Array.from(attribute.value.matchAll(/url\(\s*['"]?#([^)'"\s]+)['"]?\s*\)/g), function(match) {
14058
+ return match[1];
14059
+ });
14060
+ if (attribute.localName === 'href' && attribute.value.startsWith('#')) {
14061
+ values.push(attribute.value.slice(1));
14062
+ }
14063
+ return values;
14064
+ });
14065
+ return ids.flatMap(function(id) {
14066
+ var target = byId.get(id);
14067
+ return target == null ? [] : [
14068
+ target
14069
+ ];
14070
+ });
14071
+ };
14072
+ var containsNative = function containsNative1(element, seen) {
14073
+ if (seen === void 0) seen = new Set();
14074
+ if (seen.has(element)) {
14075
+ return false;
14076
+ }
14077
+ seen.add(element);
14078
+ if (native.has(tagOf(element))) {
14079
+ return true;
14080
+ }
14081
+ return Array.from(element.children).some(function(child) {
14082
+ return !declarations.has(tagOf(child)) && containsNative(child, seen);
14083
+ }) || references(element).some(function(target) {
14084
+ return containsNative(target, seen);
14085
+ });
14086
+ };
14087
+ var hasGraphics = function hasGraphics1(element) {
14088
+ return graphics.has(tagOf(element)) || Array.from(element.children).some(function(child) {
14089
+ return !declarations.has(tagOf(child)) && hasGraphics(child);
14090
+ });
14091
+ };
14092
+ var hasGroupEffect = function hasGroupEffect(element) {
14093
+ var _element_getAttribute;
14094
+ var style = (_element_getAttribute = element.getAttribute('style')) != null ? _element_getAttribute : '';
14095
+ return effectRules.some(function(rule) {
14096
+ return element.matches(rule.selectorText);
14097
+ }) || hasGraphicGroupEffect(function(name) {
14098
+ var _element_getAttribute;
14099
+ var _exec_, _exec;
14100
+ 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();
14101
+ });
14102
+ };
14103
+ var visit = function visit1(element) {
14104
+ var _element_getAttribute, _ref;
14105
+ var _exec_, _exec;
14106
+ var tag = tagOf(element);
14107
+ var style = (_element_getAttribute = element.getAttribute('style')) != null ? _element_getAttribute : '';
14108
+ 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');
14109
+ if (display === 'none') {
14110
+ return;
14111
+ }
14112
+ if (declarations.has(tag) || native.has(tag)) {
14113
+ return;
14114
+ }
14115
+ if (!containers.has(tag) && !graphics.has(tag)) {
14116
+ return;
14117
+ }
14118
+ if (!hasGraphics(element)) {
14119
+ return;
14120
+ }
14121
+ if ((graphics.has(tag) || tag === 'switch') && !containsNative(element)) {
14122
+ scopes.push({
14123
+ path: buildElementTreePath(element),
14124
+ selector: selectorOf(element),
14125
+ isGroup: containers.has(tag)
14126
+ });
14127
+ return;
14128
+ }
14129
+ if (hasGroupEffect(element) && !containsNative(element)) {
14130
+ scopes.push({
14131
+ path: buildElementTreePath(element),
14132
+ selector: selectorOf(element),
14133
+ isGroup: containers.has(tag)
14134
+ });
14135
+ return;
14136
+ }
14137
+ if (hasGroupEffect(element)) {
14138
+ warnings.push({
14139
+ message: 'A compositing group contains native text or images; its graphics cannot be baked separately.',
14140
+ selector: selectorOf(element)
14141
+ });
14142
+ return;
14143
+ }
14144
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(element.children)), _step; !(_step = _iterator()).done;){
14145
+ var child = _step.value;
14146
+ visit(child);
14147
+ }
14148
+ };
14149
+ visit(root);
14150
+ return {
14151
+ scopes: scopes,
14152
+ warnings: warnings
14153
+ };
14154
+ }
14155
+ function collectGroupEffectRules(root) {
14156
+ var result = [];
14157
+ if (typeof CSSStyleSheet !== 'function') {
14158
+ return result;
14159
+ }
14160
+ var visit = function visit1(rules) {
14161
+ var _loop = function() {
14162
+ var rule = _step.value;
14163
+ if (isStyleRule$1(rule)) {
14164
+ var affectsGroup = hasGraphicGroupEffect(function(name) {
14165
+ var value = rule.style.getPropertyValue(name).trim();
14166
+ return value === '' || value === 'initial' || value === 'unset' ? undefined : value;
14167
+ });
14168
+ if (affectsGroup) {
14169
+ result.push(rule);
14170
+ }
14171
+ } else if (hasNestedRules(rule)) {
14172
+ visit(rule.cssRules);
14173
+ }
14174
+ };
14175
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(rules)), _step; !(_step = _iterator()).done;)_loop();
14176
+ };
14177
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(root.querySelectorAll('style'))), _step; !(_step = _iterator()).done;){
14178
+ var style = _step.value;
14179
+ var _style_textContent;
14180
+ var sheet = new CSSStyleSheet();
14181
+ sheet.replaceSync((_style_textContent = style.textContent) != null ? _style_textContent : '');
14182
+ visit(sheet.cssRules);
14183
+ }
14184
+ return result;
14185
+ }
14186
+ /** Reject text/image dependencies and effects that cannot be rendered independently. */ function validateGraphicSnapshot(context) {
14187
+ var _loop = function() {
14188
+ var element = _step1.value;
14189
+ var computed = readStyle(element);
14190
+ var ancestor = element !== target && element.contains(target);
14191
+ var groupEffect = ancestor && hasGraphicGroupEffect(function(name) {
14192
+ return name === 'mask' ? computed.maskImage : computed.getPropertyValue(name);
14193
+ });
14194
+ if (ancestor && (groupEffect || computed.mixBlendMode !== 'normal')) {
14195
+ throw new Error('A mixed group effect cannot be applied independently to its graphics.');
14196
+ }
14197
+ if (target.contains(element) && target !== root && computed.mixBlendMode !== 'normal') {
14198
+ throw new Error('Blend modes that depend on an external backdrop cannot be baked independently.');
14199
+ }
14200
+ };
14201
+ var root = context.root, target = context.target, elements = context.elements, dependencies = context.dependencies, readStyle = context.readStyle;
14202
+ for(var _iterator = _create_for_of_iterator_helper_loose(dependencies), _step; !(_step = _iterator()).done;){
14203
+ var element = _step.value;
14204
+ if ([
14205
+ 'text',
14206
+ 'image',
14207
+ 'foreignobject'
14208
+ ].includes(element.tagName.toLowerCase())) {
14209
+ throw new Error('Graphic dependencies contain native text or images; they must remain editable.');
14210
+ }
14211
+ }
14212
+ for(var _iterator1 = _create_for_of_iterator_helper_loose(elements), _step1; !(_step1 = _iterator1()).done;)_loop();
14213
+ }
14214
+ function isStyleRule$1(rule) {
14215
+ return rule.type === 1;
14216
+ }
14217
+ function hasNestedRules(rule) {
14218
+ return 'cssRules' in rule;
14219
+ }
14220
+ function hasGraphicGroupEffect(readValue) {
14221
+ return groupEffects.some(function(name) {
14222
+ var value = readValue(name);
14223
+ return value != null && value !== 'none' && value !== 'normal' && value !== '1';
14224
+ });
14225
+ }
14226
+
14227
+ /** Mask and clipPath definitions do not produce visible layers. */ function collectNonRenderingDeclarationPaths(source) {
14228
+ var root = SVG(source).node;
14229
+ var elements = Array.from(root.querySelectorAll('*')).filter(function(element) {
14230
+ var tag = element.tagName.toLowerCase();
14231
+ return tag === 'mask' || tag === 'clippath';
14232
+ });
14233
+ return new Set(elements.map(buildElementTreePath));
14234
+ }
14235
+ /** A stylesheet diagnostic is resolved only when every element it can affect was baked. */ function collectBakedStylesheetPaths(source, isBaked) {
14236
+ var resolved = new Set();
14237
+ if (typeof DOMParser === 'undefined' || typeof CSSStyleSheet !== 'function') {
14238
+ return resolved;
14239
+ }
14240
+ var root = new DOMParser().parseFromString(source, 'image/svg+xml').documentElement;
14241
+ var allUsesBaked = Array.from(root.querySelectorAll('use')).every(function(element) {
14242
+ return isBaked(buildElementTreePath(element));
14243
+ });
14244
+ var isHandled = function isHandled(element) {
14245
+ if (isBaked(buildElementTreePath(element))) {
14246
+ return true;
14247
+ }
14248
+ if (element.closest('defs, symbol, marker, pattern, clipPath, mask, filter') != null) {
14249
+ return allUsesBaked;
14250
+ }
14251
+ return false;
14252
+ };
14253
+ for(var _iterator = _create_for_of_iterator_helper_loose(Array.from(root.querySelectorAll('style'))), _step; !(_step = _iterator()).done;){
14254
+ var style = _step.value;
14255
+ var _style_textContent;
14256
+ var sheet = new CSSStyleSheet();
14257
+ sheet.replaceSync((_style_textContent = style.textContent) != null ? _style_textContent : '');
14258
+ var rules = Array.from(sheet.cssRules);
14259
+ var handled = rules.every(function(rule) {
14260
+ if (!isStyleRule(rule)) {
14261
+ return false;
14262
+ }
14263
+ if (Array.from(rule.style).every(function(name) {
14264
+ return name === 'mix-blend-mode';
14265
+ })) {
14266
+ return true;
14267
+ }
14268
+ var matched = [].concat([
14269
+ root
14270
+ ], Array.from(root.querySelectorAll('*'))).filter(function(element) {
14271
+ return element.matches(rule.selectorText);
14272
+ });
14273
+ return matched.every(isHandled);
14274
+ });
14275
+ if (handled) {
14276
+ resolved.add(buildElementTreePath(style));
14277
+ }
14278
+ }
14279
+ return resolved;
14280
+ }
14281
+ function isStyleRule(rule) {
14282
+ return rule.type === 1;
14283
+ }
14284
+
14285
+ /** Rasterize graphics and track the source layers and warnings they replace. */ function buildBakedLayers(source, size, options, rasterScale) {
14286
+ return _async_to_generator(function() {
14287
+ 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;
14288
+ return _ts_generator(this, function(_state) {
14289
+ switch(_state.label){
14290
+ case 0:
14291
+ deferredOptions = _extends({}, options, {
14292
+ strict: false,
14293
+ onWarning: undefined
14294
+ });
14295
+ bakedPaths = [];
14296
+ baked = [];
14297
+ bakingWarnings = [];
14298
+ blending = normalizeLayerBlending(source);
14299
+ plan = planGraphicBaking(blending.source);
14300
+ for(_iterator = _create_for_of_iterator_helper_loose(blending.downgrades); !(_step = _iterator()).done;){
14301
+ downgrade = _step.value;
14302
+ 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);
14303
+ }
14304
+ for(_iterator1 = _create_for_of_iterator_helper_loose(plan.warnings); !(_step1 = _iterator1()).done;){
14305
+ warning = _step1.value;
14306
+ collectLayerWarning(bakingWarnings, deferredOptions, SVG2IR_WARNING_CODES.LAYERS_UNSUPPORTED_FEATURE, warning.message, warning.selector);
14307
+ }
14308
+ _iterator2 = _create_for_of_iterator_helper_loose(plan.scopes);
14309
+ _state.label = 1;
14310
+ case 1:
14311
+ if (!!(_step2 = _iterator2()).done) return [
14312
+ 3,
14313
+ 6
14314
+ ];
14315
+ scope = _step2.value;
14316
+ _state.label = 2;
14317
+ case 2:
14318
+ _state.trys.push([
14319
+ 2,
14320
+ 4,
14321
+ ,
14322
+ 5
14323
+ ]);
14324
+ if (!canRasterizeSVG()) {
14325
+ throw new Error('Graphic baking requires a browser with SVG and Canvas support.');
14326
+ }
14327
+ return [
14328
+ 4,
14329
+ rasterizeSVG(blending.source, scope.path, size, rasterScale, validateGraphicSnapshot)
14330
+ ];
14331
+ case 3:
14332
+ image = _state.sent();
14333
+ bakedPaths.push(scope.path);
14334
+ 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.';
14335
+ collectLayerWarning(bakingWarnings, deferredOptions, SVG2IR_WARNING_CODES.LAYERS_GRAPHIC_BAKED, message, scope.selector);
14336
+ if (image == null) {
14337
+ return [
14338
+ 3,
14339
+ 5
14340
+ ];
14341
+ }
14342
+ _image_bbox = image.bbox, left = _image_bbox[0], top = _image_bbox[1], right = _image_bbox[2], bottom = _image_bbox[3];
14343
+ width = right - left;
14344
+ height = bottom - top;
14345
+ baked.push({
14346
+ path: scope.path,
14347
+ layer: {
14348
+ id: '',
14349
+ type: 'image',
14350
+ role: 'content',
14351
+ bbox: image.bbox,
14352
+ size: [
14353
+ width,
14354
+ height
14355
+ ],
14356
+ rotation: [
14357
+ 0,
14358
+ 0,
14359
+ 0
14360
+ ],
14361
+ url: image.url,
14362
+ width: width,
14363
+ height: height
14364
+ }
14365
+ });
14366
+ return [
14367
+ 3,
14368
+ 5
14369
+ ];
14370
+ case 4:
14371
+ error = _state.sent();
14372
+ reason = _instanceof(error, Error) ? error.message : String(error);
14373
+ collectLayerWarning(bakingWarnings, deferredOptions, SVG2IR_WARNING_CODES.LAYERS_UNSUPPORTED_FEATURE, "Graphic baking failed: " + reason, scope.selector);
14374
+ return [
14375
+ 3,
14376
+ 5
14377
+ ];
14378
+ case 5:
14379
+ return [
14380
+ 3,
14381
+ 1
14382
+ ];
14383
+ case 6:
14384
+ replacesSource = function replacesSource(path) {
14385
+ return path != null && bakedPaths.some(function(scope) {
14386
+ return scope === '' || path === scope || path.startsWith("" + scope + "/");
14387
+ });
14388
+ };
14389
+ handledStyles = collectBakedStylesheetPaths(blending.source, replacesSource);
14390
+ declarations = collectNonRenderingDeclarationPaths(source);
14391
+ return [
14392
+ 2,
14393
+ {
14394
+ layers: baked,
14395
+ warnings: bakingWarnings,
14396
+ replacesSource: replacesSource,
14397
+ resolvesWarning: function resolvesWarning(warning, path) {
14398
+ return replacesSource(path) || warning.code === SVG2IR_WARNING_CODES.ELEMENT_DROPPED && path != null && (handledStyles.has(path) || declarations.has(path));
14399
+ }
14400
+ }
14401
+ ];
14402
+ }
14403
+ });
14404
+ })();
14405
+ }
13258
14406
 
13259
14407
  function encodeBase64(data) {
13260
14408
  var chunks = [];
@@ -13443,30 +14591,115 @@ function fetchImageResource(url) {
13443
14591
  }).apply(this, arguments);
13444
14592
  }
13445
14593
 
13446
- function convertSVGToLayers(source, options, loadImage, preservedData) {
13447
- return _async_to_generator(function() {
13448
- var splitResult, parsed, _assembleSVGStaticLayers, size, data, _tmp;
14594
+ var animatedTags = new Set([
14595
+ 'animate',
14596
+ 'animatetransform',
14597
+ 'animatemotion',
14598
+ 'set'
14599
+ ]);
14600
+ /** Static layers cannot sample animation; drop SMIL nodes so elements keep their authored state. */ function stripLayerAnimation(source) {
14601
+ var svg = SVG(source);
14602
+ if ((svg == null ? void 0 : svg.node) == null) {
14603
+ return {
14604
+ source: source,
14605
+ removed: 0
14606
+ };
14607
+ }
14608
+ var elements = Array.from(svg.node.querySelectorAll('*')).filter(function(element) {
14609
+ return animatedTags.has(element.tagName.toLowerCase());
14610
+ });
14611
+ if (elements.length === 0) {
14612
+ return {
14613
+ source: source,
14614
+ removed: 0
14615
+ };
14616
+ }
14617
+ for(var _iterator = _create_for_of_iterator_helper_loose(elements), _step; !(_step = _iterator()).done;){
14618
+ var element = _step.value;
14619
+ element.remove();
14620
+ }
14621
+ return {
14622
+ source: svg.svg(),
14623
+ removed: elements.length
14624
+ };
14625
+ }
14626
+
14627
+ function convertSVGToLayers() {
14628
+ return _async_to_generator(function(source, options, preservedData) {
14629
+ var loadImage, _options_rasterScale, rasterScale, conversionOptions, layerSources, warningSources, collected, stripped, staticSource, parsed, context, composition, baking, assembled, _tmp, _tmp1;
13449
14630
  return _ts_generator(this, function(_state) {
13450
14631
  switch(_state.label){
13451
14632
  case 0:
13452
- splitResult = preservedData == null ? splitSVG(source, options) : undefined;
13453
- parsed = splitResult != null ? splitResult : parseSVGToIRWithPreservedData(source, options);
13454
- _assembleSVGStaticLayers = assembleSVGStaticLayers(parsed.ir, options, parsed.warnings, preservedData != null ? preservedData : splitResult == null ? void 0 : splitResult.preservedData), size = _assembleSVGStaticLayers.size, data = _assembleSVGStaticLayers.data;
13455
- _tmp = {
13456
- size: size
14633
+ if (options === void 0) options = {};
14634
+ loadImage = options.loadImage, _options_rasterScale = options.rasterScale, rasterScale = _options_rasterScale === void 0 ? 2 : _options_rasterScale, conversionOptions = _object_without_properties_loose(options, [
14635
+ "loadImage",
14636
+ "rasterScale"
14637
+ ]);
14638
+ layerSources = new Map();
14639
+ warningSources = new Map();
14640
+ collected = {
14641
+ textDataByLayerId: new Map(),
14642
+ paintAnimationsByLayerId: new Map(),
14643
+ shapeAnimationsByLayerId: new Map()
14644
+ };
14645
+ stripped = stripLayerAnimation(source);
14646
+ staticSource = stripped.source;
14647
+ // Preserve original layer IDs while gathering the source identities required by baking and assembly.
14648
+ parsed = parseSVGToIRWithPreservedData(staticSource, _extends({}, conversionOptions, {
14649
+ strict: false,
14650
+ onWarning: undefined
14651
+ }), _extends({}, collected, {
14652
+ layerSourceCollector: layerSources,
14653
+ warningSourceCollector: warningSources
14654
+ }));
14655
+ context = {
14656
+ source: staticSource,
14657
+ ir: parsed.ir,
14658
+ warnings: parsed.warnings,
14659
+ preservedData: preservedData != null ? preservedData : collected,
14660
+ layerSources: layerSources,
14661
+ warningSources: warningSources
13457
14662
  };
14663
+ if (stripped.removed > 0) {
14664
+ collectLayerWarning(context.warnings, _extends({}, conversionOptions, {
14665
+ strict: false,
14666
+ onWarning: undefined
14667
+ }), SVG2IR_WARNING_CODES.LAYERS_ANIMATION_STRIPPED, "" + stripped.removed + " animated element(s) were removed; static layers output does not sample animation.");
14668
+ }
14669
+ composition = context.ir.compositions[0];
13458
14670
  return [
13459
14671
  4,
13460
- inlineImageResources(data, loadImage)
14672
+ buildBakedLayers(context.source, [
14673
+ composition.width,
14674
+ composition.height
14675
+ ], conversionOptions, rasterScale)
13461
14676
  ];
13462
14677
  case 1:
14678
+ baking = _state.sent();
14679
+ assembled = assembleSVGLayers({
14680
+ context: context,
14681
+ options: conversionOptions,
14682
+ baking: baking
14683
+ });
14684
+ _tmp = [
14685
+ {},
14686
+ assembled
14687
+ ];
14688
+ _tmp1 = {};
14689
+ return [
14690
+ 4,
14691
+ inlineImageResources(assembled.data, loadImage)
14692
+ ];
14693
+ case 2:
13463
14694
  return [
13464
14695
  2,
13465
- (_tmp.data = _state.sent(), _tmp.warnings = parsed.warnings, _tmp)
14696
+ _extends.apply(void 0, _tmp.concat([
14697
+ (_tmp1.data = _state.sent(), _tmp1)
14698
+ ]))
13466
14699
  ];
13467
14700
  }
13468
14701
  });
13469
- })();
14702
+ }).apply(this, arguments);
13470
14703
  }
13471
14704
 
13472
14705
  /**
@@ -13491,7 +14724,8 @@ function convertSVGToLayers(source, options, loadImage, preservedData) {
13491
14724
  JSONSceneVersion["3_4"] = "3.4";
13492
14725
  JSONSceneVersion["3_5"] = "3.5";
13493
14726
  JSONSceneVersion["3_6"] = "3.6";
13494
- JSONSceneVersion["LATEST"] = "3.6";
14727
+ JSONSceneVersion["3_7"] = "3.7";
14728
+ JSONSceneVersion["LATEST"] = "3.7";
13495
14729
  })(JSONSceneVersion || (JSONSceneVersion = {}));
13496
14730
 
13497
14731
  /*********************************************/ /* 元素属性参数类型 */ /*********************************************/ /**
@@ -13806,10 +15040,12 @@ var CameraClipMode;
13806
15040
  * 直线
13807
15041
  */ ValueType[ValueType["LINE"] = 5] = "LINE";
13808
15042
  /**
13809
- * 曲线
15043
+ * 曲线(Hermite 曲线)
15044
+ * @deprecated 使用 BEZIER_CURVE 替代,此类型仅用于旧数据迁移兼容
13810
15045
  */ ValueType[ValueType["CURVE"] = 6] = "CURVE";
13811
15046
  /**
13812
15047
  * 贝塞尔路径
15048
+ * @deprecated 使用 BEZIER_CURVE_PATH 替代,此类型仅用于旧数据迁移兼容
13813
15049
  */ ValueType[ValueType["BEZIER_PATH"] = 7] = "BEZIER_PATH";
13814
15050
  /**
13815
15051
  * 颜色
@@ -14246,6 +15482,7 @@ var DataType;
14246
15482
  DataType["AnimationGraphAsset"] = "AnimationGraphAsset";
14247
15483
  DataType["CompositionComponent"] = "CompositionComponent";
14248
15484
  DataType["FFDComponent"] = "FFDComponent";
15485
+ DataType["FrameComponent"] = "FrameComponent";
14249
15486
  DataType["Animator"] = "Animator";
14250
15487
  // Non-EffectObject
14251
15488
  DataType["TimelineClip"] = "TimelineClip";
@@ -15870,7 +17107,8 @@ function asRecordArray(value) {
15870
17107
  }
15871
17108
 
15872
17109
  /** 从已解析的 IR 和 SVG 保留数据生成 GE 场景。 */ function assembleSVGGE(parsed, options, preservedData) {
15873
- var ir = parsed.ir, warnings = parsed.warnings;
17110
+ var ir = parsed.ir;
17111
+ var warnings = [].concat(parsed.warnings);
15874
17112
  var fonts = (options != null ? options : {}).fonts;
15875
17113
  var irForGE = expandIRHoldTransitions(ir);
15876
17114
  if ((preservedData == null ? void 0 : preservedData.shapeAnimationsByLayerId) != null) {
@@ -15978,31 +17216,13 @@ function cleanFontName(raw) {
15978
17216
  return value;
15979
17217
  }
15980
17218
 
15981
- /** SVG→GE 显式入口。传入 preservedData 时应用 SVG 专属后处理。 */ function convertSVGToGE(source, options, preservedData) {
17219
+ function convertSVGToGE(sourceOrContext, options, preservedData) {
15982
17220
  var _ref = options != null ? options : {}; _ref.fonts; var parserOptions = _object_without_properties_loose(_ref, [
15983
17221
  "fonts"
15984
17222
  ]);
15985
- var parsed = parseSVGToIRWithPreservedData(source, parserOptions);
15986
- return assembleSVGGE(parsed, options, preservedData);
15987
- }
15988
-
15989
- function convertSVG(source, options, preservedData) {
15990
- var _ref = options != null ? options : {}, _ref_outputFormat = _ref.outputFormat, outputFormat = _ref_outputFormat === void 0 ? 'ge' : _ref_outputFormat;
15991
- if (outputFormat !== 'ge' && outputFormat !== 'layers') {
15992
- throw new TypeError('[svg2ir] outputFormat must be ge or layers.');
15993
- }
15994
- if ((options == null ? void 0 : options.outputFormat) === 'layers') {
15995
- options.outputFormat; var loadImage = options.loadImage, parserOptions = _object_without_properties_loose(options, [
15996
- "outputFormat",
15997
- "loadImage"
15998
- ]);
15999
- return convertSVGToLayers(source, parserOptions, loadImage, preservedData);
16000
- }
16001
- var _ref1 = options != null ? options : {}; _ref1.outputFormat; var geOptions = _object_without_properties_loose(_ref1, [
16002
- "outputFormat"
16003
- ]);
16004
- return convertSVGToGE(source, geOptions, preservedData);
17223
+ var context = typeof sourceOrContext === 'string' ? parseSVGToIRWithPreservedData(sourceOrContext, parserOptions) : sourceOrContext;
17224
+ return assembleSVGGE(context, options, preservedData != null ? preservedData : typeof sourceOrContext === 'string' ? undefined : sourceOrContext.preservedData);
16005
17225
  }
16006
17226
 
16007
- export { convertSVG, convertSVGToGE, convertSVGToIR, splitSVG };
17227
+ export { convertSVGToGE, convertSVGToIR, convertSVGToLayers, inferNumericWeightFromFamily, splitSVG };
16008
17228
  //# sourceMappingURL=index.mjs.map