2

因此,我过去制作了一些示例 KML/KMZ 文件,主要是手工制作,并且发现由于这项工作与 Google 地球存在一些不一致之处。在大多数情况下,我认为我对特定版本的 GE 需要做的事情有很好的把握。最近,我尝试在我的 KML/KMZ 示例文件中添加一些自动化功能,以便根据给定的 CSV 点和其他元数据为某些客户端自定义它们。

我想联系那些有使用自定义图标或内容从 Java 创建 KMZ 文件的经验的人。这是我坚持的皱纹:

我手动创建了一堆样式和自定义图标,以更好地显示客户数据。最近,我创建了一个 Java 应用程序,它可以通过自动化 KML/KMZ 生产来节省大量时间。这些样式直接从示例中复制到我的 Java 代码中(在其应有的位置使用转义符)。Java 代码最初构建了 KML,然后我将 KML 与示例中的图标文件夹打包,压缩并保存为 KMZ。一切正常。

然后我添加了一个主要基于此示例的代码块,并将我的所有图标作为资源添加到 jar 中。然后,我将文件构建为 .zip,并验证 KML 和 Icon 文件(在适当的文件夹中)是否在 zip 中。他们是。所有人都对这个世界感到满意。

然后我将输出文件名更改为 .kmz 而不是 .zip 并尝试在 Google 中运行输出。我的自定义图标都没有加载。KML 工作正常,点和多边形具有正确的样式颜色,但中间有带有 X 的框,好像它无法访问图标。

如果我将输出 KMZ 重命名为 zip、解压缩并在其中运行 KML,一切都会按预期工作。如果我重新压缩并重命名为 KMZ,它会再次损坏。

不过,这才是真正的乐趣。如果我将 KML 从 KMZ 中取出,使用工作区资源中的图标文件夹重新打包,另存为 KMZ 并加载到谷歌地球,它可以正常工作。

我觉得这告诉我,我的 java.util.zip 代码以某种方式破坏了图像,以至于 GE 不知道如何处理它们。但是我完全不明白为什么它们在未包装时工作正常,但在从同一位置重新包装时又坏了。

有人有想法么?提前道歉没有发布代码。如果我们可以稍微缩小问题空间,我会发布我可以发布的内容。

这是我目前可以转录的尽可能多的代码:

//Create new file output based on file-name of previously made KML file (fileOut)
//nameToken exists to pop KML extension off the back end of fileOut.getName()

File fileOut2 = new File(fileOut.getParent(), nameToken2[0] + ".kmz");
FileOutputStream foutstream = new FileOutputStream(fileOut2);

ZipOutputStream zout = new ZipOutputStream(foutstream);
byte[] buffer = new byte[1024];

String[] resourceFiles = {null,"/icons/b-lv.png",...}; //many files listed here
for(int i = 0; i < resourceFiles.length; i++){
    //Previously wrote kml file, time to read it in and add to zip
    if (i == 0){
        FileInputStream fin = new FileInoutStream(fileOut);
        zout.putNextEntry(new ZipEntry(fileOut.getName());
        int length;
        while ((length = fin.read(buffer)) > 0){
            zout.write(buffer,0,length);
        }
        zout.closeEntry();
        fin.close();
    }
    //Read in resource icon files and add to zip
    else{
        InputStream inStream = this.getClass().getResourceAsStream(resourceFiles[i]);
        zout.putNextEntry(new ZipEntry(resourceFiles[i]));
        int length;
        while((length = inStream.read(buffer)) > 0){
            zout.write(buffer,0,length);
        }
        zout.closeEntry();
        inStream.close();
    }
}

zout.flush();
zout.close();
foutstream.close();
fileOut.delete();  //Deletes previously made KML file
4

1 回答 1

7

下面是使用ZipOutputStream和根 KML 文件和图像文件条目创建示例 KMZ 文件的 Java 代码。如果在添加图像条目之前未正确关闭 KML 条目,则 KMZ 文件可能会损坏。

重要提示:您必须确保 zip 文件条目与 KML 中的 URL 引用完全匹配。zip 文件条目不应“/”或“../”或“C:/”开头。同样,对 KML 中 KMZ 条目的 URL/href 引用应该是相对于特定 KML 文件的(例如icons/b-lv.png )。

为了减少下面示例中的代码行数,Apache commons IOUtils库用于将输入文件复制到 KMZ 输出流并关闭流。

import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import java.io.*;

public class TestKmz {

    public static void main(String[] args) throws IOException {     
        createKMZ();
        System.out.println("file out.kmz created");
    }

    public static void createKMZ()  throws IOException  {
        FileOutputStream fos = new FileOutputStream("out.kmz");
        ZipOutputStream zoS = new ZipOutputStream(fos);     
        ZipEntry ze = new ZipEntry("doc.kml");
        zoS.putNextEntry(ze);
        PrintStream ps = new PrintStream(zoS);          
        ps.println("<?xml version='1.0' encoding='UTF-8'?>");
        ps.println("<kml xmlns='http://www.opengis.net/kml/2.2'>");     
        // write out contents of KML file ...
        ps.println("<Placemark>");
        // add reference to image via inline style
        ps.println("  <Style><IconStyle>");
        ps.println("    <Icon><href>image.png</href></Icon>");
        ps.println("  </IconStyle></Style>");
        ps.println("</Placemark>");
        ps.println("</kml>");
        ps.flush();                 
        zoS.closeEntry(); // close KML entry

        // now add image file entry to KMZ
        FileInputStream is = null;
        try {                   
            is = new FileInputStream("image.png");
            ZipEntry zEnt = new ZipEntry("image.png");
            zoS.putNextEntry(zEnt);
            // copy image input to KMZ output
            // write contents to entry within compressed KMZ file
            IOUtils.copy(is, zoS);
        } finally {
            IOUtils.closeQuietly(is);
        }
        zoS.closeEntry();
        zoS.close();
    }   
}   
于 2012-10-06T18:57:04.157 回答