@emasoft/svg-matrix 1.0.28 → 1.0.30
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.
- package/README.md +325 -0
- package/bin/svg-matrix.js +985 -378
- package/bin/svglinter.cjs +4172 -433
- package/bin/svgm.js +723 -180
- package/package.json +16 -4
- package/src/animation-references.js +71 -52
- package/src/arc-length.js +160 -96
- package/src/bezier-analysis.js +257 -117
- package/src/bezier-intersections.js +411 -148
- package/src/browser-verify.js +240 -100
- package/src/clip-path-resolver.js +350 -142
- package/src/convert-path-data.js +279 -134
- package/src/css-specificity.js +78 -70
- package/src/flatten-pipeline.js +751 -263
- package/src/geometry-to-path.js +511 -182
- package/src/index.js +191 -46
- package/src/inkscape-support.js +18 -7
- package/src/marker-resolver.js +278 -164
- package/src/mask-resolver.js +209 -98
- package/src/matrix.js +147 -67
- package/src/mesh-gradient.js +187 -96
- package/src/off-canvas-detection.js +201 -104
- package/src/path-analysis.js +187 -107
- package/src/path-data-plugins.js +628 -167
- package/src/path-simplification.js +0 -1
- package/src/pattern-resolver.js +125 -88
- package/src/polygon-clip.js +111 -66
- package/src/svg-boolean-ops.js +194 -118
- package/src/svg-collections.js +22 -18
- package/src/svg-flatten.js +282 -164
- package/src/svg-parser.js +427 -200
- package/src/svg-rendering-context.js +147 -104
- package/src/svg-toolbox.js +16381 -3370
- package/src/svg2-polyfills.js +93 -224
- package/src/transform-decomposition.js +46 -41
- package/src/transform-optimization.js +89 -68
- package/src/transforms2d.js +49 -16
- package/src/transforms3d.js +58 -22
- package/src/use-symbol-resolver.js +150 -110
- package/src/vector.js +67 -15
- package/src/vendor/README.md +110 -0
- package/src/vendor/inkscape-hatch-polyfill.js +401 -0
- package/src/vendor/inkscape-hatch-polyfill.min.js +8 -0
- package/src/vendor/inkscape-mesh-polyfill.js +843 -0
- package/src/vendor/inkscape-mesh-polyfill.min.js +8 -0
- package/src/verification.js +288 -124
package/src/index.js
CHANGED
|
@@ -5,13 +5,19 @@
|
|
|
5
5
|
* SVG path conversion, and 2D/3D affine transformations using Decimal.js.
|
|
6
6
|
*
|
|
7
7
|
* @module @emasoft/svg-matrix
|
|
8
|
-
* @version 1.0.
|
|
8
|
+
* @version 1.0.30
|
|
9
9
|
* @license MIT
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
|
-
* // ES Module import
|
|
12
|
+
* // ES Module import - Core functionality
|
|
13
13
|
* import { Decimal, Matrix, Vector, Transforms2D, GeometryToPath } from '@emasoft/svg-matrix';
|
|
14
14
|
*
|
|
15
|
+
* // SVG2 Polyfills - Detect and inject polyfills for mesh gradients and hatches
|
|
16
|
+
* import { detectSVG2Features, injectPolyfills } from '@emasoft/svg-matrix';
|
|
17
|
+
*
|
|
18
|
+
* // Inkscape Support - Extract layers and preserve Inkscape metadata
|
|
19
|
+
* import { findLayers, extractLayer, extractAllLayers } from '@emasoft/svg-matrix';
|
|
20
|
+
*
|
|
15
21
|
* // Precision is already set to 80 by default (max is 1e9)
|
|
16
22
|
* // You can increase it further if needed:
|
|
17
23
|
* // Decimal.set({ precision: 200 });
|
|
@@ -28,55 +34,97 @@
|
|
|
28
34
|
* const path = GeometryToPath.circleToPathData(100, 100, 50, 15);
|
|
29
35
|
*/
|
|
30
36
|
|
|
31
|
-
import Decimal from
|
|
32
|
-
import { Matrix } from
|
|
33
|
-
import { Vector } from
|
|
34
|
-
import * as Transforms2D from
|
|
35
|
-
import * as Transforms3D from
|
|
36
|
-
import * as GeometryToPath from
|
|
37
|
-
import * as PolygonClip from
|
|
38
|
-
import * as SVGFlatten from
|
|
39
|
-
import * as BrowserVerify from
|
|
40
|
-
import * as ClipPathResolver from
|
|
41
|
-
import * as MaskResolver from
|
|
42
|
-
import * as PatternResolver from
|
|
43
|
-
import * as UseSymbolResolver from
|
|
44
|
-
import * as MarkerResolver from
|
|
45
|
-
import * as MeshGradient from
|
|
46
|
-
import * as SVGParser from
|
|
47
|
-
import * as FlattenPipeline from
|
|
48
|
-
import * as Verification from
|
|
49
|
-
import * as InkscapeSupport from
|
|
50
|
-
import
|
|
51
|
-
|
|
37
|
+
import Decimal from "decimal.js";
|
|
38
|
+
import { Matrix } from "./matrix.js";
|
|
39
|
+
import { Vector } from "./vector.js";
|
|
40
|
+
import * as Transforms2D from "./transforms2d.js";
|
|
41
|
+
import * as Transforms3D from "./transforms3d.js";
|
|
42
|
+
import * as GeometryToPath from "./geometry-to-path.js";
|
|
43
|
+
import * as PolygonClip from "./polygon-clip.js";
|
|
44
|
+
import * as SVGFlatten from "./svg-flatten.js";
|
|
45
|
+
import * as BrowserVerify from "./browser-verify.js";
|
|
46
|
+
import * as ClipPathResolver from "./clip-path-resolver.js";
|
|
47
|
+
import * as MaskResolver from "./mask-resolver.js";
|
|
48
|
+
import * as PatternResolver from "./pattern-resolver.js";
|
|
49
|
+
import * as UseSymbolResolver from "./use-symbol-resolver.js";
|
|
50
|
+
import * as MarkerResolver from "./marker-resolver.js";
|
|
51
|
+
import * as MeshGradient from "./mesh-gradient.js";
|
|
52
|
+
import * as SVGParser from "./svg-parser.js";
|
|
53
|
+
import * as FlattenPipeline from "./flatten-pipeline.js";
|
|
54
|
+
import * as Verification from "./verification.js";
|
|
55
|
+
import * as InkscapeSupport from "./inkscape-support.js";
|
|
56
|
+
import {
|
|
57
|
+
INKSCAPE_NS,
|
|
58
|
+
SODIPODI_NS,
|
|
59
|
+
INKSCAPE_PREFIXES,
|
|
60
|
+
isInkscapeLayer,
|
|
61
|
+
getLayerLabel,
|
|
62
|
+
findLayers,
|
|
63
|
+
getNamedViewSettings,
|
|
64
|
+
findGuides,
|
|
65
|
+
getArcParameters,
|
|
66
|
+
getNodeTypes,
|
|
67
|
+
getExportSettings,
|
|
68
|
+
isTiledClone,
|
|
69
|
+
getTiledCloneSource,
|
|
70
|
+
hasInkscapeNamespaces,
|
|
71
|
+
ensureInkscapeNamespaces,
|
|
72
|
+
findReferencedIds,
|
|
73
|
+
buildDefsMapFromDefs,
|
|
74
|
+
resolveDefsDependencies,
|
|
75
|
+
cloneElement,
|
|
76
|
+
extractLayer,
|
|
77
|
+
extractAllLayers,
|
|
78
|
+
analyzeLayerDependencies,
|
|
79
|
+
} from "./inkscape-support.js";
|
|
80
|
+
|
|
81
|
+
import * as SVG2Polyfills from "./svg2-polyfills.js";
|
|
82
|
+
import {
|
|
83
|
+
setPolyfillMinification,
|
|
84
|
+
SVG2_FEATURES,
|
|
85
|
+
detectSVG2Features,
|
|
86
|
+
needsPolyfills,
|
|
87
|
+
generatePolyfillScript,
|
|
88
|
+
injectPolyfills,
|
|
89
|
+
removePolyfills,
|
|
90
|
+
} from "./svg2-polyfills.js";
|
|
91
|
+
|
|
92
|
+
import {
|
|
93
|
+
Logger,
|
|
94
|
+
LogLevel,
|
|
95
|
+
setLogLevel,
|
|
96
|
+
getLogLevel as _getLoggerLevel,
|
|
97
|
+
enableFileLogging,
|
|
98
|
+
disableFileLogging,
|
|
99
|
+
} from "./logger.js";
|
|
52
100
|
|
|
53
101
|
// SVGO-inspired precision modules
|
|
54
|
-
import * as PathSimplification from
|
|
55
|
-
import * as TransformDecomposition from
|
|
56
|
-
import * as GJKCollision from
|
|
57
|
-
import * as PathOptimization from
|
|
58
|
-
import * as TransformOptimization from
|
|
59
|
-
import * as OffCanvasDetection from
|
|
60
|
-
import * as CSSSpecificity from
|
|
102
|
+
import * as PathSimplification from "./path-simplification.js";
|
|
103
|
+
import * as TransformDecomposition from "./transform-decomposition.js";
|
|
104
|
+
import * as GJKCollision from "./gjk-collision.js";
|
|
105
|
+
import * as PathOptimization from "./path-optimization.js";
|
|
106
|
+
import * as TransformOptimization from "./transform-optimization.js";
|
|
107
|
+
import * as OffCanvasDetection from "./off-canvas-detection.js";
|
|
108
|
+
import * as CSSSpecificity from "./css-specificity.js";
|
|
61
109
|
|
|
62
110
|
// Animation-aware reference tracking (FIXES SVGO's animation destruction bug)
|
|
63
|
-
import * as AnimationReferences from
|
|
111
|
+
import * as AnimationReferences from "./animation-references.js";
|
|
64
112
|
|
|
65
113
|
// SVG Toolbox - SVGO-equivalent functions with simple API
|
|
66
|
-
import * as SVGToolbox from
|
|
114
|
+
import * as SVGToolbox from "./svg-toolbox.js";
|
|
67
115
|
|
|
68
116
|
// Bezier Curve Analysis - svgpathtools-equivalent with 80-digit arbitrary precision
|
|
69
117
|
// These modules provide superior precision compared to Python's float64 svgpathtools
|
|
70
|
-
import * as BezierAnalysis from
|
|
71
|
-
import * as ArcLength from
|
|
72
|
-
import * as PathAnalysis from
|
|
73
|
-
import * as BezierIntersections from
|
|
118
|
+
import * as BezierAnalysis from "./bezier-analysis.js";
|
|
119
|
+
import * as ArcLength from "./arc-length.js";
|
|
120
|
+
import * as PathAnalysis from "./path-analysis.js";
|
|
121
|
+
import * as BezierIntersections from "./bezier-intersections.js";
|
|
74
122
|
|
|
75
123
|
// SVG Boolean Operations - fill-rule and stroke-aware geometric operations
|
|
76
|
-
import * as SVGBooleanOps from
|
|
124
|
+
import * as SVGBooleanOps from "./svg-boolean-ops.js";
|
|
77
125
|
|
|
78
126
|
// SVG Rendering Context - tracks ALL SVG properties affecting rendered geometry
|
|
79
|
-
import * as SVGRenderingContext from
|
|
127
|
+
import * as SVGRenderingContext from "./svg-rendering-context.js";
|
|
80
128
|
|
|
81
129
|
// Set high-precision default (80 significant digits) on module load
|
|
82
130
|
// This is the same precision used internally by all svg-matrix modules
|
|
@@ -87,7 +135,7 @@ Decimal.set({ precision: 80 });
|
|
|
87
135
|
* Library version
|
|
88
136
|
* @constant {string}
|
|
89
137
|
*/
|
|
90
|
-
export const VERSION = '1.0.
|
|
138
|
+
export const VERSION = '1.0.30';
|
|
91
139
|
|
|
92
140
|
/**
|
|
93
141
|
* Default precision for path output (decimal places)
|
|
@@ -223,8 +271,8 @@ export {
|
|
|
223
271
|
removeAttrs,
|
|
224
272
|
removeElementsByAttr,
|
|
225
273
|
// Presets
|
|
226
|
-
|
|
227
|
-
|
|
274
|
+
presetDefault,
|
|
275
|
+
presetNone,
|
|
228
276
|
applyPreset,
|
|
229
277
|
optimize,
|
|
230
278
|
createConfig,
|
|
@@ -238,14 +286,55 @@ export {
|
|
|
238
286
|
imageToPath,
|
|
239
287
|
detectCollisions,
|
|
240
288
|
measureDistance,
|
|
289
|
+
validateXML,
|
|
241
290
|
validateSVG,
|
|
242
|
-
|
|
243
|
-
fixInvalidSvg,
|
|
291
|
+
fixInvalidSVG,
|
|
244
292
|
ValidationSeverity,
|
|
245
293
|
flattenAll,
|
|
246
294
|
simplifyPath,
|
|
295
|
+
optimizeAnimationTiming,
|
|
296
|
+
optimizePaths,
|
|
297
|
+
simplifyPaths,
|
|
247
298
|
decomposeTransform,
|
|
248
|
-
|
|
299
|
+
embedExternalDependencies,
|
|
300
|
+
} from "./svg-toolbox.js";
|
|
301
|
+
|
|
302
|
+
// Re-export all svg2-polyfills functions for direct access
|
|
303
|
+
export {
|
|
304
|
+
setPolyfillMinification,
|
|
305
|
+
SVG2_FEATURES,
|
|
306
|
+
detectSVG2Features,
|
|
307
|
+
needsPolyfills,
|
|
308
|
+
generatePolyfillScript,
|
|
309
|
+
injectPolyfills,
|
|
310
|
+
removePolyfills,
|
|
311
|
+
} from "./svg2-polyfills.js";
|
|
312
|
+
|
|
313
|
+
// Re-export all inkscape-support functions for direct access
|
|
314
|
+
export {
|
|
315
|
+
INKSCAPE_NS,
|
|
316
|
+
SODIPODI_NS,
|
|
317
|
+
INKSCAPE_PREFIXES,
|
|
318
|
+
isInkscapeLayer,
|
|
319
|
+
getLayerLabel,
|
|
320
|
+
findLayers,
|
|
321
|
+
getNamedViewSettings,
|
|
322
|
+
findGuides,
|
|
323
|
+
getArcParameters,
|
|
324
|
+
getNodeTypes,
|
|
325
|
+
getExportSettings,
|
|
326
|
+
isTiledClone,
|
|
327
|
+
getTiledCloneSource,
|
|
328
|
+
hasInkscapeNamespaces,
|
|
329
|
+
ensureInkscapeNamespaces,
|
|
330
|
+
findReferencedIds,
|
|
331
|
+
buildDefsMapFromDefs,
|
|
332
|
+
resolveDefsDependencies,
|
|
333
|
+
cloneElement,
|
|
334
|
+
extractLayer,
|
|
335
|
+
extractAllLayers,
|
|
336
|
+
analyzeLayerDependencies,
|
|
337
|
+
} from "./inkscape-support.js";
|
|
249
338
|
|
|
250
339
|
// ============================================================================
|
|
251
340
|
// LOGGING: Configurable logging control
|
|
@@ -375,8 +464,25 @@ export function ellipseToPath(cx, cy, rx, ry, precision = DEFAULT_PRECISION) {
|
|
|
375
464
|
* @param {number} [precision=6] - Number of decimal places in output
|
|
376
465
|
* @returns {string} SVG path data string
|
|
377
466
|
*/
|
|
378
|
-
export function rectToPath(
|
|
379
|
-
|
|
467
|
+
export function rectToPath(
|
|
468
|
+
x,
|
|
469
|
+
y,
|
|
470
|
+
width,
|
|
471
|
+
height,
|
|
472
|
+
rx = 0,
|
|
473
|
+
ry = null,
|
|
474
|
+
precision = DEFAULT_PRECISION,
|
|
475
|
+
) {
|
|
476
|
+
return GeometryToPath.rectToPathData(
|
|
477
|
+
x,
|
|
478
|
+
y,
|
|
479
|
+
width,
|
|
480
|
+
height,
|
|
481
|
+
rx,
|
|
482
|
+
ry,
|
|
483
|
+
false,
|
|
484
|
+
precision,
|
|
485
|
+
);
|
|
380
486
|
}
|
|
381
487
|
|
|
382
488
|
/**
|
|
@@ -583,6 +689,39 @@ export default {
|
|
|
583
689
|
InkscapeSupport,
|
|
584
690
|
SVG2Polyfills,
|
|
585
691
|
|
|
692
|
+
// SVG2 Polyfills - individual exports
|
|
693
|
+
setPolyfillMinification,
|
|
694
|
+
SVG2_FEATURES,
|
|
695
|
+
detectSVG2Features,
|
|
696
|
+
needsPolyfills,
|
|
697
|
+
generatePolyfillScript,
|
|
698
|
+
injectPolyfills,
|
|
699
|
+
removePolyfills,
|
|
700
|
+
|
|
701
|
+
// Inkscape Support - individual exports
|
|
702
|
+
INKSCAPE_NS,
|
|
703
|
+
SODIPODI_NS,
|
|
704
|
+
INKSCAPE_PREFIXES,
|
|
705
|
+
isInkscapeLayer,
|
|
706
|
+
getLayerLabel,
|
|
707
|
+
findLayers,
|
|
708
|
+
getNamedViewSettings,
|
|
709
|
+
findGuides,
|
|
710
|
+
getArcParameters,
|
|
711
|
+
getNodeTypes,
|
|
712
|
+
getExportSettings,
|
|
713
|
+
isTiledClone,
|
|
714
|
+
getTiledCloneSource,
|
|
715
|
+
hasInkscapeNamespaces,
|
|
716
|
+
ensureInkscapeNamespaces,
|
|
717
|
+
findReferencedIds,
|
|
718
|
+
buildDefsMapFromDefs,
|
|
719
|
+
resolveDefsDependencies,
|
|
720
|
+
cloneElement,
|
|
721
|
+
extractLayer,
|
|
722
|
+
extractAllLayers,
|
|
723
|
+
analyzeLayerDependencies,
|
|
724
|
+
|
|
586
725
|
// Logging
|
|
587
726
|
Logger,
|
|
588
727
|
LogLevel,
|
|
@@ -611,6 +750,12 @@ export default {
|
|
|
611
750
|
PathAnalysis,
|
|
612
751
|
BezierIntersections,
|
|
613
752
|
|
|
753
|
+
// SVG Boolean Operations (fill-rule and stroke-aware)
|
|
754
|
+
SVGBooleanOps,
|
|
755
|
+
|
|
756
|
+
// SVG Rendering Context (tracks all SVG properties affecting geometry)
|
|
757
|
+
SVGRenderingContext,
|
|
758
|
+
|
|
614
759
|
// Convenience functions
|
|
615
760
|
translate2D,
|
|
616
761
|
rotate2D,
|
package/src/inkscape-support.js
CHANGED
|
@@ -25,6 +25,8 @@ export const INKSCAPE_PREFIXES = ['inkscape', 'sodipodi'];
|
|
|
25
25
|
*/
|
|
26
26
|
export function isInkscapeLayer(element) {
|
|
27
27
|
if (!element || element.tagName !== 'g') return false;
|
|
28
|
+
// Safety check: ensure getAttribute method exists before calling it
|
|
29
|
+
if (typeof element.getAttribute !== 'function') return false;
|
|
28
30
|
return element.getAttribute('inkscape:groupmode') === 'layer';
|
|
29
31
|
}
|
|
30
32
|
|
|
@@ -223,7 +225,9 @@ export function getTiledCloneSource(element) {
|
|
|
223
225
|
* @returns {boolean} True if Inkscape namespaces are present
|
|
224
226
|
*/
|
|
225
227
|
export function hasInkscapeNamespaces(doc) {
|
|
228
|
+
if (!doc) return false;
|
|
226
229
|
const svg = doc.documentElement || doc;
|
|
230
|
+
if (!svg || typeof svg.getAttribute !== 'function') return false;
|
|
227
231
|
const hasInkscape = svg.getAttribute('xmlns:inkscape') === INKSCAPE_NS;
|
|
228
232
|
const hasSodipodi = svg.getAttribute('xmlns:sodipodi') === SODIPODI_NS;
|
|
229
233
|
return hasInkscape || hasSodipodi;
|
|
@@ -239,6 +243,11 @@ export function hasInkscapeNamespaces(doc) {
|
|
|
239
243
|
export function ensureInkscapeNamespaces(doc) {
|
|
240
244
|
const svg = doc.documentElement || doc;
|
|
241
245
|
|
|
246
|
+
// Safety check: ensure getAttribute and setAttribute methods exist
|
|
247
|
+
if (typeof svg.getAttribute !== 'function' || typeof svg.setAttribute !== 'function') {
|
|
248
|
+
return doc;
|
|
249
|
+
}
|
|
250
|
+
|
|
242
251
|
if (!svg.getAttribute('xmlns:inkscape')) {
|
|
243
252
|
svg.setAttribute('xmlns:inkscape', INKSCAPE_NS);
|
|
244
253
|
}
|
|
@@ -332,7 +341,7 @@ export function findReferencedIds(element) {
|
|
|
332
341
|
* @param {Object} doc - Parsed SVG document
|
|
333
342
|
* @returns {Map<string, Object>} Map of ID to element
|
|
334
343
|
*/
|
|
335
|
-
export function
|
|
344
|
+
export function buildDefsMapFromDefs(doc) {
|
|
336
345
|
const defsMap = new Map();
|
|
337
346
|
|
|
338
347
|
const walk = (el) => {
|
|
@@ -462,8 +471,8 @@ export function extractLayer(doc, layerOrId, options = {}) {
|
|
|
462
471
|
if (typeof layerOrId === 'string') {
|
|
463
472
|
const layers = findLayers(doc);
|
|
464
473
|
const found = layers.find(l => l.id === layerOrId || l.label === layerOrId);
|
|
465
|
-
if (!found) {
|
|
466
|
-
throw new Error(`Layer not found: ${layerOrId}`);
|
|
474
|
+
if (!found || !found.element) {
|
|
475
|
+
throw new Error(`Layer not found or invalid: ${layerOrId}`);
|
|
467
476
|
}
|
|
468
477
|
layer = found.element;
|
|
469
478
|
} else {
|
|
@@ -478,7 +487,7 @@ export function extractLayer(doc, layerOrId, options = {}) {
|
|
|
478
487
|
const svgRoot = doc.documentElement || doc;
|
|
479
488
|
|
|
480
489
|
// Build defs map from source document
|
|
481
|
-
const defsMap =
|
|
490
|
+
const defsMap = buildDefsMapFromDefs(doc);
|
|
482
491
|
|
|
483
492
|
// Find all IDs referenced by this layer
|
|
484
493
|
const referencedIds = findReferencedIds(layer);
|
|
@@ -508,8 +517,10 @@ export function extractLayer(doc, layerOrId, options = {}) {
|
|
|
508
517
|
defsChildren.push(cloneElement(defElement));
|
|
509
518
|
}
|
|
510
519
|
}
|
|
511
|
-
|
|
512
|
-
|
|
520
|
+
if (defsChildren.length > 0) {
|
|
521
|
+
const newDefs = new SVGElement('defs', {}, defsChildren, null);
|
|
522
|
+
svgChildren.push(newDefs);
|
|
523
|
+
}
|
|
513
524
|
}
|
|
514
525
|
|
|
515
526
|
// Clone the layer
|
|
@@ -586,7 +597,7 @@ export function extractAllLayers(doc, options = {}) {
|
|
|
586
597
|
*/
|
|
587
598
|
export function analyzeLayerDependencies(doc) {
|
|
588
599
|
const layers = findLayers(doc);
|
|
589
|
-
const defsMap =
|
|
600
|
+
const defsMap = buildDefsMapFromDefs(doc);
|
|
590
601
|
const layerRefs = new Map(); // layer ID -> Set of referenced def IDs
|
|
591
602
|
const defUsage = new Map(); // def ID -> Set of layer IDs that use it
|
|
592
603
|
|