svg-slimming
TypeScript icon, indicating that this package has built-in type declarations

1.5.3 • Public • Published

svg-slimming

npm version

Change Log

View change log

Introduction

svg-slimming is an SVG compression tool that provides rich customization and follows the W3C SVG specification

Installation

npm install svg-slimming

Use

const svgSlimming = require('svg-slimming');
svgSlimming(svgcode[, config]).then(result => {
	console.log(result);
});

Where svgcode is svg text in string format and config is user-defined optimized configuration

Use svg-slimming-loader

svg-slimming-loader is a loader plugin for webpack, which supports optimization of imported SVG files

Use postcss-svg-slimming

postcss-svg-slimming is a plugin for postcss that supports optimizing inline SVG in CSS

Why choose svg-slimming?

  • Rich and powerful functions, enough personalized configuration parameters
  • Pursue the ultimate optimization effect
  • Try not to destroy the original svg effect
  • Follow the latest svg specifications

vs svgo

Optimization classification Optimization project svg-slimming svgo
Basic svg parsing Built-in parser xml-parser sax
Basic Non-svg xml node processing logic Remove Report error
Basic Oversized svg processing ×
Basic Compressing Redundant Blanks
Basic Remove Comments
Basic Remove xml declaration and doctype
Basic Merging Text Nodes
Basic Support optimization CDATA node ×
Elements Remove unnecessary elements
Elements Remove Invisible Elements
Elements Collapse unnecessary group nodes
Elements Collapse unnecessary text container nodes ×
Elements remove elements that do not conform to the svg specification
Elements Optimize nesting of irregular elements
Elements optimization defs
Elements Apply defs directly to the element v1.5.3
svg element viewBox vs size size preferred viewbox preferred
svg element remove version attribute
svg element optimization xmlns
path element d attribute of path optimized by calculation
path element discard empty subpaths ×
path element remove invalid waypoints for continuous line instructions ×
path element merge a instruction under certain conditions ×
path element thinning path node ×
path element small size curve command to line command v1.5.0
path element remove a directive flag trailing space v1.5.0
path element merge path
shape shape to path
shape remove empty shapes (such as circle with radius 0, rect with width and height 0, etc.) ×
shape ellipsis and circle rotation v1.5.0
shape support thinning path node optimization polyline and polygon ×
Attributes Remove empty attributes
Attributes Remove invalid and illegal attributes ×
Attributes Remove attributes with the same default values ×
Attributes Optimize attributes by analyzing style inheritance chains ×
Attributes Shorten ID
Attributes Remove px units
Attributes Remove unnecessary fills and strokes ×
Numbers Optimize Digital
Numbers Precisely optimize different types of values ×
Numbers Digital to Scientific Notation ×
Matrix merge and shorten transform
Matrix Apply transform directly to attributes v1.5.2
Color Optimize Color
Color Support hsl / hsla format color ×
Color Support rgba format color ×
Color Supports hex color in #rrggbbaa format ×
css css parsing css csso
css merge style elements ×
css Optimize style content
css shorten className ×
css style to attributes
css attribute to style √ (badcase exists) ×
css remove css styles not supported by svg √ (badcase exists) ×
css Apply style content directly to elements ×

Optimized Configuration

The optimized configuration is an object in JSON format, where key is the corresponding configuration item, value is the array, the first item in the array is the switch of the rule, and the second item (if any) is the detailed configuration of the rule.

The following is an example of an optimized configuration:

{
	"collapse-g": [false],
	"combine-transform": [true, {
		"trifuncDigit": 3,
		"sizeDigit": 2,
		"angelDigit": 2
	}]
}

** Note: Although the old configuration method can also take effect, it may be removed in the future **

{
	"collapse-g": false,
	"combine-transform": [true, 3, 2, 2]
}

collapse-g

  • Default configuration:
{
	"collapse-g": [true]
}
  • Explanation:
    • When the g element has no children, remove the element
    • When the g element has no attribute value, replace the element with a child element
    • When the g element has only one child element and has no id, class, and mask attributes, copy the attributes of the g element to the child element and replace it with the child element

E.g:

<g></g>
<g fill="red"><rect width="100" height="100"/></g>

After optimization will become:

<rect fill="red" width="100" height="100"/>

collapse-textwrap

  • Default configuration:
{
	"collapse-textwrap": [true]
}
  • Explanation:
    • For all nested text containers, when the inner text container does not contain any valid attributes, remove the element and promote the text content to the child nodes of the parent element

E.g:

<text></text>
<text fill="red"><tspan>123</tspan></text>

After optimization will become:

<text fill="red">123</text>

combine-path

  • Default configuration:
{
	"combine-path": [true, {
		"disregardFill": false,
		"disregardOpacity": false
	}]
}
  • Explanation:
    • Merge path nodes that meet the following conditions:
      1. All attributes and styles (including inherited styles) are the same
      2. adjacent
      3. no fill
      4. stroke transparency is not less than 1
      5. No marker-start, marker-mid, marker-end
  • Configuration parameters:
    • disregardFill
      • Default: false
      • Whether to allow paths that meet the following conditions:
        1. stroke is empty
        2. fill-rull is not evenodd
        3. The transparency of fill is not less than 1
    • disregardOpacity
      • Default: false
      • Whether to allow paths with transparency less than 1 E.g:
<path d="M0,0L100,100" fill="none" stroke="red" stroke-width="2"/>
<path d="M0,50L100,150" fill="none" stroke="red" stroke-width="2"/>

After optimization will become:

<path d="M0,0L100,100M0,50L100,150" fill="none" stroke="red" stroke-width="2"/>

combine-transform

  • Default configuration:
{
	"combine-transform": [true, {
		"angelDigit": 2,
		"sizeDigit": 2,
		"trifuncDigit": 3
	}]
}
  • Explanation:
    • Analyze and merge transform attributes
  • Configuration parameters:
    • angelDigit
      • Default value: 2
      • Limited to 0 or positive integer
      • Angle parameter accuracy of skewX, skewY, rotate
    • sizeDigit
      • Default value: 2
      • Limited to 0 or positive integer
      • matrix e, f position parameter precision, translate parameter precision, and 3 parameter precision after 2 value rotate
    • trifuncDigit
      • Default: 3
      • Limited to 0 or positive integer
      • matrix a, b, c, d position parameter precision, scale parameter precision

E.g:

<rect fill="red" width="100" height="100" transform="translate(100,100)scale(2)rotate(180)"/>

After optimization will become:

<rect fill="red" width="100" height="100" transform="matrix(-2,0,0,-2,100,100)"/>

compute-path

  • Default configuration:
{
	"compute-path": [true, {
		"angelDigit": 2,
		"sizeDigit": 2,
		"straighten": 0,
		"thinning": 0
	}]
}
  • Explanation:
    • Calculate the d attribute of path to make it shorter
  • Configuration parameters:
    • angelDigit
      • Default value: 2
      • Limited to 0 or positive integer
      • Accuracy of a / A instruction x-axis-rotation
    • sizeDigit
      • Default value: 2
      • Limited to 0 or positive integer
      • Precision of coordinate type values
    • straighten
      • Default value: 0
      • Limited to 0 or positive integer
      • Turn the curve command within the specified threshold into a shorter straight command
      • If it is 0, it means that no conversion will be performed.
    • thinning
      • Default value: 0
      • Limited to 0 or positive integer
      • Thin out path nodes for shorter results
      • 0 means no path thinning is performed, non-zero will be considered as the threshold of thinning nodes

E.g:

<path fill="red" d="M0,0L100,0,100,100,0,100z"/>

After optimization will become:

<path fill="red" d="m0,0h100v100H0z"/>

rm-attribute

  • Default configuration:
{
	"rm-attribute": [true, {
		"keepAria": false,
		"keepEvent": false,
		"rmDefault": true
	}]
}
  • Explanation:
    • Remove non-canonical attributes (not in SVG spec and not attributes of the xmlns class)
  • Configuration parameters:
    • keepAria
      • Default: false
      • Keep all aria attributes, currently removed by default
    • keepEvent
      • Default: false
      • Keep all Event Monitoring attributes, currently removed by default
    • rmDefault
      • Default: true
      • Remove the same attribute as the default (if the attribute is inheritable and the parent element has an attribute with the same name, it cannot be removed)

E.g:

<g fill="red">
	<rect fill="black" width="100" height="100" aa="1" bb="2" cc="3" aria-autocomplete="both" onclick="console.log('a');"/>
</g>

After optimization will become:

<g fill="red">
	<rect fill="black" width="100" height="100"/>
</g>

rm-comments

  • Default configuration:
{
	"rm-comments": [true]
}
  • Explanation:
    • Remove comment

rm-doctype

  • Default configuration:
{
	"rm-doctype": [true]
}
  • Explanation:
    • Remove DOCTYPE declaration

rm-hidden

  • Default configuration:
{
	"rm-hidden": [true]
}
  • Explanation:
    • Remove elements with display attribute none
    • Removed graphic elements with fill and stroke properties of none
    • Remove text container without children
    • Remove other graphic elements that are not rendered for some reason

The following will be removed:

display IS none

<g style="display:none"></g>

stroke and fill are none

<rect fill="none" stroke="none" width="100" height="100"/>

use element references a non-existing id

<use href="#undefined"/>

Some elements that are not visible because the size attribute is 0, e.g:

<pattern id="pattern-1" width="0" height="0" />

rm-irregular-nesting

  • Default configuration:
{
	"rm-irregular-nesting": [true, {
		"ignore": []
	}]
}
  • Explanation:
    • Remove irregularly nested tags
  • Configuration parameters:
    • ignore
      • Default:[]
      • Restricted to a list of strings. If the tag name of an element is in the list, neither the element nor its child elements will validate the nesting rules.

E.g:

<rect fill="red" width="100px" height="100px"><circle cx="100" cy="100" r="100"/></rect>

After optimization will become:

<rect fill="red" width="100" height="100"/>

rm-irregular-tag

  • Default configuration:
{
	"rm-irregular-tag": [true, {
		"ignore": []
	}]
}
  • Explanation:
  • Configuration parameters:
    • ignore
      • Default:[]
      • Restricted to a list of strings. If the tag name of an element is in the list, the element will not be removed although it is not a standard SVG tag

rm-px

  • Default configuration:
{
	"rm-px": [true]
}
  • Explanation:
    • Remove px units and 0 units

E.g:

<rect fill="red" width="100px" height="100px" rx="0pt"/>

After optimization will become:

<rect fill="red" width="100" height="100" rx="0"/>

rm-unnecessary

  • Default configuration:
{
	"rm-unnecessary": [true, {
		"tags": ["desc", "discard", "foreignObject", "video", "audio", "iframe", "canvas", "metadata", "script", "title", "unknown", "image"]
	}]
}
  • Explanation:
    • Remove unnecessary tags
    • Although style tags are not removed by default, some rules (such as shape-to-path) may cause selectors in the style sheet to fail to match
    • As there is no analysis and processing of javascript scripts, if the script tag is not removed by default, there is no guarantee that the optimized code can still be executed correctly
  • Configuration parameters:
    • tags
      • Default: ["desc", "discard", "foreignObject", "video", "audio", "iframe", "canvas", "metadata", "script", "title", "unknown", "image"]
      • Restricted to a list of strings
      • Configure the tag names to be removed. Only tags in the following list can be removed: ["desc", "discard", "foreignObject", "video", "audio", "iframe", "canvas", "metadata", "script", "style", "title", "unknown", "image"]

rm-version

  • Default configuration:
{
	"rm-version": [true]
}
  • Explanation:
    • Remove version attribute from svg element

rm-viewbox

  • Default configuration:
{
	"rm-viewbox": [true]
}
  • Explanation:
    • When x, y, width, height are exactly the same, remove viewBox property

E.g:

<svg width="1000" height="600" viewBox="0 0 1000 600">

After optimization will become:

<svg width="1000" height="600">

rm-xml-decl

  • Default configuration:
{
	"rm-xml-decl": [true]
}
  • Explanation:
    • Remove xml declaration

rm-xmlns

  • Default configuration:
{
	"rm-xmlns": [true]
}
  • Explanation:
    • Remove unreferenced xmlns definitions, remove attributes containing undefined namespaces

E.g:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
	<rect fill="red" width="100" height="100"/>
</svg>

After optimization will become(Since the xlink namespace is not referenced, it was removed):

<svg xmlns="http://www.w3.org/2000/svg">
	<rect fill="red" width="100" height="100"/>
</svg>

shorten-animate

  • Default configuration:
{
	"shorten-animate": [true, {
		"remove": false
	}]
}
  • Explanation:
    • Optimize animation elements and remove illegal animation elements
  • Configuration parameters:
    • remove
      • Default: false
      • Remove all animation elements without any verification

E.g:

<animate/><!-- no attributeName -->
<animate attributeName="title" to="test"/><!-- title is not animatable attribute -->
<animate attributeName="x"/><!-- no from/to/by/values -->
<animate attributeName="x" to="abc"/><!-- the value of to does not match x -->

经过优化以上元素都会被移除

shorten-class

  • Default configuration:
{
	"shorten-class": [true]
}
  • Explanation:
    • Shorten className
    • Remove unreferenced className

E.g:

<style>.red_rect {fill: red;}</style>
<rect class="red_rect blue_rect" width="100" height="100"/>

After optimization will become (.red_rect is shortened to .a, .blue_rect is removed directly):

<style>.a {fill: red;}</style>
<rect class="a" width="100" height="100"/>

shorten-color

  • Default configuration:
{
	"shorten-color": [true, {
		"opacityDigit": 3,
		"rrggbbaa": false
	}]
}
  • Explanation:
    • Keep color definitions as short as possible
  • Configuration parameters:
    • opacityDigit
      • Default: 3
      • Limited to 0 or positive integer
      • Precision of color alpha values in rgba, hsla format
    • rrggbbaa
      • Default: false
      • Whether to use 8-digit hexadecimal color (E.g: rgba(255,0,0,0.5) => #ff000080)

E.g:

<rect fill="#ff0000" stroke="rgb(255,255,255)" color="rgba(0,0,0,0)" width="100" height="100"/>

After optimization will become:

<rect fill="red" stroke="#fff" color="transparent" width="100" height="100"/>

shorten-decimal-digits

  • Default configuration:
{
	"shorten-decimal-digits": [true, {
		"angelDigit": 2,
		"sizeDigit": 2
	}]
}
  • Explanation:
    • Narrowing different types of numerical precision
  • Configuration parameters:
    • angelDigit
      • Default value: 2
      • Limited to 0 or positive integer
      • Accuracy of numerical values such as transparency, angle, and radian
    • sizeDigit
      • Default value: 2
      • Limited to 0 or positive integer
      • Accuracy of coordinate and size type values

E.g:

<rect fill="red" width="100.00001" height="100.00001" fill-opacity="0.05999"/>

After optimization will become:

<rect fill="red" width="100" height="100" fill-opacity="6%"/>

shorten-defs

  • Default configuration:
{
	"shorten-defs": [true]
}
  • Explanation:
    • Merge all defs tags
    • Remove invalid defs definitions
    • Remove empty defs tags

E.g:

<defs>
	<circle id="circle-1" fill="#000" cx="60" cy="60" r="60"></circle>
</defs>
<defs>
	<circle fill-opacity="0.599999964" fill="#000000" cx="60" cy="60" r="60"></circle>
</defs>
<mask id="mask-2" fill="white">
	<use xlink:href="#circle-1" />
</mask>

After optimization will become:

<defs>
	<circle id="path-1" fill="#000" cx="60" cy="60" r="60"></circle>
</defs>
<mask id="mask-2" fill="white">
	<use xlink:href="#path-1" />
</mask>

shorten-filter

  • default allocation:
{
"shorten-filter": [true]
}
  • Explanation:
    • Optimized [Filter Elements] (https://drafts.fxtf.org/filter-effects/#FilterElement)
    • Remove empty filter elements
    • The width and height of the filter element cannot be 0 or negative
    • Duplicate transferFunctionElement is not allowed under feComponentTransfer
    • transferFunctionElement retains only necessary attributes based on type

E.g:

<filter></filter>
<filter>
	<feComponentTransfer>
		<feFuncR type="gamma" amplitude="1" exponent="1" offset="0"/>
		<feFuncR type="linear" amplitude="1" exponent="1" offset="0" slope="2"/>
	</feComponentTransfer>
</filter>

After optimization will becomes:

<filter>
	<feComponentTransfer>
		<feFuncR type="linear" slope="2"/>
	</feComponentTransfer>
</filter>

shorten-id

  • Default configuration:
{
	"shorten-id": [true]
}
  • Explanation:
    • Shorten ID
    • Remove unreferenced IDs

E.g:

<defs>
	<circle id="circle-1" fill="#000" cx="60" cy="60" r="60"></circle>
</defs>
<mask id="mask-2" fill="white">
	<use xlink:href="#circle-1" />
</mask>
<rect id="rect-3" fill="red" width="100" height="100" mask="url(#mask-2)"/>

After optimization will become (#rect-3 is removed and the other 2 ids are shortened):

<defs>
	<circle id="a" fill="#000" cx="60" cy="60" r="60"></circle>
</defs>
<mask id="b" fill="white">
	<use xlink:href="#a" />
</mask>
<rect fill="red" width="100" height="100" mask="url(#b)"/>

shorten-shape(v1.5.0+)

  • Default configuration:
{
	"shorten-shape": [true, {
		"thinning": 0
	}]
}
  • Explanation:
    • If the result of the shape mapping to path is shorter, use path
    • If the rx and ry of the ellipse shape are the same, convert to circle
  • Configuration parameters:
    • thinning
      • Default value: 0
      • Limited to 0 or positive integer
      • Thinning polygons and polylines for shorter results
      • 0 means do not perform thinning nodes, non-zero will be regarded as the threshold of thinning nodes

E.g:

<rect fill="red" width="100" height="100"/>

After optimization will become:

<path fill="red" d="M0,0H100V100H0z"/>

shorten-style-attr

  • Default configuration:
{
	"shorten-style-attr": [true, {
		"exchange": false,
		"rmDefault": true
	}]
}
  • Explanation:
    • Shorten style attribute
    • In-depth analysis of the style attribute inheritance chain, removing attributes without applicable objects
    • If there is no style tag, the style and attributes are converted according to the situation
  • Configuration parameters:
    • exchange
      • Default: false
      • Regardless of the existence of the style tag, enforce the mutual conversion of style and attributes
      • Note: svg's style override rules are style attributes > style tags > attributes, so coercion may cause incorrect overrides
    • rmDefault
      • Default: true
      • Remove the same property as the default (only the style property is involved)
      • Some attributes may have different default values for different elements, this rule only verifies a single default value

E.g:

<rect fill="red" style="fill:blue;background:red;"/>

After optimization will become (the fill attribute will be overwritten by the definition of the same name in the style, so it is removed, and the background is not a standard svg style, so it is removed) :

<rect style="fill:blue;"/>

如果 svg 中不存在 style 标签,或 exchange 被设定为 true ,则优化结果为:

<rect fill="blue"/>

shorten-style-tag

  • Default configuration:
{
	"shorten-style-tag": [true, {
		"deepShorten": true,
		"rmDefault": true
	}]
}
  • Explanation:
    • Shorten the content of the style tag
    • Remove duplicate definitions
    • Remove styles that are not in SVG Specification
  • Configuration parameters:
    • deepShorten
      • Default: true
      • Remove invalid selector
      • Merge multiple same selectors
      • Merge multiple same rules
    • rmDefault
      • Default: true
      • Remove the same property as the default (only the style property is involved)
      • Some attributes may have different default values for different elements, this rule only verifies a single default value

Other optimization work

Listed below are the optimizations that this tool actively performs

  • Remove white space between labels
  • Remove nodes of type OtherSect and OtherDecl (see NodeType description below the documentation)
  • Self-closing labels without content
  • Merge all style tags
  • Merge all script tags
  • Merge adjacent text type nodes or CDATA nodes
  • Merge all redundant whitespace characters
  • Remove text child nodes from nodes without text content
  • If "<" is not included in the CDATA node, it will be converted into a normal text node

xml-parser

Introduction

An XML parsing tool is included in the project and can be used directly after installing the project without additional installation.

Use

const xmlParser = require('svg-slimming/xml-parser.js');

xmlParser.parse(xmlcode).then(result => {
	console.log(result);
});

console.log(xmlParser.NodeType);

Where xmlcode is xml text in string format (not limited to svg)

NodeType

Node types follow the definition of the DOM specification as much as possible Reference Document

The specific definitions are as follows:

  • Element Node | Tag

    • value: 1
    • nodeName: <tagName>
    • Contains attributes and childNodes
  • Text Node | Text

    • value: 3
    • nodeName: #text
    • Contains the textContent property
  • CDATA

    • value: 4
    • nodeName: #cdata
    • Contains the textContent property
  • OtherSect

    • value: 5
    • nodeName: #<sectName>
    • Contains the textContent property
    • Refers to blocks other than CDATA, such as <![INCLUDE [...]]>
  • OtherDecl

    • value: 6
    • nodeName: #<declName>
    • Contains the textContent property
    • Refers to declarations other than DocType, such as <!ENTITY...>
  • xml declaration | XMLDecl

    • value: 7
    • nodeName: #xml-decl
    • Contains the textContent property
  • Notes | Comments

    • value: 8
    • nodeName: #comments
    • Contains the textContent property
  • document node | Document

    • value: 9
    • nodeName: #document
    • Contains childNodes attribute
    • The root node object output by xml-parser
  • DocType

    • value: 10
    • nodeName: #doctype
    • Contains the textContent property

Node definition (typescript format)

interface INode {
	nodeName: string;
	nodeType: NodeType;
	namespace?: string;
	textContent?: string;

	readonly attributes?: IAttr[];
	readonly childNodes?: INode[];

	parentNode?: INode;

	cloneNode(): INode;

	appendChild(childNode: INode): void;
	insertBefore(childNode: INode, previousTarget: INode): void;
	replaceChild(childNode: INode, ...children: INode[]): void;
	removeChild(childNode: INode): void;

	hasAttribute(name: string, namespace?: string): boolean;
	getAttribute(name: string, namespace?: string): string;
	setAttribute(name: string, value: string, namespace?: string): void;
	removeAttribute(name: string, namespace?: string): void;
}

Attribute definition (typescript format)

interface IAttr {
	name: string; // Attribute name (without namespace)
	value: string;
	fullname: string; // Attribute full name (including namespace)
	namespace?: string;
}

What are the advantages of this xml parser?

  • Strictly follow the xml specification, it will report an error when it encounters non-compliant xml text, instead of trying to repair
  • Supports parsing xml declaration, doctype, comment, CDATA and other types of nodes
  • XML namespaces will be parsed correctly
  • Attributes of element nodes are correctly parsed, including attributes with namespaces
  • Strictly reflects the content order and format of the original document, and does not do additional things such as text node merge

Package Sidebar

Install

npm i svg-slimming

Weekly Downloads

5

Version

1.5.3

License

MIT

Unpacked Size

857 kB

Total Files

11

Last publish

Collaborators