Socket
Socket
Sign inDemoInstall

svgo

Package Overview
Dependencies
11
Maintainers
2
Versions
102
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.5.1 to 0.5.2

plugins/addClassesToSVGElement.js

12

CHANGELOG.md

@@ -0,1 +1,13 @@

### [ [>](https://github.com/svg/svgo/tree/v0.5.2) ] 0.5.2 / 24.05.2015
* Introduced new `transformPrecision` option for better image quality (defaults to 5) in “[convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js)” and “[convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js)” (for the purpose of applying transformations) plugins.
* Matrix transformations now can be decomposed into a combination of few simple transforms like `translate`, `rotate`, `scale`.
* Arcs (paths `arcto` command) are now correctly being transformed into another arcs without being converting to Bezier curves.
* Fixed an issue with “[mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js)” failing to detect paths intersection in some cases.
* Fixed a bug with “[removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js)” removing some paths, which was introduced in [v0.5.1](https://github.com/svg/svgo/tree/v0.5.1).
* Fixed a bug with transformation having `rotate()` with optional parameters.
* Patterns with inherited attributes are no longer being removed.
* Styles are no longer being removed from `<desc>` (by @dennari).
* SVGO no longer breaks during parsing.
* Added `clone()` method to JSAPI (by @jakearchibald)
### [ [>](https://github.com/svg/svgo/tree/v0.5.1) ] 0.5.1 / 30.03.2015

@@ -2,0 +14,0 @@ * added new command-line option to set precision in floating point numbers.

35

lib/svgo/jsAPI.js

@@ -6,3 +6,2 @@ 'use strict';

var JSAPI = module.exports = function(data, parentNode) {
EXTEND(this, data);

@@ -15,3 +14,37 @@ if (parentNode) {

}
};
/**
* Perform a deep clone of this node.
*
* @return {Object} element
*/
JSAPI.prototype.clone = function() {
var node = this;
var nodeData = {};
Object.keys(node).forEach(function(key) {
if (key != 'content') {
nodeData[key] = node[key];
}
});
// Deep-clone node data
// This is still faster than using EXTEND(true…)
nodeData = JSON.parse(JSON.stringify(nodeData));
// parentNode gets set to a proper object by the parent clone,
// but it needs to be true/false now to do the right thing
// in the constructor.
var clonedNode = new JSAPI(nodeData, !!node.parentNode);
if (node.content) {
clonedNode.content = node.content.map(function(childNode) {
var clonedChild = childNode.clone();
clonedChild.parentNode = clonedNode;
return clonedChild;
});
}
return clonedNode;
};

@@ -18,0 +51,0 @@

10

lib/svgo/svg2js.js

@@ -140,3 +140,3 @@ 'use strict';

callback(root);
if (!this.error) callback(root);

@@ -153,7 +153,7 @@ };

while (start && !start.text) start = start.content[0];
if (start) start.text = start.text.replace(/^\s+/, '');
while (start && start.content && !start.text) start = start.content[0];
if (start && start.text) start.text = start.text.replace(/^\s+/, '');
while (end && !end.text) end = end.content[end.content.length - 1];
if (end) end.text = end.text.replace(/\s+$/, '');
while (end && end.content && !end.text) end = end.content[end.content.length - 1];
if (end && end.text) end.text = end.text.replace(/\s+$/, '');

@@ -160,0 +160,0 @@ return elem;

{
"name": "svgo",
"version": "0.5.1",
"version": "0.5.2",
"description": "Nodejs-based tool for optimizing SVG vector graphics files",

@@ -42,13 +42,13 @@ "keywords": [ "svgo", "svg", "optimize", "minify" ],

"dependencies": {
"sax": "~0.6.1",
"sax": "~1.1.1",
"coa": "~1.0.1",
"js-yaml": "~3.2.3",
"colors": "~1.0.3",
"js-yaml": "~3.3.1",
"colors": "~1.1.0",
"whet.extend": "~0.9.9",
"mkdirp": "~0.5.0"
"mkdirp": "~0.5.1"
},
"devDependencies": {
"mocha": "~2.2.1",
"should": "~5.2.0",
"istanbul": "~0.3.11",
"mocha": "~2.2.5",
"should": "6.0.3",
"istanbul": "~0.3.14",
"mocha-istanbul": "~0.2.0",

@@ -60,6 +60,3 @@ "coveralls": "~2.11.2"

},
"licenses": [{
"type": "MIT",
"url": "https://raw.github.com/svg/svgo/master/LICENSE"
}]
"license": "MIT"
}

@@ -8,2 +8,3 @@ 'use strict';

transformsMultiply = require('./_transforms').transformsMultiply,
transformArc = require('./_transforms').transformArc,
collections = require('./_collections.js'),

@@ -171,7 +172,6 @@ referencesProps = collections.referencesProps,

* @param {Array} path input path data
* @param {Boolean} applyTransformsStroked whether to apply transforms to stroked lines.
* @param {Number} floatPrecision precision (used for stroke width)
* @param {Object} params whether to apply transforms to stroked lines and transform precision (used for stroke width)
* @return {Array} output path data
*/
exports.applyTransforms = function(elem, path, applyTransformsStroked, floatPrecision) {
exports.applyTransforms = function(elem, path, params) {
// if there are no 'stroke' attr and references to other objects such as

@@ -186,64 +186,29 @@ // gradiends or clip-path which are also subjects to transform.

var matrix = transformsMultiply(transform2js(elem.attr('transform').value)),
splittedMatrix = matrix.splitted || splitMatrix(matrix.data),
stroke = elem.computedAttr('stroke'),
newPoint, sx, sy;
transformPrecision = params.transformPrecision,
newPoint, scale;
if (stroke && stroke.value != 'none'){
if (!applyTransformsStroked){
return path;
}
if (matrix.name == 'matrix'){
sx = +Math.sqrt(matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]).toFixed(floatPrecision);
sy = +Math.sqrt(matrix.data[2] * matrix.data[2] + matrix.data[3] * matrix.data[3]).toFixed(floatPrecision);
} else if (matrix.name == 'scale'){
sx = +matrix.data[0].toFixed(floatPrecision);
sy = +matrix.data[1].toFixed(floatPrecision);
} else {
sx = 1;
sy = 1;
}
if (stroke && stroke.value != 'none') {
if (!params.applyTransformsStroked ||
(matrix.data[0] != matrix.data[3] || matrix.data[1] != -matrix.data[2]) &&
(matrix.data[0] != -matrix.data[3] || matrix.data[1] != matrix.data[2]))
return path;
if (sx !== sy){
return path;
}
if (sx !== 1){
var strokeWidth = elem.computedAttr('stroke-width') || defaultStrokeWidth;
scale = +Math.sqrt(matrix.data[0] * matrix.data[0] + matrix.data[1] * matrix.data[1]).toFixed(transformPrecision);
if (elem.hasAttr('stroke-width')){
elem.attrs['stroke-width'].value = elem.attrs['stroke-width'].value.trim()
.replace(regNumericValues, function(num) { return removeLeadingZero(num * sx) });
} else {
elem.addAttr({
name: 'stroke-width',
prefix: '',
local: 'stroke-width',
value: strokeWidth.replace(regNumericValues, function(num) { return removeLeadingZero(num * sx) })
});
}
}
}
if (scale !== 1) {
var strokeWidth = elem.computedAttr('stroke-width') || defaultStrokeWidth;
// If an 'a' command can't be transformed directly, convert path to curves.
if (!splittedMatrix.isSimple && path.some(function(i) { return i.instruction == 'a' })) {
var prev;
path.forEach(function(item, index, path){
if (item.instruction == 'a') {
var curves = a2c.apply(0, [0, 0].concat(item.data)),
items = [],
curveData;
while ((curveData = curves.splice(0,6)).length) {
var base = prev.coords;
items.push(prev = {
instruction: 'c',
data: curveData,
coords: [base[0] + item.data[4], base[1] + item.data[5]],
base: prev.coords
});
}
path.splice.apply(path, [index, 1].concat(items));
if (elem.hasAttr('stroke-width')) {
elem.attrs['stroke-width'].value = elem.attrs['stroke-width'].value.trim()
.replace(regNumericValues, function(num) { return removeLeadingZero(num * scale) });
} else {
if (prev) item.base = prev.coords;
prev = item;
elem.addAttr({
name: 'stroke-width',
prefix: '',
local: 'stroke-width',
value: strokeWidth.replace(regNumericValues, function(num) { return removeLeadingZero(num * scale) })
});
}
});
}
}

@@ -289,5 +254,13 @@

pathItem.data[0] *= splittedMatrix.scalex;
pathItem.data[1] *= splittedMatrix.scaley;
pathItem.data[2] += splittedMatrix.rotate;
transformArc(pathItem.data, matrix.data);
// reduce number of digits in rotation angle
if (Math.abs(pathItem.data[2]) > 80) {
var a = pathItem.data[0],
rotation = pathItem.data[2];
pathItem.data[0] = pathItem.data[1];
pathItem.data[1] = a;
pathItem.data[2] = rotation + (rotation > 0 ? -90 : 90);
}
newPoint = transformPoint(matrix.data, pathItem.data[5], pathItem.data[6]);

@@ -572,7 +545,12 @@ pathItem.data[5] = newPoint[0];

// concat previous data with current
prev = newPath[prevIndex] = {
instruction: prev.instruction,
data: prev.data.concat(item.data),
coords: item.coords,
base: prev.base
if (item.instruction != 'M') {
prev = newPath[prevIndex] = {
instruction: prev.instruction,
data: prev.data.concat(item.data),
coords: item.coords,
base: prev.base
}
} else {
prev.data = item.data;
prev.coords = item.coords;
}

@@ -607,3 +585,3 @@ } else {

*/
exports.interesects = function(path1, path2) {
exports.intersects = function(path1, path2) {
if (path1.length < 3 || path2.length < 3) return false; // nothing to fill

@@ -662,18 +640,16 @@

// Compute farthest polygon point in particular direction.
// Computes farthest polygon point in particular direction.
// Thanks to knowledge of min/max x and y coordinates we can choose a quadrant to search in.
// Since we're working on convex hull, the dot product is increasing until we find the farthest point.
function supportPoint(polygon, direction) {
// Choose a quadrant to search in. In the worst case only one quadrant would be iterated.
var index = direction[1] >= 0 ?
direction[0] < 0 ? polygon.maxY : polygon.maxX : // [1, 0] lands right on maxX
direction[0] < 0 ? polygon.maxY : polygon.maxX :
direction[0] < 0 ? polygon.minX : polygon.minY,
max = dot(polygon[index], direction);
for (var i = index; i < polygon.length; i++) {
var value = dot(polygon[i], direction);
if (value >= max) {
index = i;
max = value;
} else break; // surely we've found the maximum since we've choosen a quadrant
max = -Infinity,
value;
while ((value = dot(polygon[index], direction)) > max) {
max = value;
index = ++index % polygon.length;
}
return polygon[index];
return polygon[(index || polygon.length) - 1];
}

@@ -843,3 +819,4 @@ };

var lower = [],
minY = 0;
minY = 0,
bottom = 0;
for (var i = 0; i < points.length; i++) {

@@ -850,3 +827,4 @@ while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) <= 0) {

if (points[i][1] < points[minY][1]) {
minY = lower.length;
minY = i;
bottom = lower.length;
}

@@ -857,4 +835,5 @@ lower.push(points[i]);

var upper = [],
maxY = points.length - 1;
for (var i = points.length ; i--;) {
maxY = points.length - 1,
top = 0;
for (var i = points.length; i--;) {
while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) {

@@ -864,3 +843,4 @@ upper.pop();

if (points[i][1] > points[maxY][1]) {
maxY = upper.length;
maxY = i;
top = upper.length;
}

@@ -878,4 +858,4 @@ upper.push(points[i]);

hull.maxX = lower.length;
hull.minY = minY;
hull.maxY = (lower.length + maxY) % hull.length;
hull.minY = bottom;
hull.maxY = (lower.length + top) % hull.length;

@@ -893,63 +873,2 @@ return hull;

function norm(a) {
return a[0] * a[0] + a[1] * a[1];
}
function normalize(a) {
var mag = Math.sqrt(norm(a));
if (a[0]) a[0] /= mag;
if (a[1]) a[1] /= mag;
}
function deg(rad) {
return rad * 180 / Math.PI % 360;
}
function determinant(matrix) {
return matrix[0] * matrix[3] - matrix[1] * matrix[2];
}
/* Splits matrix into primitive transformations
= (object) in format:
o dx (number) translation by x
o dy (number) translation by y
o scalex (number) scale by x
o scaley (number) scale by y
o shear (number) shear
o rotate (number) rotation in deg
o isSimple (boolean) could it be represented via simple transformations
*/
function splitMatrix(matrix) {
var out = {};
// translation
out.dx = matrix[4];
out.dy = matrix[5];
// scale and shear
var row = [[matrix[0] , matrix[2] ], [matrix[1] , matrix[3]]];
out.scalex = Math.sqrt(norm(row[0]));
normalize(row[0]);
out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1];
row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear];
out.scaley = Math.sqrt(norm(row[1]));
normalize(row[1]);
out.shear /= out.scaley;
if (determinant(matrix) < 0) {
out.scalex = -out.scalex;
}
// rotation
var sin = -row[0][1],
cos = row[1][1];
if (cos < 0) {
out.rotate = deg(Math.acos(cos));
if (sin < 0) {
out.rotate = 360 - out.rotate;
}
} else {
out.rotate = deg(Math.asin(sin));
}
out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate);
return out;
}
function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {

@@ -956,0 +875,0 @@ // for more information of where this Math came from visit:

@@ -28,5 +28,3 @@ 'use strict';

// then collect it and change current context
transforms.push(current = {
name: item
});
transforms.push(current = { name: item });
// else if item is data

@@ -36,15 +34,2 @@ } else {

current.data = item.split(regTransformDataSplit).map(Number);
// 'rotate' has optional parameters <cx> <cy> which specify the point to rotate about.
// equivalent to 'translate(<cx>, <cy>) rotate(<rotate-angle>) translate(-<cx>, -<cy>)'
if (current.name == 'rotate' && current.data.length == 3) {
transforms.push({
name: 'translate',
data: [-current.data[1], -current.data[2]]
});
transforms.splice(transforms.length - 2, 0, {
name: 'translate',
data: current.data.splice(1)
});
}
}

@@ -67,25 +52,6 @@ }

var simple = true,
scalex = 1,
scaley = 1,
rotate = 0;
// convert transforms objects to the matrices
transforms = transforms.map(function(transform) {
if (transform.name === 'matrix') {
simple = false;
return transform.data;
} else if (simple) {
if (transform.name == 'scale') {
scalex *= transform.data[0];
scaley *= transform.data[1];
} else if (transform.name == 'rotate') {
if (scalex.toFixed(9) == scaley.toFixed(9)) {
rotate += transform.data[0];
} else {
simple = false;
}
} else if (transform.name != 'translate') {
simple = false;
}
}

@@ -103,11 +69,2 @@ return transformToMatrix(transform);

if (simple) {
transforms.splitted = {
scalex: scalex,
scaley: scaley,
rotate: rotate,
isSimple: true
}
}
return transforms;

@@ -159,73 +116,75 @@

/**
* Convert matrix data to the transform alias.
* Decompose matrix into simple transforms. See
* http://www.maths-informatique-jeux.com/blog/frederic/?post/2013/12/01/Decomposition-of-2D-transform-matrices
*
* @param {Object} data matrix transform object
* @return {Object} transform object
* @return {Object|Array} transforms array or original transform object
*/
exports.matrixToTransform = function(transform, params) {
var floatPrecision = params.floatPrecision,
data = transform.data,
transforms = [],
sx = +Math.sqrt(data[0] * data[0] + data[1] * data[1]).toFixed(params.transformPrecision),
sy = +((data[0] * data[3] - data[1] * data[2]) / sx).toFixed(params.transformPrecision),
colsSum = data[0] * data[2] + data[1] * data[3],
rowsSum = data[0] * data[1] + data[2] * data[3],
scaleBefore = rowsSum || +(sx == sy);
var data = transform.data;
// [..., ..., ..., ..., tx, ty] → translate(tx, ty)
if (data[4] || data[5]) {
transforms.push({ name: 'translate', data: data.slice(4, data[5] ? 6 : 5) });
}
// [1, 0, 0, 1, tx, ty] → translate(tx, ty)
if (
data[0] === 1 &&
data[1] === 0 &&
data[2] === 0 &&
data[3] === 1
) {
transform.name = 'translate';
transform.data = [data[4], data[5]];
// [sx, 0, tan(a)·sy, sy, 0, 0] → skewX(a)·scale(sx, sy)
if (!data[1] && data[2]) {
transforms.push({ name: 'skewX', data: [mth.atan(data[2] / sy, floatPrecision)] });
// [sx, 0, 0, sy, 0, 0] → scale(sx, sy)
} else if (
data[1] === 0 &&
data[2] === 0 &&
data[4] === 0 &&
data[5] === 0
) {
transform.name = 'scale';
transform.data = [data[0], data[3]];
// [sx, sx·tan(a), 0, sy, 0, 0] → skewY(a)·scale(sx, sy)
} else if (data[1] && !data[2]) {
transforms.push({ name: 'skewY', data: [mth.atan(data[1] / data[0], floatPrecision)] });
sx = data[0];
sy = data[3];
// [cos(a), sin(a), -sin(a), cos(a), 0 0] → rotate(a)
} else if (
data[0] === data[3] &&
data[1] === -data[2] &&
data[4] === 0 &&
data[5] === 0
) {
var a1 = mth.acos(data[0], params.floatPrecision),
a2 = mth.asin(data[1], params.floatPrecision);
// [sx·cos(a), sx·sin(a), sy·-sin(a), sy·cos(a), x, y] → rotate(a[, cx, cy])·(scale or skewX) or
// [sx·cos(a), sy·sin(a), sx·-sin(a), sy·cos(a), x, y] → scale(sx, sy)·rotate(a[, cx, cy]) (if !scaleBefore)
} else if (!colsSum || (sx == 1 && sy == 1) || !scaleBefore) {
if (!scaleBefore) {
sx = Math.sqrt(data[0] * data[0] + data[2] * data[2]);
sy = Math.sqrt(data[1] * data[1] + data[3] * data[3]);
transforms.push({ name: 'scale', data: [sx, sy] });
}
var a1 = mth.acos(data[0] / sx, floatPrecision),
a2 = mth.asin(data[1] / (rowsSum ? sx : sy), floatPrecision),
rotate = [a1.toFixed(floatPrecision) * (data[1] < 0 ? -1 : 1)];
a1 = a2 < 0 ? -a1 : a1;
if (rotate[0]) transforms.push({ name: 'rotate', data: rotate });
if (Math.round(a1) === Math.round(a2)) {
transform.name = 'rotate';
transform.data = [a1];
if (rowsSum && colsSum) transforms.push({
name: 'skewX',
data: [mth.atan(colsSum / (sx * sx), floatPrecision)]
})
// rotate(a, cx, cy) can consume translate() within optional arguments cx, cy (rotation point)
if (rotate[0] && (data[4] || data[5])) {
transforms.shift();
var cos = data[0] / sx,
sin = data[1] / (scaleBefore ? sx : sy),
x = data[4] * (scaleBefore || sy),
y = data[5] * (scaleBefore || sx),
denom = (Math.pow(1 - cos, 2) + Math.pow(sin, 2)) * (scaleBefore || sx * sy);
rotate.push(((1 - cos) * x - sin * y) / denom);
rotate.push(((1 - cos) * y + sin * x) / denom);
}
// [1, 0, tan(a), 1, 0, 0] → skewX(a)
} else if (
data[0] === 1 &&
data[1] === 0 &&
data[3] === 1 &&
data[4] === 0 &&
data[5] === 0
) {
transform.name = 'skewX';
transform.data = [mth.atan(data[2], params.floatPrecision)];
// [1, tan(a), 0, 1, 0, 0] → skewY(a)
} else if (
data[0] === 1 &&
data[2] === 0 &&
data[3] === 1 &&
data[4] === 0 &&
data[5] === 0
) {
transform.name = 'skewY';
transform.data = [mth.atan(data[1], params.floatPrecision)];
// Too many transformations, return original matrix if it isn't just a scale/translate
} else if (data[1] || data[2]) {
return transform;
}
return transform;
if (scaleBefore && (sx != 1 || sy != 1) || !transforms.length) transforms.push({
name: 'scale',
data: sx == sy ? [sx] : [sx, sy]
});
return transforms;
};

@@ -239,3 +198,3 @@

*/
var transformToMatrix = exports.transformToMatrix = function(transform) {
function transformToMatrix(transform) {

@@ -246,3 +205,3 @@ if (transform.name === 'matrix') return transform.data;

switch(transform.name) {
switch (transform.name) {
case 'translate':

@@ -257,7 +216,9 @@ // [1, 0, 0, 1, tx, ty]

case 'rotate':
// [cos(a), sin(a), -sin(a), cos(a), 0, 0]
// [cos(a), sin(a), -sin(a), cos(a), x, y]
var cos = mth.cos(transform.data[0]),
sin = mth.sin(transform.data[0]);
sin = mth.sin(transform.data[0]),
cx = transform.data[1] || 0,
cy = transform.data[2] || 0;
matrix = [cos, sin, -sin, cos, 0, 0];
matrix = [cos, sin, -sin, cos, (1 - cos) * cx + sin * cy, (1 - cos) * cy - sin * cx];
break;

@@ -279,2 +240,56 @@ case 'skewX':

/**
* Applies transformation to an arc. To do so, we represent ellipse as a matrix, multiply it
* by the transformation matrix and use a singular value decomposition to represent in a form
* rotate(θ)·scale(a b)·rotate(φ). This gives us new ellipse params a, b and θ.
* SVD is being done with the formulae provided by Wolffram|Alpha (svd {{m0, m2}, {m1, m3}})
*
* @param {Array} arc [a, b, rotation in deg]
* @param {Array} transform transformation matrix
* @return {Array} arc transformed input arc
*/
exports.transformArc = function(arc, transform) {
var a = arc[0],
b = arc[1],
rot = arc[2] * Math.PI / 180,
cos = Math.cos(rot),
sin = Math.sin(rot),
h = Math.pow(arc[5] * cos - arc[6] * sin, 2) / (4 * a * a) +
Math.pow(arc[5] * sin + arc[6] * cos, 2) / (4 * b * b);
if (h > 1) {
h = Math.sqrt(h);
a *= h;
b *= h;
}
var ellipse = [a * cos, a * sin, -b * sin, b * cos, 0, 0],
m = multiplyTransformMatrices(transform, ellipse),
// Decompose the new ellipse matrix
lastCol = m[2] * m[2] + m[3] * m[3],
squareSum = m[0] * m[0] + m[1] * m[1] + lastCol,
root = Math.sqrt(
(Math.pow(m[0] - m[3], 2) + Math.pow(m[1] + m[2], 2)) *
(Math.pow(m[0] + m[3], 2) + Math.pow(m[1] - m[2], 2))
);
if (!root) { // circle
arc[0] = arc[1] = Math.sqrt(squareSum / 2);
arc[2] = 0;
} else {
var majorAxisSqr = (squareSum + root) / 2,
minorAxisSqr = (squareSum - root) / 2,
major = Math.abs(majorAxisSqr - lastCol) > 1e-6,
sub = (major ? majorAxisSqr : minorAxisSqr) - lastCol,
rowsSum = m[0] * m[2] + m[1] * m[3],
term1 = m[0] * sub + m[2] * rowsSum,
term2 = m[1] * sub + m[3] * rowsSum;
arc[0] = Math.sqrt(majorAxisSqr);
arc[1] = Math.sqrt(minorAxisSqr);
arc[2] = ((major ? term2 < 0 : term1 > 0) ? -1 : 1) *
Math.acos((major ? term1 : term2) / Math.sqrt(term1 * term1 + term2 * term2)) * 180 / Math.PI;
}
return arc;
};
/**
* Multiply transformation matrices.

@@ -289,10 +304,10 @@ *

return [
+(a[0] * b[0] + a[2] * b[1]).toFixed(3),
+(a[1] * b[0] + a[3] * b[1]).toFixed(3),
+(a[0] * b[2] + a[2] * b[3]).toFixed(3),
+(a[1] * b[2] + a[3] * b[3]).toFixed(3),
+(a[0] * b[4] + a[2] * b[5] + a[4]).toFixed(3),
+(a[1] * b[4] + a[3] * b[5] + a[5]).toFixed(3)
a[0] * b[0] + a[2] * b[1],
a[1] * b[0] + a[3] * b[1],
a[0] * b[2] + a[2] * b[3],
a[1] * b[2] + a[3] * b[3],
a[0] * b[4] + a[2] * b[5] + a[4],
a[1] * b[4] + a[3] * b[5] + a[5]
];
}

@@ -14,2 +14,3 @@ 'use strict';

floatPrecision: 3,
transformPrecision: 5,
removeUseless: true,

@@ -62,3 +63,3 @@ collapseRepeated: true,

if (params.applyTransforms) {
data = applyTransforms(item, data, params.applyTransformsStroked, params.floatPrecision);
data = applyTransforms(item, data, params);
}

@@ -65,0 +66,0 @@

@@ -8,12 +8,14 @@ 'use strict';

exports.params = {
convertToShorts: true,
floatPrecision: 3,
matrixToTransform: true,
shortTranslate: true,
shortScale: true,
shortRotate: true,
removeUseless: true,
collapseIntoOne: true,
leadingZero: true,
negativeExtraSpace: false
convertToShorts: true,
// degPrecision: 3, // transformPrecision (or matrix precision) - 2 by default
floatPrecision: 3,
transformPrecision: 5,
matrixToTransform: true,
shortTranslate: true,
shortScale: true,
shortRotate: true,
removeUseless: true,
collapseIntoOne: true,
leadingZero: true,
negativeExtraSpace: false
};

@@ -71,7 +73,32 @@

function convertTransform(item, attrName, params) {
var data = transform2js(item.attr(attrName).value),
matrixData = data.reduce(function(a, b) { return b.name == 'matrix' ? a.concat(b.data.slice(0, 4)) : a }, []),
degPrecision = params.floatPrecision,
significantDigits = params.transformPrecision;
var data = transform2js(item.attr(attrName).value);
// Limit transform precision with matrix one. Calculating with larger precision doesn't add any value.
if (matrixData.length) {
params.transformPrecision = Math.min(params.transformPrecision,
Math.max.apply(Math, matrixData.map(function(n) {
return (n = String(n)).slice(n.indexOf('.')).length - 1; // Number of digits after point. 0.125 → 3
})) || params.transformPrecision);
significantDigits = Math.max.apply(Math, matrixData.map(function(n) {
return String(n).replace(/\D+/g, '').length; // Number of digits in number. 123.45 → 5
}));
}
// No sense in angle precision more then number of significant digits in matrix.
if (!('degPrecision' in params)) {
params.degPrecision = Math.max(0, Math.min(params.floatPrecision, significantDigits - 2));
}
if (params.collapseIntoOne && data.length > 1) {
data = [transformsMultiply(data)];
}
if (params.convertToShorts) {
data = convertToShorts(data, params);
} else {
data.forEach(function(transform) {
transform = roundTransform(transform, params);
});
}

@@ -83,26 +110,3 @@

if (
params.collapseIntoOne &&
(
data.length >= 3 ||
data.length == 2 &&
(
data[0].name === 'matrix' || data[1].name === 'matrix' ||
data[0].name == data[1].name
)
)
) {
data = [transformsMultiply(data, params)];
if (params.matrixToTransform) {
data = [matrixToTransform(data[0], params)];
}
if (params.removeUseless) {
data = removeUseless(data);
}
}
item.attr(attrName).value = js2transform(data, params);
}

@@ -126,13 +130,20 @@

params.matrixToTransform &&
transforms.length < 3 &&
transform.name === 'matrix'
) {
transforms[i] = matrixToTransform(transform, params);
var decomposed = matrixToTransform(transform, params);
if (decomposed != transform &&
js2transform(decomposed, params).length <= js2transform([transform], params).length) {
transforms.splice.apply(transforms, [i, 1].concat(decomposed));
}
transform = transforms[i];
}
transform = roundTransform(transform, params);
// fixed-point numbers
// 12.754997 → 12.755
if (params.floatPrecision !== false) {
if (params.transformPrecision !== false) {
transform.data = transform.data.map(function(num) {
return +num.toFixed(params.floatPrecision);
return +num.toFixed(params.transformPrecision);
});

@@ -147,5 +158,5 @@ }

transform.data.length === 2 &&
transform.data[1] === 0
!transform.data[1]
) {
transform.data = [transform.data[0]];
transform.data.pop();
}

@@ -161,3 +172,3 @@

) {
transform.data = [transform.data[0]];
transform.data.pop();
}

@@ -207,19 +218,25 @@

// translate(0), rotate(0), skewX(0), skewY(0)
// translate(0), rotate(0[, cx, cy]), skewX(0), skewY(0)
if (
['translate', 'rotate', 'skewX', 'skewY'].indexOf(transform.name) > -1 &&
(transform.data.length === 1 || transform.name === 'rotate') &&
transform.data[0] === 0 ||
transform.name === 'translate' &&
transform.data[0] === 0 &&
transform.data[1] === 0
(transform.data.length == 1 || transform.name == 'rotate') &&
!transform.data[0] ||
// translate(0, 0)
transform.name == 'translate' &&
!transform.data[0] &&
!transform.data[1] ||
// scale(1)
transform.name == 'scale' &&
transform.data[0] == 1 &&
(transform.data.length < 2 || transform.data[1] == 1) ||
// matrix(1 0 0 1 0 0)
transform.name == 'matrix' &&
transform.data[0] == 1 &&
transform.data[3] == 1 &&
!(transform.data[1] || transform.data[2] || transform.data[4] || transform.data[5])
) {
return false;
// scale(1)
} else if (
transform.name === 'scale' &&
transform.data.length === 1 &&
transform.data[0] === 1
) {
return false;
return false
}

@@ -246,5 +263,4 @@

transformJS.forEach(function(transform) {
transformString += (transformString ? ' ' : '') + transform.name + '(' + cleanupOutData(transform.data, params) + ')';
transform = roundTransform(transform, params);
transformString += (transformString && ' ') + transform.name + '(' + cleanupOutData(transform.data, params) + ')';
});

@@ -255,1 +271,52 @@

}
function roundTransform(transform, params) {
var floatRound = params.floatPrecision > 0 ? smartRound : round,
transformRound = params.transformPrecision > 0 ? smartRound : round;
switch (transform.name) {
case 'translate':
transform.data = floatRound(transform.data, params.floatPrecision);
break;
case 'rotate':
transform.data = floatRound(transform.data.slice(0, 1), params.degPrecision)
.concat(floatRound(transform.data.slice(1), params.floatPrecision));
break;
case 'skewX':
case 'skewY':
transform.data = floatRound(transform.data, params.degPrecision);
break;
case 'scale':
transform.data = transformRound(transform.data, params.transformPrecision);
break;
case 'matrix':
transform.data = transformRound(transform.data.slice(0, 4), params.transformPrecision)
.concat(floatRound(transform.data.slice(4), params.floatPrecision));
break;
}
return transform;
}
function round(data) {
return data.map(Math.round);
}
/**
* Decrease accuracy of floating-point numbers
* in transforms keeping a specified number of decimals.
* Smart rounds values like 2.349 to 2.35.
*
* @param {Array} data input data array
* @param {Number} fixed number of decimals
* @return {Array} output data array
*/
function smartRound(data, precision) {
for (var i = data.length, tolerance = Math.pow(.1, precision); i--;) {
var rounded = +data[i].toFixed(precision - 1);
data[i] = +Math.abs(rounded - data[i]).toFixed(precision) >= tolerance ?
+data[i].toFixed(precision) :
rounded;
}
return data;
}

@@ -15,3 +15,3 @@ 'use strict';

js2path = require('./_path.js').js2path,
interesects = require('./_path.js').interesects;
intersects = require('./_path.js').intersects;

@@ -58,3 +58,3 @@ /**

if (equalData && !interesects(prevPathJS, curPathJS)) {
if (equalData && !intersects(prevPathJS, curPathJS)) {
js2path(prevContentItem, prevPathJS.concat(curPathJS), params);

@@ -61,0 +61,0 @@ return false;

@@ -27,4 +27,5 @@ 'use strict';

return !(item.isElem(container) && !item.isElem('svg') && item.isEmpty());
return !(item.isElem(container) && !item.isElem('svg') && item.isEmpty() &&
(!item.isElem('pattern') || !item.hasAttr('xlink:href')));
};

@@ -24,3 +24,3 @@ 'use strict';

var regValidPath = /m.*[lhvcsqta]/i;
var regValidPath = /M\s*(?:[+-]?(?:\d*\.\d+|\d+(?!\.\d)\.?)(?!\d)\s*,?\s*){2}\D*\d/i;

@@ -27,0 +27,0 @@ /**

@@ -37,3 +37,3 @@ "use strict";

if (item.hasAttr('id')) {
if (item.hasAttr('id') || item.isElem('style')) {

@@ -40,0 +40,0 @@ usefulItems.push(item);

**english** | [русский](https://github.com/svg/svgo/blob/master/README.ru.md)
- - -
<img src="http://soulshine.in/svgo.svg" width="200" height="200" alt="logo"/>
<img src="https://svg.github.io/svgo-logo.svg" width="200" height="200" alt="logo"/>

@@ -21,35 +21,35 @@ ## SVGO [![NPM version](https://badge.fury.io/js/svgo.svg)](https://npmjs.org/package/svgo) [![Dependency Status](https://gemnasium.com/svg/svgo.png)](https://gemnasium.com/svg/svgo) [![Build Status](https://secure.travis-ci.org/svg/svgo.svg)](https://travis-ci.org/svg/svgo) [![Coverage Status](https://img.shields.io/coveralls/svg/svgo.svg)](https://coveralls.io/r/svg/svgo?branch=master)

* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) ] cleanup attributes from newlines, trailing and repeating spaces
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) ] remove doctype declaration
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) ] remove XML processing instructions
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) ] remove comments
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) ] remove `<metadata>`
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) ] remove `<title>` (disabled by default)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) ] remove `<desc>` (only non-meaningful by default)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) ] remove elements of `<defs>` without `id`
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) ] remove editors namespaces, elements and attributes
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) ] remove empty attributes
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) ] remove hidden elements
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) ] remove empty Text elements
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) ] remove empty Container elements
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) ] remove `viewBox` attribute when possible (disabled by default)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) ] remove or cleanup `enable-background` attribute when possible
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) ] convert styles into attributes
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) ] convert colors (from `rgb()` to `#rrggbb`, from `#rrggbb` to `#rgb`)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) ] convert Path data to relative or absolute whichever is shorter, convert one segment to another, trim useless delimiters, smart rounding and much more
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) ] collapse multiple transforms into one, convert matrices to the short aliases and much more
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) ] remove unknown elements content and attributes, remove attrs with default values
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) ] remove non-inheritable group's "presentation" attributes
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) ] remove useless stroke and fill attrs
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) ] remove unused namespaces declaration
* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) ] remove unused and minify used IDs
* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) ] round numeric values to the fixed precision, remove default 'px' units
* [ [>](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) ] move elements attributes to the existing group wrapper
* [ [>](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) ] move some group attributes to the content elements
* [ [>](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) ] collapse useless groups
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) ] remove raster images (disabled by default)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) ] merge multiple Paths into one
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) ] convert some basic shapes to path
* [ [>](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) ] sort element attributes for epic readability (disabled by default)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) ] apply transforms, crop by real width, center vertical alignment and resize SVG with one Path inside (disabled by default)
* [ [ cleanupAttrs](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) ] cleanup attributes from newlines, trailing and repeating spaces
* [ [ removeDoctype](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) ] remove doctype declaration
* [ [ removeXMLProcInst](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) ] remove XML processing instructions
* [ [ removeComments](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) ] remove comments
* [ [ removeMetaData](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) ] remove `<metadata>`
* [ [ removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) ] remove `<title>` (disabled by default)
* [ [ removeDesc](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) ] remove `<desc>` (only non-meaningful by default)
* [ [ removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) ] remove elements of `<defs>` without `id`
* [ [ removeEditorsNSData](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) ] remove editors namespaces, elements and attributes
* [ [ removeEmptyAttrs](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) ] remove empty attributes
* [ [ removeHiddenElems](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) ] remove hidden elements
* [ [ removeEmptyText](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) ] remove empty Text elements
* [ [ removeEmptyContainers](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) ] remove empty Container elements
* [ [ removeViewBox](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) ] remove `viewBox` attribute when possible (disabled by default)
* [ [ cleanUpEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) ] remove or cleanup `enable-background` attribute when possible
* [ [ convertTyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) ] convert styles into attributes
* [ [ convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) ] convert colors (from `rgb()` to `#rrggbb`, from `#rrggbb` to `#rgb`)
* [ [ convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) ] convert Path data to relative or absolute whichever is shorter, convert one segment to another, trim useless delimiters, smart rounding and much more
* [ [ convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) ] collapse multiple transforms into one, convert matrices to the short aliases and much more
* [ [ removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) ] remove unknown elements content and attributes, remove attrs with default values
* [ [ removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) ] remove non-inheritable group's "presentation" attributes
* [ [ removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) ] remove useless stroke and fill attrs
* [ [ removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) ] remove unused namespaces declaration
* [ [ cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) ] remove unused and minify used IDs
* [ [ cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) ] round numeric values to the fixed precision, remove default 'px' units
* [ [ moveElemsAttrsToGroup](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) ] move elements attributes to the existing group wrapper
* [ [ moveGroupAttrsToElems](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) ] move some group attributes to the content elements
* [ [ collapseGroups](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) ] collapse useless groups
* [ [ removeRasterImages](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) ] remove raster images (disabled by default)
* [ [ mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) ] merge multiple Paths into one
* [ [ convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) ] convert some basic shapes to path
* [ [ sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) ] sort element attributes for epic readability (disabled by default)
* [ [ transformsWithOnePath](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) ] apply transforms, crop by real width, center vertical alignment and resize SVG with one Path inside (disabled by default)

@@ -56,0 +56,0 @@ Want to know how it works and how to write your own plugin? [Of course you want to](https://github.com/svg/svgo/blob/master/docs/how-it-works/en.md).

[english](https://github.com/svg/svgo/blob/master/README.md) | **русский**
- - -
<img src="http://soulshine.in/svgo.svg" width="200" height="200" alt="logo"/>
<img src="https://svg.github.io/svgo-logo.svg" width="200" height="200" alt="logo"/>

@@ -21,35 +21,35 @@ ## SVGO [![NPM version](https://badge.fury.io/js/svgo.svg)](https://npmjs.org/package/svgo) [![Dependency Status](https://gemnasium.com/svg/svgo.png)](https://gemnasium.com/svg/svgo) [![Build Status](https://secure.travis-ci.org/svg/svgo.svg)](https://travis-ci.org/svg/svgo) [![Coverage Status](https://img.shields.io/coveralls/svg/svgo.svg)](https://coveralls.io/r/svg/svgo?branch=master)

* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) ] удаление переносов строк и лишних пробелов
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) ] удаление doctype
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) ] удаление XML-инструкций
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) ] удаление комментариев
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) ] удаление `<metadata>`
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) ] удаление `<title>` (отключена по умолчанию)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) ] удаление `<desc>` (по умолчанию только незначимых)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) ] удаление элементов в `<defs>` без `id`
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) ] удаление пространств имён различных редакторов, их элементов и атрибутов
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) ] удаление пустых атрибутов
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) ] удаление скрытых элементов
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) ] удаление пустых текстовых элементов
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) ] удаление пустых элементов-контейнеров
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) ] удаление атрибута `viewBox`, когда это возможно
* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) ] удаление или оптимизация атрибута `enable-background`, когда это возможно
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) ] конвертирование стилей в атрибуте `style` в отдельные svg-атрибуты
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) ] конвертирование цветовых значений: из `rgb()` в `#rrggbb`, из `#rrggbb` в `#rgb`
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) ] конвертирование данных Path в относительные или абсолютные координаты, смотря что короче, конвертирование одних типов сегментов в другие, удаление ненужных разделителей, умное округление и тому подобное
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) ] схлопывание нескольких трансформаций в одну, конвертирование матриц в короткие алиасы и многое другое
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) ] удаление неизвестных элементов, контента и атрибутов
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) ] удаление ненаследуемых "презентационных" атрибутов групп
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) ] удаление неиспользуемых атрибутов stroke-* и fill-*
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) ] удаление деклараций неиспользуемых пространств имён
* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) ] удаление неиспользуемых и сокращение используемых ID
* [ [>](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) ] округление дробных чисел до заданной точности, удаление `px` как единицы измерения по-умолчанию
* [ [>](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) ] перемещение совпадающих атрибутов у всех элементов внутри группы `<g>`
* [ [>](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) ] перемещение некоторых атрибутов группы на элементы внутри
* [ [>](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) ] схлопывание бесполезных групп `<g>`
* [ [>](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) ] удаление растровых изображений (выключено по умолчанию)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) ] склеивание нескольких Path в одну кривую
* [ [>](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) ] конвертирование простых форм в Path
* [ [>](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) ] сортировка атрибутов элементов для удобочитаемости (выключено по умолчанию)
* [ [>](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) ] применение трансформаций, обрезка по реальной ширине, вертикальное выравнивание по центру и изменение размеров SVG с одним Path внутри
* [ [ cleanupAttrs](https://github.com/svg/svgo/blob/master/plugins/cleanupAttrs.js) ] удаление переносов строк и лишних пробелов
* [ [ removeDoctype](https://github.com/svg/svgo/blob/master/plugins/removeDoctype.js) ] удаление doctype
* [ [ removeXMLProcInst](https://github.com/svg/svgo/blob/master/plugins/removeXMLProcInst.js) ] удаление XML-инструкций
* [ [ removeComments](https://github.com/svg/svgo/blob/master/plugins/removeComments.js) ] удаление комментариев
* [ [ removeMetadata](https://github.com/svg/svgo/blob/master/plugins/removeMetadata.js) ] удаление `<metadata>`
* [ [ removeTitle](https://github.com/svg/svgo/blob/master/plugins/removeTitle.js) ] удаление `<title>` (отключена по умолчанию)
* [ [ removeDesc](https://github.com/svg/svgo/blob/master/plugins/removeDesc.js) ] удаление `<desc>` (по умолчанию только незначимых)
* [ [ removeUselessDefs](https://github.com/svg/svgo/blob/master/plugins/removeUselessDefs.js) ] удаление элементов в `<defs>` без `id`
* [ [ removeEditorsNSData](https://github.com/svg/svgo/blob/master/plugins/removeEditorsNSData.js) ] удаление пространств имён различных редакторов, их элементов и атрибутов
* [ [ removeEmptyAttrs](https://github.com/svg/svgo/blob/master/plugins/removeEmptyAttrs.js) ] удаление пустых атрибутов
* [ [ removeHiddenElems](https://github.com/svg/svgo/blob/master/plugins/removeHiddenElems.js) ] удаление скрытых элементов
* [ [ removeEmptyText](https://github.com/svg/svgo/blob/master/plugins/removeEmptyText.js) ] удаление пустых текстовых элементов
* [ [ removeEmptyContainers](https://github.com/svg/svgo/blob/master/plugins/removeEmptyContainers.js) ] удаление пустых элементов-контейнеров
* [ [ removeViewBox](https://github.com/svg/svgo/blob/master/plugins/removeViewBox.js) ] удаление атрибута `viewBox`, когда это возможно
* [ [ cleanupEnableBackground](https://github.com/svg/svgo/blob/master/plugins/cleanupEnableBackground.js) ] удаление или оптимизация атрибута `enable-background`, когда это возможно
* [ [ convertStyleToAttrs](https://github.com/svg/svgo/blob/master/plugins/convertStyleToAttrs.js) ] конвертирование стилей в атрибуте `style` в отдельные svg-атрибуты
* [ [ convertColors](https://github.com/svg/svgo/blob/master/plugins/convertColors.js) ] конвертирование цветовых значений: из `rgb()` в `#rrggbb`, из `#rrggbb` в `#rgb`
* [ [ convertPathData](https://github.com/svg/svgo/blob/master/plugins/convertPathData.js) ] конвертирование данных Path в относительные или абсолютные координаты, смотря что короче, конвертирование одних типов сегментов в другие, удаление ненужных разделителей, умное округление и тому подобное
* [ [ convertTransform](https://github.com/svg/svgo/blob/master/plugins/convertTransform.js) ] схлопывание нескольких трансформаций в одну, конвертирование матриц в короткие алиасы и многое другое
* [ [ removeUnknownsAndDefaults](https://github.com/svg/svgo/blob/master/plugins/removeUnknownsAndDefaults.js) ] удаление неизвестных элементов, контента и атрибутов
* [ [ removeNonInheritableGroupAttrs](https://github.com/svg/svgo/blob/master/plugins/removeNonInheritableGroupAttrs.js) ] удаление ненаследуемых "презентационных" атрибутов групп
* [ [ removeUselessStrokeAndFill](https://github.com/svg/svgo/blob/master/plugins/removeUselessStrokeAndFill.js) ] удаление неиспользуемых атрибутов stroke-* и fill-*
* [ [ removeUnusedNS](https://github.com/svg/svgo/blob/master/plugins/removeUnusedNS.js) ] удаление деклараций неиспользуемых пространств имён
* [ [ cleanupIDs](https://github.com/svg/svgo/blob/master/plugins/cleanupIDs.js) ] удаление неиспользуемых и сокращение используемых ID
* [ [ cleanupNumericValues](https://github.com/svg/svgo/blob/master/plugins/cleanupNumericValues.js) ] округление дробных чисел до заданной точности, удаление `px` как единицы измерения по-умолчанию
* [ [ moveElemsAttrsToGroup](https://github.com/svg/svgo/blob/master/plugins/moveElemsAttrsToGroup.js) ] перемещение совпадающих атрибутов у всех элементов внутри группы `<g>`
* [ [ moveGroupAttrsToElems](https://github.com/svg/svgo/blob/master/plugins/moveGroupAttrsToElems.js) ] перемещение некоторых атрибутов группы на элементы внутри
* [ [ collapseGroups](https://github.com/svg/svgo/blob/master/plugins/collapseGroups.js) ] схлопывание бесполезных групп `<g>`
* [ [ removeRasterImage](https://github.com/svg/svgo/blob/master/plugins/removeRasterImages.js) ] удаление растровых изображений (выключено по умолчанию)
* [ [ mergePaths](https://github.com/svg/svgo/blob/master/plugins/mergePaths.js) ] склеивание нескольких Path в одну кривую
* [ [ convertShapeToPath](https://github.com/svg/svgo/blob/master/plugins/convertShapeToPath.js) ] конвертирование простых форм в Path
* [ [ sortAttrs](https://github.com/svg/svgo/blob/master/plugins/sortAttrs.js) ] сортировка атрибутов элементов для удобочитаемости (выключено по умолчанию)
* [ [ transformsWithOnePath](https://github.com/svg/svgo/blob/master/plugins/transformsWithOnePath.js) ] применение трансформаций, обрезка по реальной ширине, вертикальное выравнивание по центру и изменение размеров SVG с одним Path внутри

@@ -56,0 +56,0 @@ Хотите узнать, как это работает и как написать свой плагин? [Конечно же, да!](https://github.com/svg/svgo/blob/master/docs/how-it-works/ru.md).

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc