OSDN Git Service

FIX: 出力GPXにWPTが出力されない問題を解消
[importpicture/importpicture.git] / importPicture / src / osm / jp / gpx / ImportPicture.java
index 3c798bb..46dd1c7 100644 (file)
@@ -92,11 +92,11 @@ public class ImportPicture extends Thread {
      *\r
      * @param argv\r
      * argv[-] = dummy\r
-     * argv[0] = 画像ファイルが格納されているディレクトリ\r
-     * argv[1] = 時刻補正の基準とする画像ファイル\r
-     * argv[2] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd'T'HH:mm:ss"\r
-     * argv[3] = [noEXIF] EXIF情報の書き換えを行わない / EXIF情報の書き換えを行う(出力先フォルダ)\r
-     * argv[4] = 撮影位置をロギングしたGPXファイル\r
+     * argv[0] = 画像ファイルが格納されているディレクトリ          --> imgDir\r
+     * argv[1] = 時刻補正の基準とする画像ファイル                              --> baseFile\r
+     * argv[2] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd'T'HH:mm:ss"      --> timeStr\r
+     * argv[3] = 出力先フォルダ                                                         --> outDir\r
+     * argv[4] = 撮影位置をロギングしたGPXファイル                              --> gpxDir\r
      * \r
      * @throws IOException\r
      * @throws ImageReadException \r
@@ -120,9 +120,33 @@ public class ImportPicture extends Thread {
             return;\r
         }\r
 \r
+        obj.params = new AppParameters();\r
+\r
+        // 基準時刻(ファイル更新日時 | EXIF撮影日時)\r
+       obj.exifBase = (obj.params.getProperty(AppParameters.GPX_BASETIME).equals("EXIF_TIME") ? true : false);\r
+\r
         // 基準時刻ファイルの「更新日時」を使って時刻合わせを行う。\r
         File baseFile = new File(obj.imgDir, argv[1]);\r
-        jptime = new Date(baseFile.lastModified());\r
+        if (obj.exifBase) {\r
+            ImageMetadata meta = Imaging.getMetadata(baseFile);\r
+            JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta;\r
+            if (jpegMetadata == null) {\r
+                System.out.println("'"+ baseFile.getAbsolutePath() +"' にEXIF情報がありません");\r
+                return;\r
+            }\r
+            TiffImageMetadata exif = jpegMetadata.getExif();\r
+            if (exif == null) {\r
+                System.out.println("'"+ baseFile.getAbsolutePath() +"' にEXIF情報がありません");\r
+                return;\r
+            }\r
+               String dateTimeOriginal = exif.getFieldValue(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL)[0];\r
+               long lastModifyTime = (new SimpleDateFormat("yyyy:MM:dd HH:mm:ss")).parse(dateTimeOriginal).getTime();\r
+               jptime = new Date(lastModifyTime);\r
+        }\r
+        else {\r
+            jptime = new Date(baseFile.lastModified());\r
+        }\r
+\r
         String timeStr = argv[2];\r
         try {\r
             dfjp.setTimeZone(TimeZone.getTimeZone("JST"));\r
@@ -131,42 +155,99 @@ public class ImportPicture extends Thread {
         }\r
         catch (ParseException e) {\r
             System.out.println("'"+ timeStr +"' の書式が違います("+ TIME_FORMAT_STRING +")");\r
+            return;\r
         }\r
 \r
-        // \r
-        if (argv[3].toUpperCase().equals("noEXIF")) {\r
-            obj.exif = false;\r
-            obj.outDir = null;\r
-        }\r
-        else {\r
-            obj.exif = true;\r
-            obj.outDir = new File(argv[3]);\r
-        }\r
+        // 出力ファイル\r
+        obj.outDir = new File(argv[3]);\r
 \r
-        // 第6引数が指定されなければ、指定されたディレクトリ内のGPXファイルすべてを対象とする\r
-        if (argv.length >= 5) {\r
-            obj.gpxDir = new File(argv[4]);\r
-        }\r
+        // その他のパラメータを読み取る\r
+       String paramStr = obj.params.getProperty(AppParameters.GPX_GPXSPLIT);\r
+       if ((paramStr != null) && (paramStr.equals(Boolean.toString(true)))) {\r
+               obj.param_GpxSplit = true;\r
+       }\r
+        \r
+       paramStr = obj.params.getProperty(AppParameters.GPX_NO_FIRST_NODE);\r
+       if ((paramStr != null) && (paramStr.equals(Boolean.toString(true)))) {\r
+               obj.param_GpxNoFirstNode = true;\r
+       }\r
+       \r
+       paramStr = obj.params.getProperty(AppParameters.GPX_REUSE);\r
+       if ((paramStr != null) && (paramStr.equals(Boolean.toString(true)))) {\r
+               obj.param_GpxReuse = true;\r
+       }\r
+        \r
+       paramStr = obj.params.getProperty(AppParameters.GPX_OUTPUT_WPT);\r
+       if ((paramStr != null) && (paramStr.equals(Boolean.toString(true)))) {\r
+               obj.param_GpxOutputWpt = true;\r
+       }\r
+       \r
+       paramStr = obj.params.getProperty(AppParameters.GPX_OVERWRITE_MAGVAR);\r
+       if ((paramStr != null) && (paramStr.equals(Boolean.toString(true)))) {\r
+               Complementation.param_GpxOverwriteMagvar = true;\r
+       }\r
+\r
+       paramStr = obj.params.getProperty(AppParameters.GPX_OUTPUT_SPEED);\r
+       if ((paramStr != null) && (paramStr.equals(Boolean.toString(true)))) {\r
+               Complementation.param_GpxOutputSpeed = true;\r
+       }\r
+\r
+       paramStr = obj.params.getProperty(AppParameters.GPX_SOURCE_FOLDER);\r
+       if (paramStr != null) {\r
+               obj.param_GpxSourceFolder = new String(paramStr);\r
+            obj.gpxDir = new File(obj.param_GpxSourceFolder);\r
+            if (!obj.gpxDir.exists()) {\r
+               // GPXファイルまたはディレクトリが存在しません。\r
+               System.out.println("GPXファイルまたはディレクトリが存在しません。('"+ paramStr +"')");\r
+               return;\r
+            }\r
+       }\r
         else {\r
             obj.gpxDir = obj.imgDir;\r
         }\r
-        if (obj.gpxDir.isFile()) {\r
-            obj.gpxFiles.add(new File(obj.gpxDir, argv[4]));            \r
-        }\r
-        else {\r
+\r
+       // 指定されたディレクトリ内のGPXファイルすべてを対象とする\r
+        if (obj.gpxDir.isDirectory()) {\r
             File[] files = obj.gpxDir.listFiles();\r
+            if (files == null) {\r
+               // 対象となるGPXファイルがありませんでした。\r
+               System.out.println("対象となるGPXファイルがありませんでした。('"+ obj.gpxDir.getAbsolutePath() +"')");\r
+               return;\r
+            }\r
             for (File file : files) {\r
                 if (file.isFile()) {\r
                     String filename = file.getName().toUpperCase();\r
-                    if (filename.endsWith(".GPX")) {\r
-                        if (!filename.endsWith("_.GPX")) {\r
+                    if (filename.toUpperCase().endsWith(".GPX")) {\r
+                        if (!filename.toUpperCase().endsWith("_.GPX") || obj.param_GpxReuse) {\r
                             obj.gpxFiles.add(file);\r
                         }\r
                     }\r
                 }\r
             }\r
         }\r
-        \r
+        else {\r
+            obj.gpxFiles.add(obj.gpxDir);\r
+        }\r
+\r
+       paramStr = obj.params.getProperty(AppParameters.IMG_OUTPUT_EXIF);\r
+       if ((paramStr != null) && (paramStr.equals(Boolean.toString(true)))) {\r
+               obj.exif = true;\r
+       }\r
+\r
+        System.out.println(" - param: imgDir = '"+ obj.imgDir.getAbsolutePath() +"'");\r
+        System.out.println(" - param: outDir = '"+ (obj.outDir == null ? "" : obj.outDir.getAbsolutePath()) +"'");\r
+        System.out.println(" - param: gpxDir = '"+ (obj.gpxDir == null ? "" : obj.gpxDir.getAbsolutePath()) +"'");\r
+        System.out.println(" - param: number of gpxFiles = '"+ obj.gpxFiles.size() +"'");\r
+        System.out.println(" - param: "+ AppParameters.GPX_GPXSPLIT +"="+ obj.param_GpxSplit);\r
+        System.out.println(" - param: "+ AppParameters.GPX_NO_FIRST_NODE +"="+ obj.param_GpxNoFirstNode);        \r
+        System.out.println(" - param: "+ AppParameters.GPX_REUSE +"="+ obj.param_GpxReuse);        \r
+        System.out.println(" - param: "+ AppParameters.GPX_BASETIME +"="+ obj.params.getProperty(AppParameters.GPX_BASETIME) );\r
+        System.out.println(" - param: "+ AppParameters.IMG_OUTPUT +"="+ obj.params.getProperty(AppParameters.IMG_OUTPUT));     \r
+        System.out.println(" - param: "+ AppParameters.IMG_OUTPUT_EXIF +"= "+ String.valueOf(obj.exif));\r
+        System.out.println(" - param: "+ AppParameters.GPX_SOURCE_FOLDER +"="+ obj.param_GpxSourceFolder);\r
+        System.out.println(" - param: "+ AppParameters.GPX_OUTPUT_WPT +"="+ obj.param_GpxOutputWpt);\r
+        System.out.println(" - param: "+ AppParameters.GPX_OVERWRITE_MAGVAR +"="+ Complementation.param_GpxOverwriteMagvar);\r
+        System.out.println(" - param: "+ AppParameters.GPX_OUTPUT_SPEED +"="+ Complementation.param_GpxOutputSpeed);\r
         obj.start();\r
         try {\r
             obj.join();                            \r
@@ -178,11 +259,20 @@ public class ImportPicture extends Thread {
     public File outDir;\r
     public long delta = 0;\r
     public boolean exif = false;\r
+    public boolean exifBase = false;\r
     public ArrayList<File> gpxFiles = new ArrayList<>();\r
-    \r
+    public AppParameters params;\r
+       public boolean param_GpxSplit = false;\r
+       public boolean param_GpxNoFirstNode = false;\r
+       public boolean param_GpxReuse = false;\r
+       //public boolean Complementation.param_GpxOutputSpeed = false;\r
+       //public boolean Complementation.param_GpxOverwriteMagvar = false;\r
+       public boolean param_GpxOutputWpt = true;\r
+       public String param_GpxSourceFolder = ".";\r
+       public static final long DIFF_MAE_TIME = 3000L; // before 3 secound\r
+       \r
     @Override\r
     public void run() {\r
-        \r
         /**\r
          *\r
                 <wpt lat="35.25714922" lon="139.15490497">\r
@@ -197,113 +287,190 @@ public class ImportPicture extends Thread {
                         <sat>9</sat>\r
                 </wpt>\r
          */\r
+        try {\r
+               if (params.getProperty(AppParameters.IMG_OUTPUT).equals(Boolean.toString(true))) {\r
+                outDir = new File(outDir, imgDir.getName());\r
+               }\r
+               else {\r
+                outDir = gpxDir;\r
+               }\r
+\r
+            for (File gpxFile : this.gpxFiles) {\r
+               procGPXfile(gpxFile);\r
+            }\r
+        }\r
+        catch(ParserConfigurationException | DOMException | SAXException | IOException | ParseException | ImageReadException | ImageWriteException | IllegalArgumentException | TransformerException e) {\r
+               e.printStackTrace();\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * 個別のGPXファイルを処理する\r
+     * \r
+     * @throws ParserConfigurationException \r
+     * @throws IOException \r
+     * @throws SAXException \r
+     * @throws ParseException \r
+     * @throws ImageWriteException \r
+     * @throws ImageReadException \r
+     * @throws TransformerException \r
+     */\r
+    void procGPXfile(File gpxFile) throws ParserConfigurationException, SAXException, IOException, ParseException, ImageReadException, ImageWriteException, TransformerException {\r
         DocumentBuilderFactory factory;\r
         DocumentBuilder        builder;\r
         Node gpx;\r
 \r
-        try {\r
-               \r
-            outDir = new File(outDir, imgDir.getName());\r
+        String fileName = gpxFile.getName();\r
+        String iStr = fileName.substring(0, fileName.length() - 4);\r
 \r
-            for (File gpxFile : this.gpxFiles) {\r
-                String fileName = gpxFile.getName();\r
-                String iStr = fileName.substring(0, fileName.length() - 4);\r
-\r
-                File outputFile = new File(imgDir, iStr +"_.gpx");\r
-                System.out.println(iStr + " => "+ outputFile.getName());\r
-\r
-                factory = DocumentBuilderFactory.newInstance();\r
-                builder = factory.newDocumentBuilder();\r
-                factory.setIgnoringElementContentWhitespace(true);\r
-                factory.setIgnoringComments(true);\r
-                factory.setValidating(true);\r
-\r
-                // GPX file --> Node root\r
-                DOMImplementation domImpl = builder.getDOMImplementation();\r
-                document = domImpl.createDocument("", "gpx", null);\r
-\r
-                /*\r
-                <gpx>\r
-                <trk>\r
-                <name><![CDATA[Tracked with OSMTracker for Android?]]></name>\r
-                <cmt><![CDATA[警告: HDOP values aren't the HDOP as returned by the GPS device. They're approximated from the location accuracy in meters.]]></cmt>\r
-                <trkseg>\r
-                <trkpt lat="35.32123832" lon="139.56965631">\r
-                <ele>47.20000076293945</ele>\r
-                <time>2012-06-15T03:00:29Z</time>\r
-                <hdop>0.5</hdop>\r
-                </trkpt>\r
-                </trkseg>\r
-                </trk>\r
-                <wpt lat="35.2564461" lon="139.15437809">\r
-                </wpt>\r
-                </gpx>\r
-                */\r
-                TreeMap<Long,Element> map = new TreeMap<>();\r
-                Element trk = null;\r
-                gpx    = builder.parse(gpxFile).getFirstChild();\r
-                NodeList nodes = gpx.getChildNodes();\r
-                for (int i=0; i < nodes.getLength(); i++) {\r
-                    Node node2 = nodes.item(i);\r
-                    if (node2.getNodeName().equals("trk")) {\r
-                        trk = (Element) node2;\r
-                        trkptMap(trk, map);\r
-                    }\r
-                }\r
+        File outputFile = new File(outDir, iStr +"_.gpx");\r
+        System.out.println(gpxFile.getAbsolutePath() + " => "+ outputFile.getAbsolutePath());\r
+        System.out.println("           時差: "+ (delta / 1000) +"(sec)");\r
+        System.out.println("    Target GPX: ["+ gpxFile.getAbsolutePath() +"]");\r
+        System.out.println("          EXIF: "+ (exif ? ("convert to '" + outDir.getAbsolutePath() +"'") : "off"));\r
+        System.out.println();\r
 \r
-                boolean change = false;\r
-                if (trk != null) {\r
-                    /*\r
-                    * GPXへ割りつける開始時刻と終了時刻を求める\r
-                    */\r
-                    long gpxStartTime = (new Date()).getTime();                // 対象とする開始時刻(現在時刻)\r
-                    long gpxEndTime = 0L;                                                      // 対象とする終了時刻\r
-                    Set<Long> keySet = map.keySet();  //すべてのキー値を取得\r
-                    for (Long timeLong : keySet) {\r
-                        long gpxTime = timeLong;\r
-                        if (gpxStartTime > gpxTime) {\r
-                            gpxStartTime = gpxTime;\r
-                        }\r
-                        if (gpxEndTime < gpxTime) {\r
-                            gpxEndTime = gpxTime;\r
+        factory = DocumentBuilderFactory.newInstance();\r
+        builder = factory.newDocumentBuilder();\r
+        factory.setIgnoringElementContentWhitespace(true);\r
+        factory.setIgnoringComments(true);\r
+        factory.setValidating(true);\r
+\r
+        // GPX file --> Node root\r
+        DOMImplementation domImpl = builder.getDOMImplementation();\r
+        document = domImpl.createDocument("", "gpx", null);\r
+\r
+        /*\r
+         * <gpx>\r
+         *   <trk>\r
+         *     <name><![CDATA[Tracked with OSMTracker for Android?]]></name>\r
+         *     <cmt><![CDATA[警告: HDOP values aren't the HDOP as returned by the GPS device. They're approximated from the location accuracy in meters.]]></cmt>\r
+         *     <trkseg>\r
+         *       <trkpt lat="35.32123832" lon="139.56965631">\r
+         *         <ele>47.20000076293945</ele>\r
+         *         <time>2012-06-15T03:00:29Z</time>\r
+         *         <hdop>0.5</hdop>\r
+         *       </trkpt>\r
+         *     </trkseg>\r
+         *   </trk>\r
+         *   <wpt lat="35.2564461" lon="139.15437809"></wpt>\r
+         * </gpx>\r
+         */\r
+        TreeMap<Long,Element> map = new TreeMap<Long, Element>();\r
+        TreeMap<Long,Element> mapTRKSEG = new TreeMap<>();\r
+        Element trk = null;\r
+        //Element maeTRKPT = null;\r
+        gpx    = builder.parse(gpxFile).getFirstChild();\r
+        document = gpx.getOwnerDocument();\r
+        NodeList nodes = gpx.getChildNodes();\r
+        for (int i=0; i < nodes.getLength(); i++) {\r
+            Node node2 = nodes.item(i);\r
+            if (node2.getNodeName().equals("trk")) {\r
+                trk = (Element) node2;\r
+                \r
+                NodeList nodes1 = trk.getChildNodes();\r
+                int trksegCounter = 0;\r
+                for (int i1=0; i1 < nodes1.getLength(); i1++) {\r
+                    Node nodeTRKSEG = nodes1.item(i1);\r
+                    if (nodeTRKSEG.getNodeName().equals("trkseg")) {\r
+                       trksegCounter++;\r
+                       Element newTRKSEG = document.createElement("trkseg");\r
+                        Element trkseg = (Element) nodeTRKSEG;\r
+                        NodeList nodes2 = trkseg.getChildNodes();\r
+                        for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
+                            Node nodeTRKPT = nodes2.item(i2);\r
+                            if (nodeTRKPT.getNodeName().equals("trkpt")) {\r
+                               if (param_GpxNoFirstNode && (i2 == 0)) {\r
+                                       continue;\r
+                               }\r
+                               newTRKSEG.appendChild(getCopy(document, nodeTRKPT));\r
+                            }\r
                         }\r
-                    }\r
+                        mapTRKSEG.put(new Long(trksegCounter), getCopy(document, newTRKSEG));\r
 \r
-                    System.out.println("           時差: "+ (delta / 1000) +"(sec)");\r
-                    System.out.println("    Target GPX: ["+ gpxFile.getAbsolutePath() +"]");\r
-                    System.out.println("GPX start time: "+ dfjp.format(new Date(gpxStartTime)) + "\t[GMT " + dfuk.format(new Date(gpxStartTime))+"]");\r
-                    System.out.println("  GPX end time: "+ dfjp.format(new Date(gpxEndTime)) + "\t[GMT " + dfuk.format(new Date(gpxEndTime))+"]");\r
-                    System.out.println("          EXIF: "+ (exif ? ("convert to '" + outDir.getAbsolutePath() +"'") : "off"));\r
-                    System.out.println();\r
-                    System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
-                    System.out.println(" name       | UpdateTime         | GPStime            | Latitude   | Longitude  | ele    |magvar|");\r
-                    System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
-                    change = proc(imgDir, delta, gpxStartTime, gpxEndTime, map, exif, gpx);\r
-                    System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
+                        // <trk>から<trkseg>を削除する。\r
+                        trk.removeChild(nodeTRKSEG);\r
+                    }\r
                 }\r
+                \r
+                // <trkseg>毎に実行する\r
+                Iterator<Long> keyIte = mapTRKSEG.keySet().iterator();\r
+                while (keyIte.hasNext()) {    //ループ。反復子iteratorによる キー 取得\r
 \r
-                // 出力\r
-                if (change) {\r
-                    DOMSource source = new DOMSource(gpx);\r
-                    FileOutputStream os = new FileOutputStream(outputFile);\r
-                    StreamResult result = new StreamResult(os);\r
-                    TransformerFactory transFactory = TransformerFactory.newInstance();\r
-                    Transformer transformer = transFactory.newTransformer();\r
-                    transformer.setOutputProperty(OutputKeys.INDENT, "yes");\r
-                    transformer.setOutputProperty(OutputKeys.METHOD, "xml");\r
-                    transformer.transform(source, result);         \r
-                    if (exif) {\r
-                        outputFile = new File(outDir, iStr +"_.gpx");\r
-                        os = new FileOutputStream(outputFile);\r
-                        result = new StreamResult(os);\r
-                        transformer.transform(source, result);\r
-                    }\r
+                       // <trk>に、新たな<trkseg>を追加する。\r
+                       Element newTRKSEG = mapTRKSEG.get(keyIte.next());\r
+                    trk.appendChild(newTRKSEG);\r
+                    \r
+                    // mapに、<trkpt>を割り付ける\r
+                    trkptMap(newTRKSEG, map);\r
                 }\r
             }\r
         }\r
-        catch(ParserConfigurationException | DOMException | SAXException | IOException | ParseException | ImageReadException | ImageWriteException | IllegalArgumentException | TransformerException e) {\r
-        }\r
+        \r
+        /*\r
+         * GPXへ割りつける開始時刻と終了時刻を求める\r
+         */\r
+               long gpxStartTime = (new Date()).getTime();             // 対象とする開始時刻(現在時刻)\r
+               long gpxEndTime = 0L;                                                   // 対象とする終了時刻\r
+               Set<Long> keySet = map.keySet();  //すべてのキー値を取得\r
+               for (Long timeLong : keySet) {\r
+                       long gpxTime = timeLong;\r
+                       if (gpxStartTime > gpxTime) {\r
+                            gpxStartTime = gpxTime;\r
+                       }\r
+                       if (gpxEndTime < gpxTime) {\r
+                            gpxEndTime = gpxTime;\r
+                       }\r
+               }\r
+               \r
+               /*\r
+                * SPEEDをGPXに設定する\r
+                * 条件: SPEEDを書き出すフラグがONの時\r
+                * 条件: オリジナルのSPEEDがある場合「上書きする/変更しない」(GPX_OUTPUT_SPEED)\r
+                */\r
+               /*\r
+        TreeMap<Long,Element> map2 = new TreeMap<Long, Element>();\r
+               if (Boolean.parseBoolean(params.getProperty(AppParameters.GPX_OUTPUT_SPEED))) {\r
+                       for (Long timeL : keySet) {\r
+                   Element trkptE = trkpt(map, new Date(timeL));\r
+                   if (trkptE != null) {\r
+                       map2.put(timeL, trkptE);\r
+                   }\r
+                   else {\r
+                       map2.put(timeL, map.get(timeL));\r
+                   }\r
+                       }\r
+               }\r
+               else {\r
+                       map2 = (TreeMap<Long, Element>) map.clone();\r
+               }\r
+               */\r
+                \r
+               System.out.println("GPX start time: "+ dfjp.format(new Date(gpxStartTime)) + "\t[GMT " + dfuk.format(new Date(gpxStartTime))+"]");\r
+               System.out.println("  GPX end time: "+ dfjp.format(new Date(gpxEndTime)) + "\t[GMT " + dfuk.format(new Date(gpxEndTime))+"]");\r
+               System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|------|");\r
+               System.out.println(" name       | UpdateTime         | GPStime            | Latitude   | Longitude  | ele    |magvar| km/h |");\r
+               System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|------|");\r
+               proc(imgDir, delta, gpxStartTime, gpxEndTime, map, exif, gpx);\r
+               System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|------|");\r
+\r
+        // 出力\r
+        DOMSource source = new DOMSource(gpx);\r
+        FileOutputStream os = new FileOutputStream(outputFile);\r
+        StreamResult result = new StreamResult(os);\r
+        TransformerFactory transFactory = TransformerFactory.newInstance();\r
+        Transformer transformer = transFactory.newTransformer();\r
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");\r
+        transformer.setOutputProperty(OutputKeys.METHOD, "xml");\r
+        transformer.transform(source, result);         \r
+\r
+        outputFile = new File(outDir, iStr +"_.gpx");\r
+        os = new FileOutputStream(outputFile);\r
+        result = new StreamResult(os);\r
+        transformer.transform(source, result);\r
+\r
     }\r
+    \r
        \r
     /**\r
      * 再帰メソッド\r
@@ -318,7 +485,7 @@ public class ImportPicture extends Thread {
         DecimalFormat dayFormatter = new DecimalFormat("00");\r
 \r
         boolean ret = false;\r
-        File[] files = dir.listFiles();\r
+        File[] files = dir.listFiles(new JpegFileFilter());\r
         Arrays.sort(files, new FileSort());\r
         for (File image : files) {\r
             System.out.print(String.format("%12s|", image.getName()));\r
@@ -334,6 +501,24 @@ public class ImportPicture extends Thread {
             }\r
             \r
             Date itime = new Date(image.lastModified());\r
+            if (this.exifBase) {\r
+                ImageMetadata meta = Imaging.getMetadata(image);\r
+                JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta;\r
+                if (jpegMetadata == null) {\r
+                    System.out.println("'"+ image.getAbsolutePath() +"' にEXIF情報がありません");\r
+                    continue;\r
+                }\r
+                TiffImageMetadata exif = jpegMetadata.getExif();\r
+                if (exif == null) {\r
+                    System.out.println("'"+ image.getAbsolutePath() +"' にEXIF情報がありません");\r
+                    continue;\r
+                }\r
+               String dateTimeOriginal = exif.getFieldValue(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL)[0];\r
+               long lastModifyTime = (new SimpleDateFormat("yyyy:MM:dd HH:mm:ss")).parse(dateTimeOriginal).getTime();\r
+               itime = new Date(lastModifyTime);\r
+            }\r
+\r
+            // uktime <-- 画像撮影時刻に対応するGPX時刻\r
             Date uktime = new Date(itime.getTime() + delta);\r
             System.out.print(String.format("%20s ", dfjp.format(itime)));\r
             System.out.print(String.format("%20s|", dfjp.format(uktime)));\r
@@ -342,37 +527,38 @@ public class ImportPicture extends Thread {
                continue;\r
             }\r
 \r
-            Element trkpt = trkpt(map, uktime);\r
-            if (trkpt == null) {\r
+               // 時刻uktimeにおける<magver>をtrkptに追加する\r
+            Element trkptE = trkpt(map, uktime);\r
+            if (trkptE == null) {\r
                 System.out.println(String.format("%20s ", "Out of GPX logging time."));\r
                continue;\r
             }\r
-            \r
-            Element wpt = createWptTag(image, uktime.getTime(), trkpt);\r
-            String latStr = wpt.getAttribute("lat");\r
-            String lonStr = wpt.getAttribute("lon");\r
-            double latitude = Double.parseDouble(latStr);\r
-            double longitude = Double.parseDouble(lonStr);\r
+\r
+            TagTrkpt trkptT = new TagTrkpt(trkptE);\r
+\r
+               //Element wpt = createWptTag(image, uktime.getTime(), trkptE);\r
+            //String latStr = trkptT.lat.toString();\r
+            //String lonStr = trkptT.lon.toString();\r
+            double latitude = trkptT.lat;\r
+            double longitude = trkptT.lon;\r
             \r
             String eleStr = "-";\r
+            if (trkptT.eleStr != null) {\r
+               eleStr = new String(trkptT.eleStr);\r
+            }\r
+            \r
             String magvarStr = "-";\r
-            NodeList nodes = wpt.getChildNodes();      // 子ノードを取得\r
-            for (int i4 = 0; i4 < nodes.getLength(); i4++) {\r
-                Node node = nodes.item(i4);\r
-                if (node != null) {\r
-                    switch (node.getNodeName()) {\r
-                        case "ele":\r
-                            eleStr = node.getFirstChild().getNodeValue();\r
-                            break;\r
-                        case "magvar":\r
-                            magvarStr = node.getFirstChild().getNodeValue();\r
-                            break;\r
-                    }\r
-                }\r
+            if (trkptT.magvarStr != null) {\r
+               magvarStr = new String(trkptT.magvarStr);\r
+            }\r
+            \r
+            String speedStr = "-";\r
+            if (trkptT.speedStr != null) {\r
+               speedStr = new String(trkptT.speedStr);\r
             }\r
 \r
-            System.out.print(String.format("%12s %12s|", latStr, lonStr));\r
-            System.out.println(String.format("%8s|%6s|", eleStr, magvarStr));\r
+            System.out.print(String.format("%12s %12s|", (new Double(latitude)).toString(), (new Double(longitude)).toString()));\r
+            System.out.println(String.format("%8s|%6s|%6s|", eleStr, magvarStr, speedStr));\r
             ret = true;\r
 \r
             if (exifWrite) {\r
@@ -489,8 +675,10 @@ public class ImportPicture extends Thread {
                 }\r
             }\r
 \r
-            Element temp = getCopy(gpx.getOwnerDocument(), wpt);\r
-            gpx.appendChild(temp);\r
+            if (Boolean.parseBoolean(params.getProperty(AppParameters.GPX_OUTPUT_WPT))) {\r
+               Element temp = createWptTag(image, itime.getTime(), trkptT.trkpt);\r
+                gpx.appendChild(temp);\r
+            }\r
         }\r
         return ret;\r
     }\r
@@ -507,41 +695,41 @@ public class ImportPicture extends Thread {
     /**\r
      * XMLエレメント<trkpt>をTIMEでキー付したHashMapを生成する<br>\r
      * \r
-     *         <trk><trkseg><trkpt><time>2014-01-01T00:59:09Z</time></trkpt></trkseg></trk>\r
+     * <trkseg>\r
+     *         <trkpt lat="34.976635" lon="138.466228">\r
+     *                 <ele>267.291</ele>\r
+     *                 <magvar>359</magvar>\r
+     *                 <speed></speed>\r
+     *                 <time>2016-07-02T08:25:18Z</time>\r
+     *         </trkpt>\r
+     * </trkseg>\r
      * \r
      * @param trk\r
      * @param map\r
      * @throws ParseException\r
      */\r
-    public static void trkptMap(Element trk, TreeMap<Long,Element> map) throws ParseException {\r
+    public void trkptMap(Element trkseg, TreeMap<Long,Element> map) throws ParseException {\r
         dfuk.setTimeZone(TimeZone.getTimeZone("GMT"));\r
 \r
-        NodeList nodes1 = trk.getChildNodes();\r
-        for (int i1=0; i1 < nodes1.getLength(); i1++) {\r
-            Node node2 = nodes1.item(i1);\r
-            if (node2.getNodeName().equals("trkseg")) {\r
-                Element trkseg = (Element) node2;\r
-                NodeList nodes2 = trkseg.getChildNodes();\r
-                for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
-                    Node node3 = nodes2.item(i2);\r
-                    if (node3.getNodeName().equals("trkpt")) {\r
-                        Element trkpt = (Element) node3;\r
-\r
-                        NodeList nodes3 = trkpt.getChildNodes();\r
-                        for (int i3=0; i3 < nodes3.getLength(); i3++) {\r
-                            Node node4 = nodes3.item(i3);\r
-                            if (node4.getNodeName().equals("time")) {\r
-                                Element time = (Element) node4;\r
-                                NodeList nodes4 = time.getChildNodes();      // 子ノードを取得\r
-                                for (int i4=0; i4< nodes4.getLength(); i4++) {\r
-                                    Node node5 = nodes4.item(i4);\r
-                                    if (node5 != null) {\r
-                                        if (node5.getNodeType() == Node.TEXT_NODE) {\r
-                                            String timeStr = node5.getNodeValue();\r
-                                            long t = dfuk.parse(timeStr).getTime();\r
-                                            map.put(t, getCopy(trk.getOwnerDocument(), trkpt));\r
-                                        }\r
-                                    }\r
+        NodeList nodes2 = trkseg.getChildNodes();\r
+        for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
+            Node node3 = nodes2.item(i2);\r
+            if (node3.getNodeName().equals("trkpt")) {\r
+                Element trkpt = (Element) node3;\r
+\r
+                NodeList nodes3 = trkpt.getChildNodes();\r
+                for (int i3=0; i3 < nodes3.getLength(); i3++) {\r
+                    Node node4 = nodes3.item(i3);\r
+                    if (node4.getNodeName().equals("time")) {\r
+                        Element time = (Element) node4;\r
+                        NodeList nodes4 = time.getChildNodes();      // 子ノードを取得\r
+                        for (int i4=0; i4< nodes4.getLength(); i4++) {\r
+                            Node node5 = nodes4.item(i4);\r
+                            if (node5 != null) {\r
+                                if (node5.getNodeType() == Node.TEXT_NODE) {\r
+                                    String timeStr = node5.getNodeValue();\r
+                                    long t = dfuk.parse(timeStr).getTime();\r
+                                    map.put(t, getCopy(trkseg.getOwnerDocument(), trkpt));\r
                                 }\r
                             }\r
                         }\r
@@ -551,131 +739,104 @@ public class ImportPicture extends Thread {
         }\r
     }\r
 \r
+    \r
     /**\r
      * <trkpt lat="35.32123832" lon="139.56965631">\r
      *          <ele>47.20000076293945</ele>\r
      *          <time>2012-06-15T03:00:29Z</time>\r
      * </trkpt>\r
+     *DIFF_MAE_TIME\r
      * @return\r
      * @param map\r
+     * @param jptime   画像ファイルの撮影日時 ミリ秒(日本時間)\r
+     * @throws ParseException\r
+     */\r
+    public Element trkpt(TreeMap<Long,Element> map, Date jptime) throws ParseException {\r
+       // 指定した時刻のエレメント(imaTrkpt)を取得する\r
+        Element imaE = getTrkpt(map, jptime);\r
+        if (imaE != null) {\r
+               Element maeE = getMaeTrkpt(map, new TagTrkpt(imaE));\r
+            if (maeE != null) {\r
+               Complementation comp = new Complementation(imaE, maeE);\r
+\r
+                // <MAGVAR>がなければ、\r
+                // 直前の位置と、現在地から進行方向を求める\r
+               // 経度(longitude)と経度から進行方向を求める\r
+                if (Complementation.param_GpxOverwriteMagvar) {\r
+                       comp.complementationMagvar();\r
+                }\r
+\r
+                // 緯度・経度と時間差から速度(km/h)を求める\r
+                if (Complementation.param_GpxOutputSpeed) {\r
+                       comp.complementationSpeed();\r
+                }\r
+                imaE = (Element)(comp.imaTag.trkpt.cloneNode(true));\r
+            }\r
+        }\r
+        return imaE;\r
+    }\r
+\r
+    /**\r
+     * [map]から指定した時刻の<trkpt>エレメントを取り出す。\r
+     * GPX時刻との差が10分以上は無効\r
+     * \r
+     * @param map\r
      * @param jptime\r
+     * @return\r
      * @throws ParseException\r
      */\r
-    public static Element trkpt(TreeMap<Long,Element> map, Date jptime) throws ParseException {\r
-        Double R = 20000000 / Math.PI;\r
+    public Element getTrkpt(TreeMap<Long,Element> map, Date jptime) throws ParseException {\r
         long sa = 2L * 3600000L;\r
         long jpt = jptime.getTime();\r
+        \r
         Element ret = null;\r
-        Element mae = null;\r
 \r
         Set<Long> keySet = map.keySet();  //すべてのキー値を取得\r
         Iterator<Long> keyIte = keySet.iterator();\r
         while (keyIte.hasNext()) {    //ループ。反復子iteratorによる キー 取得\r
             Long time = keyIte.next();\r
             long t = time;\r
+\r
             if (Math.abs(jpt - t) < sa) {\r
                 sa = Math.abs(jpt - t);\r
                 ret = map.get(time);\r
-\r
-                // <MAGVAR>がなければ、\r
-                // 直前の位置と、現在地から進行方向を求める\r
-                NodeList nodes3 = ret.getChildNodes();\r
-                Element magvar = null;\r
-                for (int i3=0; i3 < nodes3.getLength(); i3++) {\r
-                    Node node4 = nodes3.item(i3);\r
-                    if (node4.getNodeName().toLowerCase().equals("magvar")) {\r
-                        magvar = (Element) node4;\r
-                        break;\r
-                    }\r
-                }\r
-                if (magvar == null) {\r
-                    if (mae != null) {\r
-                        Double maeLAT = null;\r
-                        Double maeLON = null;\r
-                        Double imaLAT = null;\r
-                        Double imaLON =null;\r
-\r
-                        // 経度(longitude)と経度から進行方向を求める\r
-                        NamedNodeMap nodeMap = mae.getAttributes();\r
-                        if (null != nodeMap) {\r
-                            for (int j=0; j < nodeMap.getLength(); j++ ) {\r
-                                switch (nodeMap.item(j).getNodeName()) {\r
-                                    case "lat":\r
-                                        String latStr = nodeMap.item(j).getNodeValue();\r
-                                        maeLAT = new Double(latStr);\r
-                                        break;\r
-                                    case "lon":\r
-                                        String lonStr = nodeMap.item(j).getNodeValue();\r
-                                        maeLON = new Double(lonStr);\r
-                                        break;\r
-                                }\r
-                            }\r
-                            nodeMap = ret.getAttributes();\r
-                            for (int j=0; j < nodeMap.getLength(); j++ ) {\r
-                                switch (nodeMap.item(j).getNodeName()) {\r
-                                    case "lat":\r
-                                        String latStr = nodeMap.item(j).getNodeValue();\r
-                                        imaLAT = new Double(latStr);\r
-                                        break;\r
-                                    case "lon":\r
-                                        String lonStr = nodeMap.item(j).getNodeValue();\r
-                                        imaLON = new Double(lonStr);\r
-                                        break;\r
-                                }\r
-                            }\r
-                            Double r = Math.cos(Math.toRadians((imaLAT + maeLAT) / 2)) * R;\r
-                            Double x = Math.toRadians(imaLON - maeLON) * r;\r
-                            Double y = Math.toRadians(imaLAT - maeLAT) * R;\r
-                            double rad = Math.toDegrees(Math.atan2(y, x));\r
-                            \r
-                            if (y >= 0) {\r
-                                if (x >= 0) {\r
-                                    rad = 0 - (rad - 90);\r
-                                }\r
-                                else {\r
-                                    rad = 360 - (rad - 90);\r
-                                }\r
-                            }\r
-                            else {\r
-                                if (x >= 0) {\r
-                                    rad = 90 - rad;\r
-                                }\r
-                                else {\r
-                                    rad = 90 - rad;\r
-                                }\r
-                            }\r
-\r
-                            magvar = ret.getOwnerDocument().createElement("magvar");\r
-                            String str = Double.toString(rad);\r
-                            int iDot = str.indexOf('.');\r
-                            if (iDot > 0) {\r
-                                str = str.substring(0, iDot);\r
-                            }\r
-                            magvar.setTextContent(str);\r
-                            ret.appendChild(magvar);\r
-                            \r
-                            Element speed = ret.getOwnerDocument().createElement("speed");\r
-                            str = Double.toString(Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));\r
-                            iDot = str.indexOf('.');\r
-                            if (iDot > 0) {\r
-                                str = str.substring(0, iDot);\r
-                            }\r
-                            speed.setTextContent(str);\r
-                            ret.appendChild(speed);\r
-                        }\r
-                    }\r
-                }\r
             }\r
-            mae = map.get(time);\r
         }\r
 \r
         if (sa < (60000L * 10L)) {\r
-            // System.out.println(dfuk.format(jpt) +" ("+ sa +")");\r
+               // GPX時刻との差が10分以内なら有効\r
             return ret;\r
         }\r
         return null;\r
     }\r
 \r
+    public Element getMaeTrkpt(TreeMap<Long,Element> map, TagTrkpt imaTrkpt) throws ParseException {\r
+        Element ret = null;\r
+        long diffTime = 2L * 3600000L;         // 2時間\r
+        long jpt = imaTrkpt.time.getTime() - DIFF_MAE_TIME;\r
+\r
+        Set<Long> keySet = map.keySet();  //すべてのキー値を取得\r
+        Iterator<Long> keyIte = keySet.iterator();\r
+        while (keyIte.hasNext()) {    //ループ。反復子iteratorによる キー 取得\r
+            Long time = keyIte.next();\r
+            long t = time;\r
+\r
+            if (Math.abs(jpt - t) < diffTime) {\r
+               diffTime = Math.abs(jpt - t);\r
+                ret = map.get(time);\r
+            }\r
+        }\r
+\r
+        if (diffTime < (60000L * 10L)) {\r
+               // GPX時刻との差が10分以内なら有効\r
+               if (diffTime < (imaTrkpt.time.getTime() - 1000)) {\r
+                       // 元の時刻との差が1秒以上あること\r
+                return ret;\r
+               }\r
+        }\r
+        return null;\r
+    }\r
+    \r
     /**\r
      * 対象は '*.JPG' のみ対象とする\r
      * @return \r
@@ -768,6 +929,19 @@ public class ImportPicture extends Thread {
                     }\r
                 }\r
                 break;\r
+            case "speed":\r
+                for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
+                    Node node2 = nodes2.item(i2);\r
+                    if (node2 != null) {\r
+                        if (node2.getNodeType() == Node.TEXT_NODE) {\r
+                            String speedStr = node2.getNodeValue();\r
+                            Element speedE = document.createElement("speed");\r
+                            speedE.setTextContent(speedStr);\r
+                            wpt.appendChild(speedE);\r
+                        }\r
+                    }\r
+                }\r
+                break;\r
             }\r
         }\r
 \r
@@ -839,4 +1013,16 @@ public class ImportPicture extends Thread {
         }\r
     }\r
 \r
+    /**\r
+     * JPEGファイルフィルター\r
+     * @author yuu\r
+     */\r
+       class JpegFileFilter implements FilenameFilter{\r
+       public boolean accept(File dir, String name) {\r
+                       if (name.toUpperCase().matches(".*\\.JPG$")) {\r
+                               return true;\r
+                       }\r
+                       return false;\r
+       }\r
+       }\r
 }
\ No newline at end of file