Skip to content

使用 SVGO 优化图标

此函数属于 Iconify Tools 中的 图标操作函数 的一部分。

函数 runSVGO() 使用流行的 SVG 优化工具 SVGO 来优化图标。

它旨在用于已经通过 cleanupSVG() 处理过的图标,该函数会完成大部分的清理工作。

此函数用于执行 SVGO 擅长的高级操作:转换变换、清理数值、移除未使用的 SVG 元素等。

插件

默认情况下,该函数使用预配置的 SVGO 插件列表,其中排除了一些存在缺陷的插件。

如果图标包含 SVG 动画,则会排除修改形状的插件。

用法

该函数具有以下参数:

  • svgSVG。图标实例。
  • optionsobject。选项(可选)。

选项

设置选项有两种方式:

  • 使用自定义的 SVGO 插件列表。
  • 通过多个选项切换插件组。

自定义插件列表

你可以使用选项的 plugins 属性来设置自定义插件。该值是一个插件数组,将直接传递给 SVGO(请参阅 SVGO 文档)。

示例:

tsrunSVGO(svg, {
   plugins: ['convertStyleToAttrs', 'inlineStyles'],
   multipass: true,
});

插件选项

你也可以通过设置以下选项从预设的插件列表中进行选择:

  • animatedboolean。如果为 true,则不会使用已知在处理动画图标时会出现问题的 SVGO 插件。
  • keepShapesboolean。如果为 true,则不会使用修改形状的插件。如果你需要保持形状原样(例如在对形状进行动画处理时),这会很有用,但它不如设置 animated 选项那么严格。
  • cleanupIDsstring|false|function。用于重写 ID 的自定义前缀,设置为 false 可禁用更改 ID 的插件。也可以是一个回调函数,根据旧 ID 返回新 ID。

这些选项不能与 plugins 选项同时使用。

其他选项

可与上述任何选项配合使用的选项:

  • multipassboolean。如果为 true,插件将运行多次以获得更好的优化效果。默认启用。

示例

svgo.ts
tsimport { SVG, runSVGO } from '@iconify/tools';

const reallyBadIcon = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<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#"
  xmlns:svg="http://www.w3.org/2000/svg"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  width="2048"
  height="2048"
  id="svg3891"
  version="1.1"
  inkscape:version="0.91 r13725"
  sodipodi:docname="trash.svg"
  inkscape:export-filename="/home/nikku/camunda/projects/bpmn.io/bpmn-font/raw/trash.png"
  inkscape:export-xdpi="0.88"
  inkscape:export-ydpi="0.88">
 <defs
    id="defs3893">
   <inkscape:path-effect
      effect="spiro"
      id="path-effect4094"
      is_visible="true" />
   <inkscape:path-effect
      effect="spiro"
      id="path-effect4094-0"
      is_visible="true" />
 </defs>
 <sodipodi:namedview
    id="base"
    pagecolor="#ffffff"
    bordercolor="#666666"
    borderopacity="1.0"
    inkscape:pageopacity="0.0"
    inkscape:pageshadow="2"
    inkscape:zoom="0.175"
    inkscape:cx="307.67263"
    inkscape:cy="1030.7415"
    inkscape:document-units="px"
    inkscape:current-layer="layer1-6"
    showgrid="false"
    inkscape:window-width="1596"
    inkscape:window-height="807"
    inkscape:window-x="0"
    inkscape:window-y="91"
    inkscape:window-maximized="0"
    inkscape:snap-page="false"
    inkscape:snap-object-midpoints="false"
    inkscape:snap-nodes="false"
    inkscape:snap-to-guides="false"
    inkscape:snap-grids="false" />
 <metadata
    id="metadata3896">
   <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>
 <g
    inkscape:label="Layer 1"
    inkscape:groupmode="layer"
    id="layer1"
    transform="translate(0,995.63783)">
   <g
      transform="matrix(96.752895,0,0,96.752895,55.328158,-100816.34)"
      id="layer1-6"
      inkscape:label="Layer 1"
      style="display:inline">
     <path
        style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.343629;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
        d="m 3.4296875,1038.3672 1.3325877,12.7308 10.5912408,0 1.228186,-12.7284 -13.1520736,0 z m 1.4921875,1.3437 10.185547,0 -0.972656,10.0411 -8.1582035,0 z"
        id="rect4089"
        inkscape:connector-curvature="0"
        sodipodi:nodetypes="ccccccccccc" />
     <g
        id="g4275"
        transform="matrix(1,0,0,0.90111263,0,103.41515)">
       <path
          sodipodi:nodetypes="cc"
          inkscape:connector-curvature="0"
          inkscape:original-d="m 7.0333918,1040.9794 0.9432241,7.504"
          inkscape:path-effect="#path-effect4094"
          id="path4092"
          d="m 7.0333918,1040.9794 0.9432241,7.504"
          style="fill:none;stroke:#000000;stroke-width:1.343629;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
       <path
          sodipodi:nodetypes="cc"
          inkscape:connector-curvature="0"
          inkscape:original-d="m 12.990235,1040.9794 -0.943224,7.504"
          inkscape:path-effect="#path-effect4094-0"
          id="path4092-2"
          d="m 12.990235,1040.9794 -0.943224,7.504"
          style="fill:none;stroke:#000000;stroke-width:1.343629;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
     </g>
     <path
        style="fill:#000000;fill-opacity:1;stroke:none"
        d="m 7.2638322,1035.194 -4.2854023,1.2542 0,0.6276 14.0667651,0 0,-0.6276 -4.337726,-1.2542 z"
        id="rect4121"
        inkscape:connector-curvature="0"
        sodipodi:nodetypes="ccccccc" />
     <path
        style="display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.72291225;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
        d="m 7.6269598,1033.8929 4.7697062,0 0,1.737 -4.7697062,0 z"
        id="rect4121-6" />
   </g>
 </g>
</svg>`
;

const svg = new SVG(reallyBadIcon);
runSVGO(svg);
console.log(svg.toMinifiedString());
结果:
svg<svg xmlns="http://www.w3.org/2000/svg" width="2048" height="2048" viewBox="0 0 2048 2048"><metadata/><path d="m3.43 1038.367 1.332 12.731h10.592l1.228-12.728H3.43zm1.492 1.344h10.185l-.972 10.041H5.977z" color="#000" enable-background="accumulate" font-family="sans-serif" overflow="visible" style="line-height:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;block-progression:tb;white-space:normal;isolation:auto;mix-blend-mode:normal" transform="translate(55.328 -99820.702) scale(96.7529)"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.344" d="m7.033 1040.98.944 7.503m5.013-7.503-.943 7.503" transform="matrix(96.7529 0 0 87.185 55.328 -89815)"/><path d="M758.141 337.32 343.458 458.648v60.76h1361.023v-60.76L1284.767 337.32z"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="69.952" d="M793.262 211.444h461.512v168.06H793.262z"/></svg>

该示例展示了在未经清理和验证的图标上运行 SVGO 的情况。并非所有无用属性都已被移除,且 SVGO 不会检查图标中不应包含的某些内容,例如文本、光栅图像和事件。

因此,所有图标在加载后都必须进行清理。

带有清理操作的相同代码:

svgo.ts
tsimport { SVG, runSVGO, cleanupSVG } from '@iconify/tools';

const reallyBadIcon = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<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#"
  xmlns:svg="http://www.w3.org/2000/svg"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  width="2048"
  height="2048"
  id="svg3891"
  version="1.1"
  inkscape:version="0.91 r13725"
  sodipodi:docname="trash.svg"
  inkscape:export-filename="/home/nikku/camunda/projects/bpmn.io/bpmn-font/raw/trash.png"
  inkscape:export-xdpi="0.88"
  inkscape:export-ydpi="0.88">
 <defs
    id="defs3893">
   <inkscape:path-effect
      effect="spiro"
      id="path-effect4094"
      is_visible="true" />
   <inkscape:path-effect
      effect="spiro"
      id="path-effect4094-0"
      is_visible="true" />
 </defs>
 <sodipodi:namedview
    id="base"
    pagecolor="#ffffff"
    bordercolor="#666666"
    borderopacity="1.0"
    inkscape:pageopacity="0.0"
    inkscape:pageshadow="2"
    inkscape:zoom="0.175"
    inkscape:cx="307.67263"
    inkscape:cy="1030.7415"
    inkscape:document-units="px"
    inkscape:current-layer="layer1-6"
    showgrid="false"
    inkscape:window-width="1596"
    inkscape:window-height="807"
    inkscape:window-x="0"
    inkscape:window-y="91"
    inkscape:window-maximized="0"
    inkscape:snap-page="false"
    inkscape:snap-object-midpoints="false"
    inkscape:snap-nodes="false"
    inkscape:snap-to-guides="false"
    inkscape:snap-grids="false" />
 <metadata
    id="metadata3896">
   <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>
 <g
    inkscape:label="Layer 1"
    inkscape:groupmode="layer"
    id="layer1"
    transform="translate(0,995.63783)">
   <g
      transform="matrix(96.752895,0,0,96.752895,55.328158,-100816.34)"
      id="layer1-6"
      inkscape:label="Layer 1"
      style="display:inline">
     <path
        style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.343629;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
        d="m 3.4296875,1038.3672 1.3325877,12.7308 10.5912408,0 1.228186,-12.7284 -13.1520736,0 z m 1.4921875,1.3437 10.185547,0 -0.972656,10.0411 -8.1582035,0 z"
        id="rect4089"
        inkscape:connector-curvature="0"
        sodipodi:nodetypes="ccccccccccc" />
     <g
        id="g4275"
        transform="matrix(1,0,0,0.90111263,0,103.41515)">
       <path
          sodipodi:nodetypes="cc"
          inkscape:connector-curvature="0"
          inkscape:original-d="m 7.0333918,1040.9794 0.9432241,7.504"
          inkscape:path-effect="#path-effect4094"
          id="path4092"
          d="m 7.0333918,1040.9794 0.9432241,7.504"
          style="fill:none;stroke:#000000;stroke-width:1.343629;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
       <path
          sodipodi:nodetypes="cc"
          inkscape:connector-curvature="0"
          inkscape:original-d="m 12.990235,1040.9794 -0.943224,7.504"
          inkscape:path-effect="#path-effect4094-0"
          id="path4092-2"
          d="m 12.990235,1040.9794 -0.943224,7.504"
          style="fill:none;stroke:#000000;stroke-width:1.343629;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
     </g>
     <path
        style="fill:#000000;fill-opacity:1;stroke:none"
        d="m 7.2638322,1035.194 -4.2854023,1.2542 0,0.6276 14.0667651,0 0,-0.6276 -4.337726,-1.2542 z"
        id="rect4121"
        inkscape:connector-curvature="0"
        sodipodi:nodetypes="ccccccc" />
     <path
        style="display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.72291225;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
        d="m 7.6269598,1033.8929 4.7697062,0 0,1.737 -4.7697062,0 z"
        id="rect4121-6" />
   </g>
 </g>
</svg>`
;

const svg = new SVG(reallyBadIcon);

// Clean up and validate icon
cleanupSVG(svg);

// Optimise icon
runSVGO(svg);

console.log(svg.toMinifiedString());
结果:
svg<svg xmlns="http://www.w3.org/2000/svg" width="2048" height="2048" viewBox="0 0 2048 2048"><path d="m387.19 644.317 128.875 1231.76h1024.807l118.813-1231.47H387.19zm144.356 130.035h985.428l-94.044 971.496H633.62z" color="#000"/><path fill="none" stroke="#000" stroke-linecap="round" stroke-width="1.344" d="m7.033 1040.98.944 7.503m5.013-7.503-.943 7.503" transform="matrix(96.7529 0 0 87.185 55.328 -89815)"/><path d="M758.141 337.32 343.458 458.648v60.76h1361.023v-60.76L1284.767 337.32z"/><path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="69.952" d="M793.262 211.444h461.512v168.06H793.262z"/></svg>