I would like to keep only the shapes that have no fill on this map : https://commons.wikimedia.org/wiki/File:Antarctica_in_the_World_(yellow).svg Obviously, I don't want to remove all the other ones by hand...
Is it possible to delete only the shapes that have only a fill an no stroke ? Maybe by editing the code of the file? I don't know how to do, but I know how to use regexes if necessary.
Thank you for your help.
You might use inkscape's command line but I think a custom java script is more convenient as you can immediately preview the output.
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>
This approach requires the svg source to allow cross origin access. So the svg needs to have a appropriate CORS header or to be served from same domain.
/**
* 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>
new DOMParser()
path
and polygon
elements (quite often shapes in maps can either be paths or polygons)element.getAttribute()
: if a path has a fill but no stroke attribute we can remove this itemBesides, we can remove some proprietary Adobe Illustrator metadata (used for preview images, editor settings and assets etc.).
We can also remove empty groups or unused definitions.
This way we can significantly reduce file size.
Testing: codepen example