使用 SVGO 优化图标
此函数属于 Iconify Tools 中的 图标操作函数 的一部分。
函数 runSVGO() 使用流行的 SVG 优化工具 SVGO 来优化图标。
它旨在用于已经通过 cleanupSVG() 处理过的图标,该函数会完成大部分的清理工作。
此函数用于执行 SVGO 擅长的高级操作:转换变换、清理数值、移除未使用的 SVG 元素等。
插件
默认情况下,该函数使用预配置的 SVGO 插件列表,其中排除了一些存在缺陷的插件。
如果图标包含 SVG 动画,则会排除修改形状的插件。
用法
该函数具有以下参数:
- svg,SVG。图标实例。
- options,object。选项(可选)。
选项
设置选项有两种方式:
- 使用自定义的 SVGO 插件列表。
- 通过多个选项切换插件组。
自定义插件列表
你可以使用选项的 plugins 属性来设置自定义插件。该值是一个插件数组,将直接传递给 SVGO(请参阅 SVGO 文档)。
示例:
ts
runSVGO(svg, {
plugins: ['convertStyleToAttrs', 'inlineStyles'],
multipass: true,
});插件选项
你也可以通过设置以下选项从预设的插件列表中进行选择:
- animated,boolean。如果为 true,则不会使用已知在处理动画图标时会出现问题的 SVGO 插件。
- keepShapes,boolean。如果为 true,则不会使用修改形状的插件。如果你需要保持形状原样(例如在对形状进行动画处理时),这会很有用,但它不如设置 animated 选项那么严格。
- cleanupIDs,string|false|function。用于重写 ID 的自定义前缀,设置为 false 可禁用更改 ID 的插件。也可以是一个回调函数,根据旧 ID 返回新 ID。
这些选项不能与 plugins 选项同时使用。
其他选项
可与上述任何选项配合使用的选项:
- multipass,boolean。如果为 true,插件将运行多次以获得更好的优化效果。默认启用。
示例
svgo.ts
ts
import { 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
ts
import { 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>