Skip to content
This repository has been archived by the owner on Oct 30, 2021. It is now read-only.

Latest commit

 

History

History
2011 lines (1612 loc) · 40.3 KB

svgcleaner.adoc

File metadata and controls

2011 lines (1612 loc) · 40.3 KB

List of cleaning options

Elements

Remove XML comments

We can remove all XML comments from SVG document since they are not rendered either way.

Note: all comments from the style attribute will be removed anyway.

CLI argument: --remove-comments

Before (243B) After (194B)
<!-- Comment -->
<svg>
  <!-- Comment -->
  <circle style="/* comment */stroke:black"
          fill="green" cx="50" cy="50" r="45"/>
</svg>
<svg>
  <circle style="stroke:black" fill="green"
          cx="50" cy="50" r="45"/>
</svg>
remove comments
remove comments

Remove XML declarations

Removes XML declarations from SVG document.

svgcleaner will remove all declarations, even though they are only allowed at the start of the document.

CLI argument: --remove-declarations

Before (164B) After (109B)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg/>
<svg/>
remove declarations
remove declarations

Remove non-SVG elements

We can remove any XML elements with non-SVG tag names, since they are not rendered either way.

Note: elements from the SVG Tiny 1.2 and SVG 2.0 (unreleased) will also be removed.

CLI argument: --remove-nonsvg-elements

Before (178B) After (163B)
<svg>
  <myelement/>
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
<svg>
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
remove nonsvg elements
remove nonsvg elements

Remove unused referenced elements

We can remove any referenced elements from the SVG document if no other elements are linked to them.

A link can be established via IRI or FuncIRI.

Also, we can remove any unreferenced elements inside the defs elements, since they are not rendered either way.

Note: the font-face element should be ignored, because it applies to the whole document and not to a specific node.

CLI argument: --remove-unused-defs

Before (637B) After (387B)
<svg>
  <defs>
    <g fill="red">
      <circle id="circle1" fill="url(#rg1)"
              cx="50" cy="50" r="50"/>
      <circle id="circle2" fill="url(#rg2)"
              cx="50" cy="50" r="50"/>
    </g>
    <radialGradient id="rg1">
      <stop offset="0" stop-color="yellow"/>
      <stop offset="1" stop-color="green"/>
    </radialGradient>
    <radialGradient id="rg2">
      <stop offset="0" stop-color="red"/>
      <stop offset="1" stop-color="blue"/>
    </radialGradient>
  </defs>
  <use xlink:href="#circle1"/>
</svg>
<svg>
  <defs>
    <circle id="circle1" fill="url(#rg1)"
            cx="50" cy="50" r="50"/>
    <radialGradient id="rg1">
      <stop offset="0" stop-color="yellow"/>
      <stop offset="1" stop-color="green"/>
    </radialGradient>
    </defs>
  <use xlink:href="#circle1"/>
</svg>
remove unused defs
remove unused defs

Convert basic shapes into paths

All basic shapes can be represented as path.

circle, ellipse and rounded rect are ignored, because their path representation will always be bigger than original.

Note: shapes may render a bit differently depending on your user agent. You can use shape-rendering attribute to tweak it.

CLI argument: --convert-shapes

Before (547B) After (465B)
<svg id="svg1">
  <rect id="rect1" x="10" y="10"
         width="80" height="80"/>
  <line id="line1" stroke="red" x1="10"
        y1="90" x2="90" y2="10"/>
  <polyline id="polyline1" stroke="blue"
            fill="none"
            points="10 10 30 10 30 30
                    50 30 50 50"/>
  <polygon id="polygon1" stroke="green"
              fill="none"
              points="10 10 10 30 30 30
                      30 50 50 50"/>
</svg>
<svg>
  <path id="rect1"
        d="M 10 10 H 90 V 90 H 10 Z"/>
  <path id="line1" stroke="red"
        d="M 10 90 L 90 10"/>
  <path id="polyline1" stroke="blue"
        fill="none"
        d="M 10 10 30 10 30 30
           50 30 50 50"/>
  <path id="polygon1" stroke="green"
        fill="none"
        d="M 10 10 10 30
           30 30 30 50 50 50 Z"/>
</svg>
convert shapes
convert shapes

Remove title element

We can remove all title elements since they are not rendered either way.

But since this element can be used by render software - this action is optional.

CLI argument: --remove-title

Before (191B) After (163B)
<svg>
  <title>svgcleaner</title>
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
<svg>
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
remove title
remove title

Remove desc element

We can remove all desc elements since they are not rendered either way.

But since this element can be used by render software - this action is optional.

CLI argument: --remove-desc

Before (189B) After (163B)
<svg>
  <desc>svgcleaner</desc>
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
<svg>
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
remove desc
remove desc

Remove metadata element

We can remove all metadata elements since they are not rendered either way.

But since this element can be used by render software - this action is optional.

CLI argument: --remove-metadata

Before (580B) After (315B)
<svg xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:cc="http://creativecommons.org/ns#"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
  <metadata id="metadata1">
    <rdf:RDF>
      <cc:Work rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
          rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
        <dc:title/>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:cc="http://creativecommons.org/ns#"
     xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
remove metadata
remove metadata

Remove duplicated linearGradient elements

An SVG can contain a lot of linearGradient elements, which may render exactly the same. So we can remove duplicates and update links in elements, that uses them.

CLI argument: --remove-dupl-lineargradient

Before (721B) After (487B)
<svg>
  <defs>
    <linearGradient id="lg1">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
    <linearGradient id="lg2">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
    <linearGradient id="lg3"
                    xlink:href="#lg2"/>
  </defs>
  <circle fill="url(#lg1)"
          cx="50" cy="50" r="45"/>
  <circle fill="url(#lg2)"
          cx="100" cy="50" r="45"/>
  <circle fill="url(#lg3)"
          cx="150" cy="50" r="45"/>
</svg>
<svg>
  <defs>
    <linearGradient id="lg1">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
  </defs>
  <circle fill="url(#lg1)"
          cx="50" cy="50" r="45"/>
  <circle fill="url(#lg1)"
          cx="100" cy="50" r="45"/>
  <circle fill="url(#lg1)"
          cx="150" cy="50" r="45"/>
</svg>
remove dupl lineargradient
remove dupl lineargradient

Remove duplicated radialGradient elements

An SVG can contain a lot of radialGradient elements, which may render exactly the same. So we can remove duplicates and update links in elements, that uses them.

CLI argument: --remove-dupl-radialgradient

Before (658B) After (424B)
<svg>
  <defs>
    <radialGradient id="rg1">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </radialGradient>
    <linearGradient id="lg1">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
    <radialGradient id="rg2"
                    xlink:href="#lg1"/>
  </defs>
  <circle fill="url(#rg1)"
          cx="50" cy="50" r="45"/>
  <circle fill="url(#rg2)"
          cx="100" cy="50" r="45"/>
</svg>
<svg>
  <defs>
    <radialGradient id="rg1">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </radialGradient>
  </defs>
  <circle fill="url(#rg1)"
          cx="50" cy="50" r="45"/>
  <circle fill="url(#rg1)"
          cx="100" cy="50" r="45"/>
</svg>
remove dupl radialgradient
remove dupl radialgradient

Remove duplicated feGaussianBlur elements

An SVG can contain a lot of feGaussianBlur elements, which may render exactly the same. So we can remove duplicates and update links in elements, that uses them.

CLI argument: --remove-dupl-fegaussianblur

Before (439B) After (363B)
<svg>
  <defs>
    <filter id='f1'>
      <feGaussianBlur stdDeviation='2'/>
    </filter>
    <filter id='f2'>
      <feGaussianBlur stdDeviation='2'/>
    </filter>
  </defs>
  <circle filter="url(#f1)" fill="green"
          cx="50" cy="50" r="45"/>
  <circle filter="url(#f2)" fill="green"
          cx="100" cy="50" r="45"/>
</svg>
<svg>
  <defs>
    <filter id='f1'>
      <feGaussianBlur stdDeviation='2'/>
    </filter>
  </defs>
  <circle filter="url(#f1)" fill="green"
          cx="50" cy="50" r="45"/>
  <circle filter="url(#f1)" fill="green"
          cx="100" cy="50" r="45"/>
</svg>
remove dupl fegaussianblur
remove dupl fegaussianblur

Ungroup groups

Groups, aka g element, is one of the main SVG structure blocks, but in a lot of cases they do not impact rendering at all.

Groups are useless: - if the group is empty - if the group has only one children - if the group doesn’t have any important attributes

Then we can ungroup it and remove.

CLI argument: --ungroup-groups

Before (276B) After (234B)
<svg>
  <g>
    <circle fill="green" r="45"
            cx="50" cy="50"/>
    <g>
      <circle fill="#023373" r="45"
              cx="100" cy="50"/>
    </g>
  </g>
</svg>
<svg>
  <circle fill="green" r="45"
          cx="50" cy="50"/>
  <circle fill="#023373" r="45"
          cx="100" cy="50"/>
</svg>
ungroup groups
ungroup groups

Ungroup defs element

If the defs element contains only referenced elements - it can be ungrouped.

Unsupported by: QtSvg ⇐ 5.7 (pattern with image child renders incorrectly)

CLI argument: --ungroup-defs

Before (361B) After (330B)
<svg>
  <defs>
    <radialGradient id="rg1">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </radialGradient>
  </defs>
  <circle fill="url(#rg1)" r="45"
          cx="50" cy="50"/>
</svg>
<svg>
  <radialGradient id="rg1">
    <stop offset="0"
          stop-color="yellow"/>
    <stop offset="1"
          stop-color="green"/>
  </radialGradient>
  <circle fill="url(#rg1)" r="45"
          cx="50" cy="50"/>
</svg>
ungroup defs
ungroup defs

Group elements by equal styles

If a continuous range of elements contains equal, inheritable attributes - we can group such elements and move this attributes to a new or an existing parent group.

Note: this option is mostly poinless when XML indent is enabled, so you should use it with Sets XML nodes indent/--indent option equal to -1 or 0.

CLI argument: --group-by-style

Before (291B) After (290B)
<svg>
  <circle fill="green" r="45"
          cx="50" cy="50"/>
  <circle fill="green" r="45"
          cx="100" cy="50"/>
  <circle fill="green" r="45"
          cx="150" cy="50"/>
</svg>
<svg>
  <g fill="green">
    <circle r="45"
            cx="50" cy="50"/>
    <circle r="45"
            cx="100" cy="50"/>
    <circle r="45"
            cx="150" cy="50"/>
  </g>
</svg>
group by style
group by style

Merge gradients

Many SVG editors split gradient implementation into two parts: one element with stop children elements and one that linked to it. It can be useful if we have a lot of gradients with equal stop’s, but if we have only one - it became pointless.

This option fixes it.

CLI argument: --merge-gradients

Before (430B) After (361B)
<svg>
  <defs>
    <linearGradient id="lg1">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
    <linearGradient id="lg2"
                    xlink:href="#lg1"/>
  </defs>
  <circle fill="url(#lg2)"
          cx="50" cy="50" r="45"/>
</svg>
<svg>
  <defs>
    <linearGradient id="lg2">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
  </defs>
  <circle fill="url(#lg2)"
          cx="50" cy="50" r="45"/>
</svg>
merge gradients
merge gradients

Regroup gradient stop elements

If two or more gradients have equal stop elements - we can move this elements into a new linearGradient and link gradients to this new gradient.

CLI argument: --regroup-gradient-stops

Before (589B) After (522B)
<svg>
  <defs>
    <linearGradient id="lg1">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
    <linearGradient id="lg2">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
  </defs>
  <circle fill="url(#lg1)"
          cx="50" cy="50" r="45"/>
  <circle fill="url(#lg2)"
          cx="100" cy="50" r="45"/>
</svg>
<svg>
  <defs>
    <linearGradient id="lg3">
      <stop offset="0"
            stop-color="yellow"/>
      <stop offset="1"
            stop-color="green"/>
    </linearGradient>
    <linearGradient id="lg1" xlink:href="#lg3"/>
    <linearGradient id="lg2" xlink:href="#lg3"/>
  </defs>
  <circle fill="url(#lg1)"
          cx="50" cy="50" r="45"/>
  <circle fill="url(#lg2)"
          cx="100" cy="50" r="45"/>
</svg>
regroup gradient stops
regroup gradient stops

Remove invalid stop elements

We can remove duplicated stop elements inside gradients.

CLI argument: --remove-invalid-stops

Before (528B) After (387B)
<svg>
  <defs>
    <linearGradient id="lg1">
       <stop offset="-1" stop-color="yellow"/>
       <stop offset="0" stop-color="yellow"/>
       <stop offset="0.5" stop-color="green"/>
       <stop offset="0.5" stop-color="green"/>
       <stop offset="1" stop-color="yellow"/>
       <stop offset="10" stop-color="yellow"/>
    </linearGradient>
  </defs>
  <circle fill="url(#lg1)"
          cx="50" cy="50" r="45"/>
</svg>
<svg>
  <defs>
    <linearGradient id="lg1">
       <stop offset="0" stop-color="yellow"/>
       <stop offset="0.5" stop-color="green"/>
       <stop offset="1" stop-color="yellow"/>
    </linearGradient>
  </defs>
  <circle fill="url(#lg1)"
          cx="50" cy="50" r="45"/>
</svg>
remove invalid stops
remove invalid stops

Remove invisible elements

The collection of algorithms that detects invisible elements and removes them.

Unsupported by: QtSvg ⇐ 5.7

CLI argument: --remove-invisible-elements

Before (335B) After (173B)
<svg>
  <linearGradient id="lg1"/>
  <clipPath id="cp1"/>
  <circle fill="green"
          cx="50" cy="50" r="45"/>
  <circle fill="green" clip-path="url(#cp1)"
          stroke="url(#lg1)"
          cx="100" cy="50" r="45"/>
</svg>
<svg>
  <circle fill="green"
          cx="50" cy="50" r="45"/>
</svg>
remove invisible elements
remove invisible elements

Resolve use elements

We can replace use element with linked element if it used only by this use.

CLI argument: --resolve-use

Before (252B) After (196B)
<svg>
  <defs>
    <circle id='circle1'
            fill="green" cx="50"
            cy="50" r="45"/>
  </defs>
  <use xlink:href='#circle1'/>
</svg>
<svg>
  <circle id='circle1'
          fill="green" cx="50"
          cy="50" r="45"/>
</svg>
resolve use
resolve use

Attributes

Remove version and baseProfile attributes

Remove version and baseProfile attributes from the svg element.

Some applications can rely on them, so someone may want to keep them. Even though they usually useless.

CLI argument: --remove-version

Before (206B) After (173B)
<svg version="1.1" baseProfile="tiny">
  <circle fill="green"
          cx="50" cy="50" r="45"/>
</svg>
<svg>
  <circle fill="green"
          cx="50" cy="50" r="45"/>
</svg>
remove version
remove version

Remove non-SVG attributes

We can remove any non-SVG attributes since they are not rendered either way.

Note: attributes from the SVG Tiny 1.2 and SVG 2.0 (unreleased) will also be removed.

CLI argument: --remove-nonsvg-attributes

Before (192B) After (173B)
<svg>
  <circle fill="green" my-attribute="hi!"
          cx="50" cy="50" r="45"/>
</svg>
<svg>
  <circle fill="green"
          cx="50" cy="50" r="45"/>
</svg>
remove nonsvg attributes
remove nonsvg attributes

Remove unreferenced id attributes

We can remove id attribute from an element if this id doesn’t use in any IRI/FuncIRI.

Note: since svgcleaner works only with static/local SVG data and does not support SVG scripting via script element, we can only assume that id is not used.

CLI argument: --remove-unreferenced-ids

Before (319B) After (286B)
<svg id="svg1">
  <circle id="circle1" fill="green"
          cx="50" cy="50" r="50"/>
  <circle id="circle2" fill="#023373"
          cx="100" cy="50" r="50"/>
  <use id="use1" x="100" xlink:href="#circle1"/>
</svg>
<svg>
  <circle id="circle1" fill="green"
          cx="50" cy="50" r="50"/>
  <circle fill="#023373"
          cx="100" cy="50" r="50"/>
  <use x="100" xlink:href="#circle1"/>
</svg>
remove unreferenced ids
remove unreferenced ids

Trim id attributes

Renames elements id attribute to a shorter one. All IRI and FuncIRI will be updated too.

Shorter name generated by encoding a serial number of this id attribute using a range of acceptable chars: a-zA-Z0-9. Given that first char can’t be 0-9.

For example: 1 → a, 51 → aa, 113 → ba and so on.

CLI argument: --trim-ids

Before (521B) After (450B)
<svg id="svg1">
  <defs id="defs1">
    <linearGradient id="linearGradient1">
      <stop id="stop1" offset="0"
            stop-color="yellow"/>
      <stop id="stop2" offset="1"
            stop-color="green"/>
    </linearGradient>
    <radialGradient id="radialGradient1"
                    xlink:href="#linearGradient1"/>
  </defs>
  <circle fill="url(#radialGradient1)"
          cx="50" cy="50" r="45"/>
</svg>
<svg id="a">
  <defs id="b">
    <linearGradient id="c">
      <stop id="d" offset="0"
            stop-color="yellow"/>
      <stop id="e" offset="1"
            stop-color="green"/>
    </linearGradient>
    <radialGradient id="f"
                    xlink:href="#c"/>
  </defs>
  <circle fill="url(#f)"
          cx="50" cy="50" r="45"/>
</svg>
trim ids
trim ids

We can remove text-related attributes, when there is no text.

But since attributes like a font can impact a length values with a em/ex units - it’s a bit more complicated. Also, the text itself can be defined in many different ways.

CLI argument: --remove-text-attributes

Before (247B) After (232B)
<svg>
  <circle fill="green" font="Verdana"
          cx="50" cy="50" r="45"/>
  <text y="30" x="30" font-size="14pt">
    Text
  </text>
</svg>
<svg>
  <circle fill="green"
          cx="50" cy="50" r="45"/>
  <text y="30" x="30" font-size="14pt">
    Text
  </text>
</svg>
remove text attributes
remove text attributes

Remove unused coordinate attributes

Many of coordinate attributes can be calculated using their neighbor attributes, so there is no need to keep them.

CLI argument: --remove-unused-coordinates

Before (207B) After (199B)
<svg>
  <rect x="10" y="10" width="80"
        height="80" fill="green"
        rx="10" ry="10"/>
</svg>
<svg>
  <rect x="10" y="10" width="80"
        height="80" fill="green"
        rx="10"/>
</svg>
remove unused coordinates
remove unused coordinates

Remove attributes with default values

We can remove attributes with default values if they are not covered by the parent elements. Some attributes do not support an inheritance, so we can remove them without checking a parent elements.

In the example below we have a circle element with a fill and a stroke attributes, which have default values. We can’t remove a fill from a circle, because than the rect will be filled with a red, but a stroke can be easily removed.

CLI argument: --remove-default-attributes

Before (215B) After (201B)
<svg>
  <g fill="red">
    <circle fill="black" stroke="none"
            cx="50" cy="50" r="45"/>
  </g>
</svg>
<svg>
  <g fill="red">
    <circle fill="black" cx="50"
            cy="50" r="45"/>
  </g>
</svg>
remove default attributes
remove default attributes

We can remove a xmlns:xlink attribute if document doesn’t use an element referencing via the xlink:href.

CLI argument: --remove-xmlns-xlink-attribute

Before (163B) After (120B)
<svg xmlns:xlink="http://www.w3.org/1999/xlink">
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
<svg>
  <circle fill="green" cx="50" cy="50" r="45"/>
</svg>
remove xmlns xlink attribute
remove xmlns xlink attribute

Remove attributes that doesn’t belong to this element

Remove attributes that doesn’t belong to current element and have no effect on rendering.

Unlike other cleaning options for attributes, this does not change attributes that can be used during rendering.

CLI argument: --remove-needless-attributes

Before (358B) After (266B)
<svg>
  <clipPath id="cp1">
    <rect fill="red" stroke="red"
          stroke-width="50" width="75"
          height="75"/>
  </clipPath>
  <circle fill="green" d="M 10 20 L 30 40"
          clip-path="url(#cp1)"
          cx="50" cy="50" r="45"/>
</svg>
<svg>
  <clipPath id="cp1">
    <rect width="75" height="75"/>
  </clipPath>
  <circle fill="green" clip-path="url(#cp1)"
          cx="50" cy="50" r="45"/>
</svg>
remove needless attributes
remove needless attributes

Remove inheritable gradient attributes

Gradients can inherit attributes via xlink:href attribute, so we can remove attributes that already defined in the parent gradient.

Currently, only an gradientUnits attribute is processed.

Unsupported by: QtSvg ⇐ 5.7, Inkscape ⇐ 0.91 r13725

CLI argument: --remove-gradient-attributes

Before (641B) After (530B)
<svg>
    <linearGradient id="lg1"
      gradientUnits='userSpaceOnUse'>
      <stop offset="0"
        stop-color="yellow"/>
      <stop offset="1"
        stop-color="green"/>
    </linearGradient>
    <linearGradient id="lg2"
      gradientUnits='userSpaceOnUse'
      xlink:href="#lg1"/>
    <linearGradient id="lg3"
      gradientUnits='userSpaceOnUse'
      xlink:href="#lg2"/>
    <radialGradient id="rg1"
      gradientUnits='userSpaceOnUse'
      xlink:href="#lg3"/>
  <circle fill="url(#rg1)"
    cx="50" cy="50" r="45"/>
</svg>
<svg>
    <linearGradient id="lg1"
      gradientUnits='userSpaceOnUse'>
      <stop offset="0"
        stop-color="yellow"/>
      <stop offset="1"
        stop-color="green"/>
    </linearGradient>
    <linearGradient id="lg2"
      xlink:href="#lg1"/>
    <linearGradient id="lg3"
      xlink:href="#lg2"/>
    <radialGradient id="rg1"
      xlink:href="#lg3"/>
  <circle fill="url(#rg1)"
    cx="50" cy="50" r="45"/>
</svg>
remove gradient attributes
remove gradient attributes

Join presentational attributes

SVG presentational attributes can be set via separated attributes and via style attribute. If we have less than 5 presentational attributes - it’s better to store them separately. Otherwise style is shorter.

Possible values:

  • no - do not join presentational attributes

  • some - join presentational attributes when there are 6 or more of them

  • all - join all presentational attributes. May produce a bigger file but can be used as a workaround of some viewers bugs.

Default: some

There is no example, because a style with 5 attributes will be a huge, nonbreakable line, which will break the layout.

Apply transformations to gradients

Transformations that contain only translate, rotate and/or proportional scale parts can be applied to some gradients.

CLI argument: --apply-transform-to-gradients

Before (460B) After (414B)
<svg>
  <linearGradient id="lg1" x1="40" y1="30"
          x2="90" y2="30"
          gradientTransform="translate(10 20)"
          gradientUnits="userSpaceOnUse">
    <stop offset="0"
          stop-color="yellow"/>
    <stop offset="1"
          stop-color="green"/>
  </linearGradient>
  <circle fill="url(#lg1)"
          cx="50" cy="50" r="45"/>
</svg>
<svg>
  <linearGradient id="lg1" x1="50" y1="50"
          x2="100" y2="50"
          gradientUnits="userSpaceOnUse">
    <stop offset="0"
          stop-color="yellow"/>
    <stop offset="1"
          stop-color="green"/>
  </linearGradient>
  <circle fill="url(#lg1)"
          cx="50" cy="50" r="45"/>
</svg>
apply transform to gradients
apply transform to gradients

Apply transformations to shapes

Transformations that contain only translate, rotate and/or proportional scale parts can be applied to some shapes.

This option will apply transformations to: rect, circle, ellipse and line.

CLI argument: --apply-transform-to-shapes

Before (238B) After (190B)
<svg>
  <circle fill="green" stroke-width='0'
          transform="translate(10 10) scale(2)"
          cx="20" cy="20" r="22"/>
</svg>
<svg>
  <circle fill="green" stroke-width='0'
          cx="50" cy="50" r="44"/>
</svg>
apply transform to shapes
apply transform to shapes

Remove unresolved classes from class attributes

The class attribute can contain a list of class selectors, but not all of them may link to the style sheet defined in the file.

This option will remove such selectors.

Note: you can’t prevent class attribute resolving anyway. This option should be used just to keep unresolved classes in the class attribute when you define them elsewhere. So you should disable it to get such behavior.

CLI argument: --remove-unresolved-classes

Before (246B) After (173B)
<svg id="svg1">
  <style>
    .fill1 {fill:green}
  </style>
  <circle class="fill1 stroke1 other"
          cx="50" cy="50" r="50"/>
</svg>
<svg>
  <circle fill="green"
          cx="50" cy="50" r="50"/>
</svg>
remove unresolved classes
remove unresolved classes

Paths

Convert path segments into relative ones

Since segments of the path data can be set in absolute and relative coordinates - we can convert all of them into relative one, which is generally shorter.

CLI argument: --paths-to-relative

Before (285B) After (276B)
<svg>
  <path d="M 750 150 L 800 200 L 850 150
           L 850 250 L 850 350 L 800 300
           L 750 350 L 750 250 Z"
        transform="scale(0.1)"
        fill="green"/>
</svg>
<svg>
  <path d="m 750 150 l 50 50 l 50 -50
           l 0 100 l 0 100 l -50 -50
           l -50 50 l 0 -100 z"
        transform="scale(0.1)"
        fill="green"/>
</svg>
paths to relative
paths to relative

Remove unused path segments

The collection of algorithms that removes unneeded segments from paths.

NOTE: can be used only with --paths-to-relative.

CLI argument: --remove-unused-segments

Before (190B) After (157B)
<svg>
  <path stroke="red"
        d="M 10 10 L 10 50 L 10 10 M 50 50 L 50 50"/>
</svg>
<svg>
  <path stroke="red" d="M 10 10 V 50 Z"/>
</svg>
remove unused segments
remove unused segments

Convert path segments into shorter ones

Some segments can be represented using different segment types keeping a resulting shape exactly the same. We only use conversions that make path notation shorter.

Currently supported conversions are:

  • LineTo → HorizontalLineTo

  • LineTo → VerticalLineTo

  • CurveTo → HorizontalLineTo

  • CurveTo → VerticalLineTo

  • CurveTo → LineTo

  • CurveTo → SmoothCurveTo

CLI argument: --convert-segments

Before (264B) After (246B)
<svg>
  <path fill="none" stroke="red"
        stroke-width="2"
        d="M 10 15 C 10 15 72.5 10 72.5 55
           C 72.5 100 135 100 135 55 L 10 55"/>
</svg>
<svg>
  <path fill="none" stroke="red"
        stroke-width="2"
        d="M 10 15 S 72.5 10 72.5 55
           S 135 100 135 55 H 10"/>
</svg>
convert segments
convert segments

Apply transformations to paths

Transformations that contain only translate, rotate and/or proportional scale parts can be applied to some paths.

This usually creates bigger files, so it’s disabled by default. But it some cases it can be useful.

CLI argument: --apply-transform-to-paths

Before (202B) After (166B)
<svg>
  <path stroke="red"
        transform="translate(10 20)"
        d="M 10 0 L 30 40"/>
</svg>
<svg>
  <path stroke="red"
        d="M 20 20 L 40 60"/>
</svg>
apply transform to paths
apply transform to paths

Use compact notation for paths

By SVG spec we are allowed to remove some symbols from path notation without breaking parsing.

CLI argument: --trim-paths

Before (250B) After (226B)
<svg>
  <path fill="green" stroke="red"
        stroke-width="2"
        d="M 30 60 a 25 25 -30 1 1 50,-20
           l 0.5 0.5 l 30 60 z"/>
</svg>
<svg>
  <path fill="green" stroke="red"
        stroke-width="2"
        d="M30 60a25 25-30 1 1 50-20l.5.5l30 60z"/>
</svg>
trim paths
trim paths

Join ArcTo flags

Elliptical arc curve segment has flags parameters, which can have values of 0 or 1. Since we have fixed-width values, we can skip spaces between them.

Unsupported by: Inkscape ⇐ 0.91 r13725, QtSvg ⇐ 5.7, librsvg ⇐ 2.40.13

CLI argument: --join-arcto-flags

Before (230B) After (228B)
<svg>
  <path fill="green" stroke="red"
        stroke-width="2"
        d="M 30 60
           a 25 25 -30 1 1 50 -20"/>
</svg>
<svg>
  <path fill="green" stroke="red"
        stroke-width="2"
        d="M 30 60
           a 25 25 -30 1150 -20"/>
</svg>
join arcto flags
join arcto flags

Remove subsequent segments command from paths

If path segment has the same type as previous - we can skip command specifier.

CLI argument: --remove-dupl-cmd-in-paths

Before (240B) After (234B)
<svg>
  <path d="M 10 10 L 90 10 L 90 90
           L 10 90 L 10 10 z"
        fill="none" stroke="red"
        stroke-width="2"/>
</svg>
<svg>
  <path d="M 10 10 L 90 10 90 90
           10 90 10 10 z"
        fill="none" stroke="red"
        stroke-width="2"/>
</svg>
remove dupl cmd in paths
remove dupl cmd in paths

Use implicit LineTo commands

By SVG spec: 'if a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands'.

CLI argument: --use-implicit-cmds

Before (213B) After (209B)
<svg>
  <path fill="green" stroke="red"
        stroke-width="2"
        d="M 10 10 L 50 50 L 120 50"/>
</svg>
<svg>
  <path fill="green" stroke="red"
        stroke-width="2"
        d="M 10 10 50 50 120 50"/>
</svg>
use implicit cmds
use implicit cmds

Output

Use #RGB notation

Use #RGB notation instead of #RRGGBB when possible.

NOTE: by default all color stored as #RRGGBB, since libsvgdom doesn’t stores colors original text representation.

CLI argument: --trim-colors

Before (165B) After (162B)
<svg>
  <circle fill="#00ff00" cx="50" cy="50" r="45"/>
</svg>
<svg>
  <circle fill="#0f0" cx="50" cy="50" r="45"/>
</svg>
trim colors
trim colors

Append newline

Ensures that the output file has a newline at the end of the file, following the POSIX standard for text files. There is no visual change in the image, but it will behave better with command-line tools, and won’t show warnings when viewed on GitHub. Disabled by default because it slightly increases the file size.

CLI argument: --append-newline

Before (209B) After (210B)
<svg>
  <circle fill="green" cx="50"
          cy="50" r="45"
          transform="translate(25)"/>
</svg> # Error: No newline at end of file.
<svg>
  <circle fill="green" cx="50"
          cy="50" r="45"
          transform="translate(25)"/>
</svg>
simplify transforms
append newline

Simplify transform matrices

Simplify transform matrices into short equivalent when possible.

CLI argument: --simplify-transforms

Before (216B) After (209B)
<svg>
  <circle fill="green" cx="50"
          cy="50" r="45"
          transform="matrix(1 0 0 1 25 0)"/>
</svg>
<svg>
  <circle fill="green" cx="50"
          cy="50" r="45"
          transform="translate(25)"/>
</svg>
simplify transforms
simplify transforms

Set coordinates numeric precision

Reduce the numeric precision of the specific coordinate attributes.

This includes: x, y, dx, dy, x1, y1, x2, y2, r, rx, ry, cx, cy, fx, fy, width, height, and translate part of transforms.

Range: 1..12

Default: 6

Set properties numeric precision

Reduce the numeric precision of the specific properties attributes.

This includes: stroke-dashoffset, stroke-miterlimit, stroke-width, opacity, fill-opacity, flood-opacity, stroke-opacity, stop-opacity, font-size.

Range: 1..12

Default: 6

Set transforms values numeric precision

Set numeric precision of the a, b, c, d values of transforms.

Range: 1..12

Default: 8

Set path’s coordinates numeric precision

We can reduce the numeric precision of path’s coordinates without breaking it.

Range: 1..12, where

  • 8..12 is basically lossless

  • 4..7 will give an actual impact on the file size

  • 1..3 is very dangerous and will probably break your file

Default: 8

CLI argument: --paths-coordinates-precision

Before (285B) After (272B)
<svg>
  <path d="M 10.000001 10.000005
           L 89.99999 10.11111
           L 89.997777 90.0005
           L 10.123456789 90 L 10 10 z"
        fill="none" stroke="red"/>
</svg>
<svg>
  <path d="M 10 10.00001
           L 89.99999 10.11111
           L 89.99778 90.0005
           L 10.12346 90 L 10 10 z"
        fill="none" stroke="red"/>
</svg>
paths coordinates precision
paths coordinates precision

Set number list separator

Set separator for attributes with number list values. Like stroke-dasharray or points.

Possible values:

  • space

  • comma

  • comma-space

Default: space

CLI argument: --list-separator

Before (173B) After (168B)
<svg>
  <polygon fill="green" points="10, 10, 10, 30, 30, 30"/>
</svg>
<svg>
  <polygon fill="green" points="10 10 10 30 30 30"/>
</svg>
list separator
list separator

Set XML nodes indent

Set indent for XML nodes.

  • none - no indention and new lines

  • 0 - no indention

  • 1..4 - indent with n spaces

  • tabs - indent with tabs

Default: none

CLI argument: --indent

Before (178B) After (166B)
<svg>
  <g>
    <circle fill="green" cx="50" cy="50" r="45"/>
  </g>
</svg>
<svg><g><circle fill="green" cx="50" cy="50" r="45"/></g></svg>
indent
indent

Other

Reset default flags to no

Most of the cleaning options are enabled by default. This flag allows to disable them all at once.

It can be useful if you need only few cleaning options.

Note that this flag applies only to options with the <FLAG> type. Options like indent will still use default values.

CLI argument: --no-defaults