Search code examples
javasvgkmlconverters

SVG paths to KML polygons


I want to create a svg to kml converter in Java. I have created a sort of translator for this task, that takes in text in svg format and prints out text in kml format. I am able to handle circle and rect tags so far. I'm not able to handle paths.

How can I read svg paths(the d attribute) and reconstruct them in kml?

The main issue stems from the fact that svg paths are not simple sequences of coordinates, and they have curves in them. Here's an example of an svg path input that I need to handle:

<html>
<body>

<svg width="10000" height="1000">
<path id="square" fill="#0000FF" 
d="M351.3,251 l-3.1-2.2c-0.3-0.2-0.3-0.5-0.1-0.8l2.2-3.1c0.2-0.3,0.5-0.3,0.8-0.1l3.1,2.2
c0.3,0.2,0.3,0.5,0.1,0.8l-2.2,3.1C355,251.1,354.6,251.2,354.3,251z"/>

</body>
</html>

If I can figure out how to evaluate the string in the d attribute, the only other issue is how to create the curves using the values extracted from the string in the d attribute.

This format of paths is not the one commonly found online; it is something that was created using adobe illustrator by someone else and now I don't have access to that software. Since there are no spaces or regular commas, I'm not able to understand how to read the string properly.


Solution

  • I found an easy way to convert SVG paths to SVG polygons in JavaScript. SVG polygons can easily be converted to KML placemarks since both use a list of coordinates. This script can be placed in an HTML file and will directly work off a browser. It will take an SVG file from your computer and save the modified file as a text file. I'd recommend using Chrome, since the SVG maintains a fixed size on it, which ensures that the coordinate system remains exactly the same.

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Reader</title>
    </head>
    <body>
    <h1>SVG paths to polygons</h1>
    <input type="file" id="fileReader" />
    <br>
    <p id="Content"></p>
    <script>
    document.getElementById("fileReader").addEventListener('change',function(){
    var fr = new FileReader();
    fr.onload = function(){;
    var d = new DOMParser().parseFromString( this.result.toString(), "image/svg+xml" );
    var nodelist = d.querySelectorAll('path');
    console.log("Number of paths: " + nodelist.length);
    nodelist.forEach(function(path){//This replaces each path with a polygon, keeping the same id.
    var polygon = d.createElementNS("http://www.w3.org/2000/svg", "polygon");
    polygon.setAttribute("id", path.getAttribute("id"));
    console.log("Converting " + path.getAttribute("id"));
    var length = path.getTotalLength();
    var p=path.getPointAtLength(0);
    var stp=p.x+","+p.y;
    for(var i=1; i<length; i++){
        p=path.getPointAtLength(i);
        stp=stp+" "+p.x+","+p.y;
        //This places points along the path at one unit distance apart.
    }
    polygon.setAttribute("points", stp);
    path.replaceWith(polygon);
    });
    var text1 = new XMLSerializer().serializeToString(d);
    document.write(text1);
    function download(filename, text) {
      var element = document.createElement('a');
      element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
      element.setAttribute('download', filename);
    
      element.style.display = 'none';
      document.body.appendChild(element);
    
      element.click();
    
      document.body.removeChild(element);
    }
    
    // Starting file download.
    download("output.txt", text1);
    }
    fr.readAsText(this.files[0]);
    })
    </script>
    </body>
    </html>

    You can then directly take the points attribute and place it in the coordinates tag in KML. You'll just have to replace the spaces with new lines.