【问题标题】:Java API for KML (JAK) embedding images in kmz filesJava API for KML (JAK) 在 kmz 文件中嵌入图像
【发布时间】:2011-09-01 03:18:20
【问题描述】:

有没有办法使用 Java API for KML (JAK) 将图像文件添加到 kmz 文件中?我可以毫无问题地创建一个 kml 文件,但我试图只嵌入一个资源(例如带有一些图像文件的图像文件夹),但是 marshalAsKmz 方法只将 Kml 对象作为附加文件,所以我想不通了解如何仅包含额外的图像。

【问题讨论】:

    标签: java kml kmz jak


    【解决方案1】:

    我在一个项目中使用 JAK 已经一年多了。我使用它来创建 KML,然后将其编组为纯 KML(而不是 KMZ)。我创建了一个单独的实用程序类,它使用 Java SE 'Zip' 类手动创建 KMZ。它工作得很好。 KMZ 只不过是一个 .zip 存档,其中仅包含一个 .kml 文件和 0 个或多个资源文件(例如图像等)。唯一的区别是在输出文件时将文件命名为 .kmz 而不是 .zip。在 KML 文档 <Style> 定义中,使用相对于 KML 文档本身的路径引用您的资源文件。 KML 文件被视为位于 KMZ 存档的“根”。如果您的资源文件也位于 KMZ (.zip) 的根目录中,则不需要路径,只需文件名即可。

    编辑: 我实际上忘记了我在压缩之前删除了将 JAK Kml 对象编组到文件的中间步骤。我下面的实用方法会将Kml 对象直接编组到ZipOutputStream

    这是我创建的一个实用程序类,用于执行我所描述的操作。我在此处发布它是希望其他人发布仅使用 JAK 的替代解决方案,以便我将来可以停用此代码。目前,这将为您完成这项工作。

    注意:如果您不使用 slf4j、Apache Commons Lang 或 Commons I/O,那么只需对代码进行一些调整,以使用您自己的代码删除/替换这些位。显然这段代码需要 JAK 库。

    package com.jimtough;
    
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.Collections;
    import java.util.List;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipOutputStream;
    
    import org.apache.commons.io.IOUtils;
    import org.apache.commons.lang.Validate;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import de.micromata.opengis.kml.v_2_2_0.Kml;
    
    /**
     * Uses the classes in java.util.zip to package a KML file and its
     * supplementary files as a ZIP-compressed KMZ file.
     * 
     * @author JTOUGH
     */
    public final class KMZPackager {
    
        private final static Logger logger =
            LoggerFactory.getLogger(KMZPackager.class);
    
        /**
         * Container for data that represents a single entry that will be added
         * to a compressed archive.
         * @author JTOUGH
         */
        public static abstract class DataSource {
            protected String archivedFileName;
    
            /**
             * Write the contents of this data source to the supplied
             * zip output stream.
             * 
             * @param zipOutputStream
             * @throws IOException
             */
            public abstract void writeToStream(ZipOutputStream zipOutputStream) 
                throws IOException; 
        }
    
        /**
         * Container for data that represents a single file that will be added
         * to a compressed archive.
         * @author JTOUGH
         */
        public static final class FileDataSource extends DataSource {
            private File sourceFile;
    
            /**
             * Constructor
             * 
             * @param sourceFile Actual file that will be added to the 
             *  compressed archive. 
             * @param archivedFileName Name that will be assigned to the compressed
             *  file within the archive. Caller must ensure that this value is
             *  unique within the archive otherwise an exception will be thrown
             *  when a name clash occurs during creation of the archive.
             *  This string must be non-null and non-empty. Any forward-slash
             *  characters in the string will be treated as directory separators
             *  when the KMZ/ZIP archive is created.
             * @throws IllegalArgumentException If either of these parameters
             *  is a null reference
             */
            public FileDataSource(
                    File sourceFile,
                    String archivedFileName) 
                    throws IllegalArgumentException {
                Validate.notNull(sourceFile);
                Validate.notEmpty(archivedFileName);
                this.sourceFile = sourceFile;
                this.archivedFileName = archivedFileName;
            }
    
            @Override
            public void writeToStream(ZipOutputStream zipOutputStream)
                    throws IOException {
                Validate.notNull(zipOutputStream);
    
                // Check that the file exists, and throw an appropriate exception
                // before reading it
                if (!sourceFile.exists()) {
                    throw new IllegalArgumentException(
                        "File referenced in parameter [" +
                        sourceFile.getAbsolutePath() + "] does not exist");
                }
    
                FileInputStream fis = new FileInputStream(sourceFile);
    
                if (logger.isDebugEnabled()) {
                    logger.debug("Adding file to KMZ archive" +
                        " | archive name: " + archivedFileName +
                        " | original name: " + 
                        sourceFile.getCanonicalPath());
                }
    
                // Mark the start of this new file in the ZIP stream
                ZipEntry entry = new ZipEntry(archivedFileName);
                zipOutputStream.putNextEntry(entry);
    
                // Use the Apache commons-io library to do a buffered
                // stream-to-stream copy
                try {
                    IOUtils.copy(fis, zipOutputStream);
                } finally {
                    fis.close();
                }
            }
        }
    
        /**
         * Container for a single JAK Kml object that will be marshalled
         * directly to a compressed KMZ archive as it is created
         * @author JTOUGH
         */
        public static final class KMLDataSource extends DataSource {
            private Kml kml;
    
            /**
             * Constructor
             * 
             * @param kml JAK Kml object that will be marshalled directly to the 
             *  compressed archive. 
             * @param archivedFileName Name that will be assigned to the compressed
             *  file within the archive. Caller must ensure that this value is
             *  unique within the archive otherwise an exception will be thrown
             *  when a name clash occurs during creation of the archive.
             *  This string must be non-null and non-empty. Any forward-slash
             *  characters in the string will be treated as directory separators
             *  when the KMZ/ZIP archive is created.
             * @throws IllegalArgumentException If either of these parameters
             *  is a null reference
             */
            public KMLDataSource(
                    Kml kml,
                    String archivedFileName) 
                    throws IllegalArgumentException {
                Validate.notNull(kml);
                Validate.notEmpty(archivedFileName);
                this.kml = kml;
                this.archivedFileName = archivedFileName;
            }
    
            @Override
            public void writeToStream(ZipOutputStream zipOutputStream) throws IOException {
                Validate.notNull(zipOutputStream);
                // Mark the start of this new file in the ZIP stream
                ZipEntry entry = new ZipEntry(archivedFileName);
                zipOutputStream.putNextEntry(entry);
    
                // Marshal the Kml object directly to the ZipOutputStream
                if (logger.isDebugEnabled()) {
                    logger.debug("Marshalling KML to KMZ archive" +
                        " | archive name: " + archivedFileName);
                }
                kml.marshal(zipOutputStream);   
            }
        }
    
        /**
         * Container for a stream holding a Kml document. This will be written
         * directly to a compressed KMZ archive as it is created.
         */
        public static final class StreamDataSource extends DataSource {
    
            private InputStream inputStream;
    
            /**
             * Constructor
             * 
             * @param inputStream the inputStream holding the KML text
             * @param archivedFileName Name that will be assigned to the compressed
             *  file within the archive. Caller must ensure that this value is
             *  unique within the archive otherwise an exception will be thrown
             *  when a name clash occurs during creation of the archive.
             *  This string must be non-null and non-empty. Any forward-slash
             *  characters in the string will be treated as directory separators
             *  when the KMZ/ZIP archive is created.
             * @throws IllegalArgumentException If either of these parameters
             *  is a null reference
             */
            public StreamDataSource(
                    InputStream inputStream,
                    String archivedFileName) 
                    throws IllegalArgumentException {
                Validate.notNull(inputStream);
                Validate.notEmpty(archivedFileName);
                this.inputStream = inputStream;
                this.archivedFileName = archivedFileName;
            }
    
            @Override
            public void writeToStream(ZipOutputStream zipOutputStream) throws IOException {
                Validate.notNull(zipOutputStream);
                // Mark the start of this new file in the ZIP stream
                ZipEntry entry = new ZipEntry(archivedFileName);
                zipOutputStream.putNextEntry(entry);
    
                // Use the Apache commons-io library to do a buffered
                // stream-to-stream copy
                if (logger.isDebugEnabled()) {
                    logger.debug("Copying KML from stream to KMZ archive" +
                        " | archive name: " + archivedFileName);
                }
                try {
                    IOUtils.copy(inputStream, zipOutputStream);
                } finally {
                    inputStream.close();
                }
            }
        }
    
        /**
         * Use ZIP compression to package a KML file and its supplementary files
         * as a KMZ archive.  The compressed archive will be written to the 
         * supplied output stream.
         * 
         * @param os OutputStream to which the compressed archive will be written.
         *  This parameter must be a non-null reference to an OutputStream that
         *  is open for write operations.
         * @param kmlDataSource KML to be added to the compressed archive. 
         *  This parameter must not be null. The archivedFileName attribute must
         *  end with the .kml extension. The file is added to the compressed 
         *  archive. The KMZ specification states that a KMZ archive must only
         *  contain a single KML file.
         * @param supplementaryFileList List of file locations for supplementary
         *  files that will be included in the KMZ archive. A common example
         *  would be icons or image overlays that are referenced in the KML file.
         *  This parameter can be null or an empty list if there are no 
         *  supplementary files to include in the KMZ. Each source that is included
         *  in the list must refer to an existing file that does NOT have the
         *  file extension '.kml'.
         * @throws RuntimeException Thrown if anything unexpected occurs
         *  that prevents execution from continuing or if any of the stated
         *  conditions for the input parameters are violated
         */
        public void packageAsKMZ(
                OutputStream os,
                DataSource kmlDataSource,
                List<FileDataSource> supplementaryFileList) 
                throws RuntimeException {
            ZipOutputStream zipOutputStream = null;
            boolean isExceptionThrown = false;
            Exception caughtException = null;
            List<FileDataSource> supplFileList = supplementaryFileList;
    
            try {
                Validate.notNull(os, "os parameter cannot be null");
                Validate.notNull(kmlDataSource, 
                    "kmlFileDataSource parameter cannot be null");
    
                // Treat a null parameter just like an empty list (which is OK)
                if (supplFileList == null) {
                    supplFileList = Collections.emptyList();
                }
    
                if (logger.isDebugEnabled()) {
                    logger.debug(
                        "Creating KMZ archive" +
                        " | supplementary files: " + supplFileList.size());
                }
    
                // Create a buffered output stream for the new KMZ file
                zipOutputStream = new ZipOutputStream(new BufferedOutputStream(os));
                Validate.isTrue(
                    kmlDataSource.archivedFileName.endsWith(".kml"),
                    "KML archived file name must end with .kml");
                kmlDataSource.writeToStream(zipOutputStream);
    
                // Now process the list of supplementary files
                if (logger.isDebugEnabled()) {
                    logger.debug("Adding supplementary files to KMZ archive" +
                        " | archive name: ");
                }
                for (FileDataSource ds : supplFileList) {
                    Validate.isTrue(
                        !ds.archivedFileName.endsWith(".kml"),
                        "Not legal to include .kml files in supplementary list");
                    ds.writeToStream(zipOutputStream);
                }
    
                // Close the output stream to complete the ZIP creation
                zipOutputStream.flush();
                zipOutputStream.close();
    
                logger.info("KMZ archive created successfully");
    
            } catch (IOException e) {
                isExceptionThrown = true;
                caughtException = e;
                logger.error("IOException while creating ZIP stream");
            } catch (IllegalArgumentException e) {
                isExceptionThrown = true;
                caughtException = e;
            } catch (RuntimeException e) {
                isExceptionThrown = true;
                caughtException = e;
            } finally {
                if (isExceptionThrown) {
                    try {
                        if (zipOutputStream != null) {
                            zipOutputStream.close();
                        }
                    } catch (IOException ioe) {
                        // Don't care
                    }
                    throw new RuntimeException(caughtException);
                }
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      Java 带有一个默认的 zip 实用程序,您只需将需要压缩的 kml 文件与图像文件列表一起传递。这两个功能应该可以解决问题。

         private void exportAsKmz(Kml kmlFile,File[] files) throws IOException {
            ZipOutputStream out = new ZipOutputStream(new FileOutputStream("example.kmz"));
            addKmzFile(kmlFile,out,files);
            out.close();
         }
      
         private void addKmzFile(Kml kmzFile, ZipOutputStream out,File[] files) throws IOException {
            String fileName = "";
            fileName = kmzFile.getFeature().getName();
            if (!fileName.endsWith(".kml")) {
               fileName += ".kml";
            }
            for(File file : files){
               out.putNextEntry(new ZipEntry(file.getName()));
               Files.copy(file.toPath(), out);
            }
            out.putNextEntry(new ZipEntry(URLEncoder.encode(fileName, "UTF-8")));
            kmzFile.marshal(out);
            out.closeEntry();
         }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多