提问人:oli_vi_er 提问时间:10/26/2023 最后编辑:herrstrietzeloli_vi_er 更新时间:11/1/2023 访问量:35
是否可以只删除只有填充而没有描边的形状?
Is it possible to delete only the shapes that have only a fill an no stroke?
问:
我只想保留这张地图上没有填充的形状:https://commons.wikimedia.org/wiki/File:Antarctica_in_the_World_(黄色).svg 显然,我不想手动删除所有其他形状......
是否可以仅删除只有填充而没有描边的形状? 也许通过编辑文件的代码?我不知道该怎么做,但我知道在必要时如何使用正则表达式。
谢谢你的帮助。
答:
1赞
herrstrietzel
10/27/2023
#1
您可以使用 inkscape 的命令行,但我认为自定义 java 脚本更方便,因为您可以立即预览输出。
示例 1:从 XML 标记分析
- 分析 SVG 标记
- 查询所有路径(可选:包括多边形和折线)
- 循环:检查每个路径的填充和描边属性
3.1。删除不带描边的元素 - 通过以下方式获取更新的 SVG 标记
new XMLSerializer()
let markup = `<svg viewBox="0 0 100 30">
<path id="is" fill="#CECECE" stroke="none" d="M5.1 8.7l5.4-0.7l1.6-0.5l3.3 0.4l2.1-0.8l3.7 0.1l-2.2 1l2.2-0.4l3.8 0.5l-7.7 2.4l3.7 0.3h3.4l-12.2 1.7l-2.5-0.1l-4.2 0.1l1.4 1.3l6-0.4h3.5l4.1 0.5l-1.5 1.3l1.8 1l5.8-1.6l-2.5 0.8l-0.4 1.3l-2.2 0.7l5.6-0.5l-2.5 1.6l-2.6 0.1l-2.4 3.8l-2.1 0.1l-1-0.5l-0.5 2.1l8.1-0.4l3.8 0.1l3.1-0.8l-0.3 0.8l2.7 0.3l0.1 0.4l3.1-0.7l1 0.9l-1.4 0.3l6.4 1.3l8 1l6-0.3l2.4-0.7l1.3-1.2l3.4-0.8l4.5-1.3l6.3-0.5l7.6-2.9l5.1 0.4l2.9-2.5l1.3-1.6l5.4-2.7l-1.3-0.9l2.4-0.1l-3.6-0.7l5.6-0.4l-3.8-0.9l3.3-0.7l-3.8-0.1l3-2l-4.5-0.8l-3.8 1l2-2.4l-4.6 0.5l2-1.8l-4.6-1.4l1.2-0.9l3.7-1l-7.2 2l-3.1-1.8l-4.8-1l-2.2 0.7l-0.9 2.5l-5-1l-3.8 2.4l-7.1-2l1 1.6l1.2 2.5l-7.7-4.3l-1.7 0.9h-2.6l-0.4 2.5l-6.2-2.7l-2.1 1.8l-1.2 2.4l-2.6-0.6l-3.1 1.6l0.1 2.4l-3.6-2.4l-2.5-2.6l1.8-1.6l-0.5-0.8l-2.5-1.3l-6.4-1.8l-4.3 0.9l6 0.7l-4.5 0.8l4.1 1.4l-1.8 1.3l-3.7-1.3l0.4-0.8l-3.4-0.8l-0.4 0.7l0.4 0.9l-3.8-0.7l4.2 1.7l-4.6 0.3l5 0.7l-2.4 0.3l2.1 0.4l-7.3-0.8l2.2 1l0.4 0.8l-5.5 0.3l5.1 0.7"/>
<path id="is_1_" fill="none" stroke="#1178AC" d="M5.1 8.7l5.4-0.7l1.6-0.5l3.3 0.4l2.1-0.8l3.7 0.1l-2.2 1l2.2-0.4l3.8 0.5l-7.7 2.4l3.7 0.3h3.4l-12.2 1.7l-2.5-0.1l-4.2 0.1l1.4 1.3l6-0.4h3.5l4.1 0.5l-1.5 1.3l1.8 1l5.8-1.6l-2.5 0.8l-0.4 1.3l-2.2 0.7l5.6-0.5l-2.5 1.6l-2.6 0.1l-2.4 3.8l-2.1 0.1l-1-0.5l-0.5 2.1l8.1-0.4l3.8 0.1l3.1-0.8l-0.3 0.8l2.7 0.3l0.1 0.4l3.1-0.7l1 0.9l-1.4 0.3l6.4 1.3l8 1l6-0.3l2.4-0.7l1.3-1.2l3.4-0.8l4.5-1.3l6.3-0.5l7.6-2.9l5.1 0.4l2.9-2.5l1.3-1.6l5.4-2.7l-1.3-0.9l2.4-0.1l-3.6-0.7l5.6-0.4l-3.8-0.9l3.3-0.7l-3.8-0.1l3-2l-4.5-0.8l-3.8 1l2-2.4l-4.6 0.5l2-1.8l-4.6-1.4l1.2-0.9l3.7-1l-7.2 2l-3.1-1.8l-4.8-1l-2.2 0.7l-0.9 2.5l-5-1l-3.8 2.4l-7.1-2l1 1.6l1.2 2.5l-7.7-4.3l-1.7 0.9h-2.6l-0.4 2.5l-6.2-2.7l-2.1 1.8l-1.2 2.4l-2.6-0.6l-3.1 1.6l0.1 2.4l-3.6-2.4l-2.5-2.6l1.8-1.6l-0.5-0.8l-2.5-1.3l-6.4-1.8l-4.3 0.9l6 0.7l-4.5 0.8l4.1 1.4l-1.8 1.3l-3.7-1.3l0.4-0.8l-3.4-0.8l-0.4 0.7l0.4 0.9l-3.8-0.7l4.2 1.7l-4.6 0.3l5 0.7l-2.4 0.3l2.1 0.4l-7.3-0.8l2.2 1l0.4 0.8l-5.5 0.3l5.1 0.7"/>
</svg>`;
// parse svg from raw xml markup
let svg = new DOMParser()
.parseFromString(markup, "text/html")
.querySelector("svg");
// query all paths and similar elements
let paths = svg.querySelectorAll("path, polygon, polyline");
paths.forEach((path) => {
// check attributes
let stroke = path.getAttribute("stroke");
let fill = path.getAttribute("fill");
// remove if element doesn't have stroke but a fill
if ((fill || fill!='none') && (!stroke || stroke==='none') ) {
path.remove();
}
});
// get updated svg
let markupNew = new XMLSerializer().serializeToString(svg)
console.log(markupNew)
// render preview
preview.append(svg);
svg{
border:1px solid #ccc;
overflow:visible
width: 50%;
height: auto;
}
<div id="preview"></div>
示例 2:从提取的 XML(远程)svg 文件进行解析
此方法要求 svg 源允许跨域访问。因此,svg 需要具有适当的 CORS 标头或从同一域提供。
/**
* fetch data asynchronously
*/
(async() => {
let url = "https://upload.wikimedia.org/wikipedia/commons/b/b6/Antarctica_in_the_World_%28yellow%29.svg"
let fetchedData = await (fetch(url));
let markup = await fetchedData.text()
// remove tabs and newlines
markup = markup.replaceAll('\t', '').replace(/[\n\r\t]/g, "")
// parse svg
let svg = new DOMParser().parseFromString(markup, 'text/html').querySelector('svg')
/**
* cleanup:
* remove AI metadata
* and forreignObjects
*/
let remove = svg.querySelectorAll('foreignObject, #adobe_illustrator_pgf')
remove.forEach(el => {
el.remove()
})
// unwrap switch
let switchEl = svg.querySelector('switch');
let switchCnt = switchEl.children[0]
switchEl.parentNode.insertBefore(switchCnt, switchEl)
switchEl.remove()
// query all paths and similar elements
let paths = svg.querySelectorAll('path, polygon, polyline')
paths.forEach(path => {
// check attributes
let stroke = path.getAttribute('stroke')
let fill = path.getAttribute('fill')
// remove if element doesn't have stroke but a fill
if ((fill || fill != 'none') && (!stroke || stroke === 'none')) {
path.remove()
}
})
// remove empty groups
let groups = svg.querySelectorAll('g')
groups.forEach(g => {
if (!g.querySelectorAll('path, polygon, rect, circle, ellipse, line, polyline, text').length) {
g.remove()
}
})
// render preview
preview.append(svg)
// cleanup whitespace and create download
let markupNew = new XMLSerializer().serializeToString(svg)
.replace(/\ {2,}/g, " ")
.replace(/[\n\r\t]/g, "")
.replaceAll('>', '>\n')
let blob = new Blob([markupNew], {
type: 'image/svg+xml'
})
output.value = markupNew;
fileSize.textContent = +(blob.size / 1024 / 1024).toFixed(3) + ' KB'
btnDownload.href = URL.createObjectURL(blob)
})()
svg {
width: 100%;
height: auto;
}
textarea {
width: 100%;
min-height: 10em;
display: block;
}
<p><a id="btnDownload" href="" download="new.svg">Download</a> <span id="fileSize"></span> </p>
<div id="preview"></div>
<h3>Output</h3>
<textarea id="output"></textarea>
运作方式
- 我们正在获取 SVG 文件
- 解析它的标记
new DOMParser()
- 查询所有和元素(地图中的形状通常可以是路径或多边形)
path
polygon
- 遍历所有 Path 元素并通过以下方式检查其填充和描边属性: 如果路径有填充但没有描边属性,我们可以删除此项目
element.getAttribute()
- 创建 blob 和对象 URL 以添加下载链接(在 SO 代码片段中不起作用)
清理(可选)
此外,我们可以删除一些专有的Adobe Illustrator元数据(用于预览图像,编辑器设置和资源等)。
我们还可以删除空组或未使用的定义。
这样,我们可以显着减小文件大小。
测试:codepen 示例
评论
0赞
oli_vi_er
10/28/2023
非常感谢@herrstrietzel。恐怕我不太理解你的 JS 代码,但清理后的文件可以在 codepen.io 上找到,所以这对我来说绰绰有余。😅 这张底图对我很有帮助,当然对共享资源上的其他人也很有帮助。
0赞
herrstrietzel
11/1/2023
@oli_vi_er:也许新的简化示例 更不言自明,并邀请您使用自定义 JS“后处理器”脚本。
0赞
oli_vi_er
11/2/2023
再次感谢你,但我真的不太了解 JavaScript......
0赞
herrstrietzel
11/2/2023
对不起,我并不是要把JS推广为最好的解决方案(如果你更熟悉其他语言,xPath将是另一个候选者)。我的观点是说明如何仅使用一些基本概念(如 1)编写自己的自定义过滤器/优化器。查询元素 2.循环播放它们 3.获取属性 4.根据条件删除元素。因此,如果您经常需要处理(坦率地说,经常搞砸)维基百科共享资源的地图数据 - JS 和其他语言,您可能会比搜索内置的 cli 命令节省更多的时间,因为有无数种方法可以“搞砸”svg =)
评论