图标清理与验证
清理函数用于 Iconify Tools 中,以验证和清理导入的图标。
遗憾的是,许多编辑器会在 SVG 文件中留下大量冗余代码,有时甚至会使图标文件大小增加数倍。
SVG 文件还可能包含脚本和指向外部资源的链接。
使用方法
要清理和验证图标,请运行 cleanupSVG()。
该函数包含一个必需参数:
- svg,SVG。图标实例。
以及一个可选参数:
- options,object。选项,见下文。
该函数不返回任何内容,它会直接对 SVG 实例应用更改。
如果发生错误,函数将抛出异常。
选项
options 参数包含以下属性:
- keepTitles,boolean。如果设置为 true,则不会移除标题。
默认情况下会移除标题,因为几乎所有图标都可以代表多种含义,因此硬编码的标题对大多数用户来说并不适用。保留标题的选项旨在用于处理特定于某个网站的自定义图标集。
清理流程
清理流程会运行多个函数来执行各种任务:
- cleanupInlineStyle() 检查内联样式并移除不需要的样式。
- convertStyleToAttrs() 将样式转换为属性。
- cleanupSVGRoot() 清理 <svg> 元素。
- checkBadTags() 检查图标中是否存在不良标签。
- removeBadAttributes() 移除不良属性。
如果需要,你可以按上述顺序运行上述列出的函数。其效果与运行 cleanupSVG() 完全相同。
优化
清理函数不会优化图标数据,也不会重写任何形状。这些函数仅移除大部分无用代码,从而使图标更易于处理。
优化应单独进行。请参阅 图标操作函数。
预设验证规则
该验证具有预设规则。它旨在用于生成可供任何人使用的图标,因此规则相当严格。
如果图标存在以下情况,验证将失败:
- 包含任何脚本。不受信任的脚本具有危险性。
- 包含任何文本。这是一项非常严格的预设规则。原因是使用文本的图标通常是设计师在未意识到所用字体并未安装在每台电脑上的情况下导出的,因此图标显示效果会与预期不同。请在从编辑器导出前将文本转换为形状。
- 包含任何位图图像。矢量形状中包含位图是不可接受的,因为它们无法无损缩放。图标的设计初衷就是能够无限制地缩放。
示例
cleanup.ts
ts
import { SVG, 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);
cleanupSVG(svg);
console.log(svg.toMinifiedString());Result:
svg
<svg xmlns="http://www.w3.org/2000/svg" width="2048" height="2048" viewBox="0 0 2048 2048"><defs id="defs3893"></defs><g id="layer1" transform="translate(0,995.63783)"><g transform="matrix(96.752895,0,0,96.752895,55.328158,-100816.34)" id="layer1-6" display="inline"><path 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" color="#000000" display="inline" visibility="visible" opacity="1" color-interpolation="sRGB" 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"/><g id="g4275" transform="matrix(1,0,0,0.90111263,0,103.41515)"><path id="path4092" d="m 7.0333918,1040.9794 0.9432241,7.504" 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" 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 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" fill="#000000" fill-opacity="1" stroke="none"/><path d="m 7.6269598,1033.8929