OSDN Git Service

途中
[importpicture/importpicture.git] / importPicture / src / osm / jp / gpx / ImportPicture.java
1 package osm.jp.gpx;\r
2 import java.io.*;\r
3 import java.text.DecimalFormat;\r
4 import java.text.ParseException;\r
5 import java.text.SimpleDateFormat;\r
6 import java.util.ArrayList;\r
7 import java.util.Arrays;\r
8 import java.util.Calendar;\r
9 import java.util.Comparator;\r
10 import java.util.Date;\r
11 import java.util.GregorianCalendar;\r
12 import java.util.Iterator;\r
13 import java.util.Set;\r
14 import java.util.TimeZone;\r
15 import java.util.TreeMap;\r
16 import java.util.logging.LogManager;\r
17 import java.util.logging.Logger;\r
18 \r
19 import javax.xml.parsers.*;\r
20 import javax.xml.transform.OutputKeys;\r
21 import javax.xml.transform.Transformer;\r
22 import javax.xml.transform.TransformerException;\r
23 import javax.xml.transform.TransformerFactory;\r
24 import javax.xml.transform.dom.DOMSource;\r
25 import javax.xml.transform.stream.StreamResult;\r
26 \r
27 import org.apache.commons.imaging.ImageReadException;\r
28 import org.apache.commons.imaging.ImageWriteException;\r
29 import org.apache.commons.imaging.Imaging;\r
30 import org.apache.commons.imaging.common.ImageMetadata;\r
31 import org.apache.commons.imaging.common.RationalNumber;\r
32 import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;\r
33 import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter;\r
34 import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;\r
35 import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;\r
36 import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants;\r
37 import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;\r
38 import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;\r
39 import org.w3c.dom.*;\r
40 import org.xml.sax.SAXException;\r
41 \r
42 public class ImportPicture extends Thread {\r
43     /**\r
44      * ログ設定プロパティファイルのファイル内容\r
45      */\r
46     protected static final String LOGGING_PROPERTIES_DATA\r
47            = "handlers=java.util.logging.ConsoleHandler\n"\r
48            + ".level=FINEST\n"\r
49            + "java.util.logging.ConsoleHandler.level=INFO\n"\r
50            + "java.util.logging.ConsoleHandler.formatter=osm.jp.gpx.YuuLogFormatter";\r
51 \r
52     /**\r
53      * static initializer によるログ設定の初期化\r
54      */\r
55     public static final Logger logger = Logger.getLogger("CommandLogging");\r
56     static {\r
57         InputStream inStream = null;\r
58         try {\r
59             inStream = new ByteArrayInputStream(LOGGING_PROPERTIES_DATA.getBytes("UTF-8"));\r
60             try {\r
61                 LogManager.getLogManager().readConfiguration(inStream);\r
62                 logger.config("ログ設定: LogManagerを設定しました。");\r
63             }\r
64             catch (IOException e) {\r
65                 logger.warning("ログ設定: LogManager設定の際に例外が発生しました。:" + e.toString());\r
66             }\r
67         }\r
68         catch (UnsupportedEncodingException e) {\r
69             logger.severe("ログ設定: UTF-8エンコーディングがサポートされていません。:" + e.toString());\r
70         }\r
71         finally {\r
72             try {\r
73                 if (inStream != null) {\r
74                     inStream.close();\r
75                 }\r
76             } catch (IOException e) {\r
77                 logger.warning("ログ設定: ログ設定プロパティファイルのストリームクローズ時に例外が発生しました。:"+ e.toString());\r
78             }\r
79         }\r
80     }\r
81     \r
82 \r
83 \r
84     /** メイン\r
85      * 画像ファイルをGPXファイルに取り込みます。\r
86      * \r
87      * ・画像ファイルの更新日付をその画像の撮影日時とします。(Exi情報は無視します)\r
88      *    ※ 対象とするファイルは'*.jpg'のみ\r
89      * ・精確な時刻との時差を入力することで、撮影日時を補正します。\r
90      * ・画像ファイルの更新日付リストをCSV形式のファイルとして出力する。\r
91      * ・・結果は、取り込み元のGPXファイルとは別に、元ファイル名にアンダーバー「_」を付加した.ファイルに出力します。\r
92      *\r
93      * @param argv\r
94      * argv[-] = dummy\r
95      * argv[0] = 画像ファイルが格納されているディレクトリ\r
96      * argv[1] = 時刻補正の基準とする画像ファイル\r
97      * argv[2] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd'T'HH:mm:ss"\r
98      * argv[3] = [noEXIF] EXIF情報の書き換えを行わない / EXIF情報の書き換えを行う(出力先フォルダ)\r
99      * argv[4] = 撮影位置をロギングしたGPXファイル\r
100      * \r
101      * @throws IOException\r
102      * @throws ImageReadException \r
103      */\r
104     public static void main(String[] argv) throws Exception\r
105     {\r
106         Date jptime;\r
107 \r
108         ImportPicture obj = new ImportPicture();\r
109 \r
110         if (argv.length > 0) {\r
111             obj.imgDir = new File(argv[0]);\r
112         }\r
113 \r
114         if (argv.length < 4) {\r
115             System.out.println("!!! Illigal command call. !!!");\r
116             System.out.println("> java -cp .:AdjustTime.jar:commons-imaging-1.0-SNAPSHOT.jar <targetDir> <time base image> <time> {EXIF/not} (gpx)");\r
117             System.out.println("> java -cp .:AdjustTime.jar:commons-imaging-1.0-SNAPSHOT.jar. IMG_01234.JPG 2012-06-15T12:52:22 EXIF");\r
118             System.out.println("> java -cp .:AdjustTime.jar . IMG_01234.JPG 2012-06-15T12:52:22 not");\r
119             System.out.println();\r
120             return;\r
121         }\r
122 \r
123         // 基準時刻ファイルの「更新日時」を使って時刻合わせを行う。\r
124         File baseFile = new File(obj.imgDir, argv[1]);\r
125         jptime = new Date(baseFile.lastModified());\r
126         String timeStr = argv[2];\r
127         try {\r
128             dfjp.setTimeZone(TimeZone.getTimeZone("JST"));\r
129             Date t = dfjp.parse(timeStr);\r
130             obj.delta = t.getTime() - jptime.getTime();\r
131         }\r
132         catch (ParseException e) {\r
133             System.out.println("'"+ timeStr +"' の書式が違います("+ TIME_FORMAT_STRING +")");\r
134         }\r
135 \r
136         // \r
137         if (argv[3].toUpperCase().equals("noEXIF")) {\r
138             obj.exif = false;\r
139             obj.outDir = null;\r
140         }\r
141         else {\r
142             obj.exif = true;\r
143             obj.outDir = new File(argv[3]);\r
144         }\r
145 \r
146         // 第6引数が指定されなければ、指定されたディレクトリ内のGPXファイルすべてを対象とする\r
147         if (argv.length >= 5) {\r
148             obj.gpxDir = new File(argv[4]);\r
149         }\r
150         else {\r
151             obj.gpxDir = obj.imgDir;\r
152         }\r
153         if (obj.gpxDir.isFile()) {\r
154             obj.gpxFiles.add(new File(obj.gpxDir, argv[4]));            \r
155         }\r
156         else {\r
157             File[] files = obj.gpxDir.listFiles();\r
158             for (File file : files) {\r
159                 if (file.isFile()) {\r
160                     String filename = file.getName().toUpperCase();\r
161                     if (filename.endsWith(".GPX")) {\r
162                         if (!filename.endsWith("_.GPX")) {\r
163                             obj.gpxFiles.add(file);\r
164                         }\r
165                     }\r
166                 }\r
167             }\r
168         }\r
169         \r
170         obj.start();\r
171         try {\r
172             obj.join();                            \r
173         } catch(InterruptedException end) {}\r
174     }\r
175     \r
176     public File gpxDir;\r
177     public File imgDir;\r
178     public File outDir;\r
179     public long delta = 0;\r
180     public boolean exif = false;\r
181     public ArrayList<File> gpxFiles = new ArrayList<>();\r
182     \r
183     @Override\r
184     public void run() {\r
185         \r
186         /**\r
187          *\r
188                 <wpt lat="35.25714922" lon="139.15490497">\r
189                         <ele>62.099998474121094</ele>\r
190                         <time>2012-06-11T00:44:38Z</time>\r
191                         <hdop>0.75</hdop>\r
192                         <name><![CDATA[写真]]></name>\r
193                         <cmt><![CDATA[精度: 3.0m]]></cmt>\r
194                         <link href="2012-06-11_09-44-38.jpg">\r
195                                 <text>2012-06-11_09-44-38.jpg</text>\r
196                         </link>\r
197                         <sat>9</sat>\r
198                 </wpt>\r
199          */\r
200         DocumentBuilderFactory factory;\r
201         DocumentBuilder        builder;\r
202         Node gpx;\r
203 \r
204         try {\r
205                 \r
206             outDir = new File(outDir, imgDir.getName());\r
207 \r
208             for (File gpxFile : this.gpxFiles) {\r
209                 String fileName = gpxFile.getName();\r
210                 String iStr = fileName.substring(0, fileName.length() - 4);\r
211 \r
212                 File outputFile = new File(imgDir, iStr +"_.gpx");\r
213                 System.out.println(iStr + " => "+ outputFile.getName());\r
214 \r
215                 factory = DocumentBuilderFactory.newInstance();\r
216                 builder = factory.newDocumentBuilder();\r
217                 factory.setIgnoringElementContentWhitespace(true);\r
218                 factory.setIgnoringComments(true);\r
219                 factory.setValidating(true);\r
220 \r
221                 // GPX file --> Node root\r
222                 DOMImplementation domImpl = builder.getDOMImplementation();\r
223                 document = domImpl.createDocument("", "gpx", null);\r
224 \r
225                 /*\r
226                 <gpx>\r
227                 <trk>\r
228                 <name><![CDATA[Tracked with OSMTracker for Android?]]></name>\r
229                 <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
230                 <trkseg>\r
231                 <trkpt lat="35.32123832" lon="139.56965631">\r
232                 <ele>47.20000076293945</ele>\r
233                 <time>2012-06-15T03:00:29Z</time>\r
234                 <hdop>0.5</hdop>\r
235                 </trkpt>\r
236                 </trkseg>\r
237                 </trk>\r
238                 <wpt lat="35.2564461" lon="139.15437809">\r
239                 </wpt>\r
240                 </gpx>\r
241                 */\r
242                 TreeMap<Long,Element> map = new TreeMap<>();\r
243                 Element trk = null;\r
244                 gpx    = builder.parse(gpxFile).getFirstChild();\r
245                 NodeList nodes = gpx.getChildNodes();\r
246                 for (int i=0; i < nodes.getLength(); i++) {\r
247                     Node node2 = nodes.item(i);\r
248                     if (node2.getNodeName().equals("trk")) {\r
249                         trk = (Element) node2;\r
250                         trkptMap(trk, map);\r
251                     }\r
252                 }\r
253 \r
254                 boolean change = false;\r
255                 if (trk != null) {\r
256                     /*\r
257                     * GPXへ割りつける開始時刻と終了時刻を求める\r
258                     */\r
259                     long gpxStartTime = (new Date()).getTime();         // 対象とする開始時刻(現在時刻)\r
260                     long gpxEndTime = 0L;                                                       // 対象とする終了時刻\r
261                     Set<Long> keySet = map.keySet();  //すべてのキー値を取得\r
262                     for (Long timeLong : keySet) {\r
263                         long gpxTime = timeLong;\r
264                         if (gpxStartTime > gpxTime) {\r
265                             gpxStartTime = gpxTime;\r
266                         }\r
267                         if (gpxEndTime < gpxTime) {\r
268                             gpxEndTime = gpxTime;\r
269                         }\r
270                     }\r
271 \r
272                     System.out.println("           時差: "+ (delta / 1000) +"(sec)");\r
273                     System.out.println("    Target GPX: ["+ gpxFile.getAbsolutePath() +"]");\r
274                     System.out.println("GPX start time: "+ dfjp.format(new Date(gpxStartTime)) + "\t[GMT " + dfuk.format(new Date(gpxStartTime))+"]");\r
275                     System.out.println("  GPX end time: "+ dfjp.format(new Date(gpxEndTime)) + "\t[GMT " + dfuk.format(new Date(gpxEndTime))+"]");\r
276                     System.out.println("          EXIF: "+ (exif ? ("convert to '" + outDir.getAbsolutePath() +"'") : "off"));\r
277                     System.out.println();\r
278                     System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
279                     System.out.println(" name       | UpdateTime         | GPStime            | Latitude   | Longitude  | ele    |magvar|");\r
280                     System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
281                     change = proc(imgDir, delta, gpxStartTime, gpxEndTime, map, exif, gpx);\r
282                     System.out.println("------------|--------------------|--------------------|------------|------------|--------|------|");\r
283                 }\r
284 \r
285                 // 出力\r
286                 if (change) {\r
287                     DOMSource source = new DOMSource(gpx);\r
288                     FileOutputStream os = new FileOutputStream(outputFile);\r
289                     StreamResult result = new StreamResult(os);\r
290                     TransformerFactory transFactory = TransformerFactory.newInstance();\r
291                     Transformer transformer = transFactory.newTransformer();\r
292                     transformer.setOutputProperty(OutputKeys.INDENT, "yes");\r
293                     transformer.setOutputProperty(OutputKeys.METHOD, "xml");\r
294                     transformer.transform(source, result);         \r
295                     if (exif) {\r
296                         outputFile = new File(outDir, iStr +"_.gpx");\r
297                         os = new FileOutputStream(outputFile);\r
298                         result = new StreamResult(os);\r
299                         transformer.transform(source, result);\r
300                     }\r
301                 }\r
302             }\r
303         }\r
304         catch(ParserConfigurationException | DOMException | SAXException | IOException | ParseException | ImageReadException | ImageWriteException | IllegalArgumentException | TransformerException e) {\r
305         }\r
306     }\r
307         \r
308     /**\r
309      * 再帰メソッド\r
310      * @throws ParseException \r
311      * @throws IOException \r
312      * @throws ImageReadException \r
313      * @throws ImageWriteException \r
314      */\r
315     boolean proc(File dir, long delta, long gpxStartTime, long gpxEndTime, TreeMap<Long,Element> map, boolean exifWrite, Node gpx) throws ParseException, ImageReadException, IOException, ImageWriteException {\r
316         DecimalFormat yearFormatter = new DecimalFormat("0000");\r
317         DecimalFormat monthFormatter = new DecimalFormat("00");\r
318         DecimalFormat dayFormatter = new DecimalFormat("00");\r
319 \r
320         boolean ret = false;\r
321         File[] files = dir.listFiles();\r
322         Arrays.sort(files, new FileSort());\r
323         for (File image : files) {\r
324             if (image.isDirectory()) {\r
325                 ret = proc(image, delta, gpxStartTime, gpxEndTime, map, exifWrite, gpx);\r
326             }\r
327             else {\r
328                 String imageName = image.getName();\r
329                 if (checkFile(imageName)) {\r
330                     Date itime = new Date(image.lastModified());\r
331                     Date uktime = new Date(itime.getTime() + delta);\r
332                     if ((uktime.getTime() >= gpxStartTime) && (uktime.getTime() <= gpxEndTime)) {\r
333                         Element trkpt = trkpt(map, uktime);\r
334                         if (trkpt != null) {\r
335                             Element wpt = createWptTag(image, uktime.getTime(), trkpt);\r
336                             String latStr = wpt.getAttribute("lat");\r
337                             String lonStr = wpt.getAttribute("lon");\r
338                             double latitude = Double.parseDouble(latStr);\r
339                             double longitude = Double.parseDouble(lonStr);\r
340                             \r
341                             String eleStr = "-";\r
342                             String magvarStr = "-";\r
343                             NodeList nodes = wpt.getChildNodes();      // 子ノードを取得\r
344                             for (int i4 = 0; i4 < nodes.getLength(); i4++) {\r
345                                 Node node = nodes.item(i4);\r
346                                 if (node != null) {\r
347                                     switch (node.getNodeName()) {\r
348                                         case "ele":\r
349                                             eleStr = node.getFirstChild().getNodeValue();\r
350                                             break;\r
351                                         case "magvar":\r
352                                             magvarStr = node.getFirstChild().getNodeValue();\r
353                                             break;\r
354                                     }\r
355                                 }\r
356                             }\r
357 \r
358                             System.out.print(String.format("%12s|", image.getName()));\r
359                             System.out.print(String.format("%20s ", dfjp.format(itime)));\r
360                             System.out.print(String.format("%20s|", dfjp.format(uktime)));\r
361                             System.out.print(String.format("%12s %12s|", latStr, lonStr));\r
362                             System.out.println(String.format("%8s|%6s|", eleStr, magvarStr));\r
363                             ret = true;\r
364 \r
365                             if (exifWrite) {\r
366                                 TiffOutputSet outputSet = null;\r
367                                 FileOutputStream fos = null;\r
368 \r
369                                 ImageMetadata meta = Imaging.getMetadata(image);\r
370                                 JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta;\r
371                                 if (jpegMetadata != null) {\r
372                                     TiffImageMetadata exif = jpegMetadata.getExif();\r
373                                     if (exif != null) {\r
374                                         outputSet = exif.getOutputSet();\r
375                                     }\r
376                                 }\r
377 \r
378                                 if (outputSet == null) {\r
379                                     System.out.println("added : new tiff output set");\r
380                                     outputSet = new TiffOutputSet();\r
381                                 }\r
382 \r
383                                 //---- EXIF_TAG_DATE_TIME_ORIGINAL / 「撮影日時/オリジナル画像の生成日時」----\r
384                                 TiffOutputDirectory exifDir = outputSet.getOrCreateExifDirectory();\r
385                                 {\r
386                                     Calendar cal = GregorianCalendar.getInstance();\r
387                                     cal.setTime(uktime);\r
388                                     exifDir.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);\r
389                                     exifDir.add(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, new SimpleDateFormat("yyyy:MM:dd HH:mm:ss").format(cal.getTime()));\r
390                                 }\r
391 \r
392                                 //---- EXIF GPS_TIME_STAMP ----\r
393                                 TiffOutputDirectory gpsDir = outputSet.getOrCreateGPSDirectory();\r
394                                 {\r
395                                     Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));\r
396                                     cal.setTime(uktime);\r
397                                     final String yearStr = yearFormatter.format(cal.get(Calendar.YEAR));\r
398                                     final String monthStr = monthFormatter.format(cal.get(Calendar.MONTH) + 1);\r
399                                     final String dayStr = dayFormatter.format(cal.get(Calendar.DAY_OF_MONTH));\r
400                                     final String dateStamp = yearStr +":"+ monthStr +":"+ dayStr;\r
401 \r
402                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP);\r
403                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP,\r
404                                             RationalNumber.valueOf(cal.get(Calendar.HOUR_OF_DAY)),\r
405                                             RationalNumber.valueOf(cal.get(Calendar.MINUTE)),\r
406                                             RationalNumber.valueOf(cal.get(Calendar.SECOND)));\r
407                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP);\r
408                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP, dateStamp);\r
409                                 }\r
410 \r
411                                 //---- EXIF GPS elevation/ALTITUDE ----\r
412                                 if (eleStr.equals("-") == false) {\r
413                                     final double altitude = Double.parseDouble(eleStr);\r
414                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE);\r
415                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(altitude));\r
416                                 }\r
417 \r
418                                 //---- EXIF GPS magvar/IMG_DIRECTION ----\r
419                                 if (magvarStr.equals("-") == false) {\r
420                                     final double magvar = Double.parseDouble(magvarStr);\r
421                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION);\r
422                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, RationalNumber.valueOf(magvar));\r
423                                 }\r
424 \r
425                                 //---- EXIF GPS_ ----\r
426                                 final String longitudeRef = (longitude < 0 ? "W" : "E");\r
427                                 longitude = Math.abs(longitude);\r
428                                 final String latitudeRef = (latitude < 0 ? "S" : "N");\r
429                                 latitude = Math.abs(latitude);\r
430 \r
431                                 gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);\r
432                                 gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF, longitudeRef);\r
433                                 gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);\r
434                                 gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF, latitudeRef);\r
435                                 {\r
436                                     double value = longitude;\r
437                                     final double longitudeDegrees = (long) value;\r
438                                     value %= 1;\r
439                                     value *= 60.0;\r
440                                     final double longitudeMinutes = (long) value;\r
441                                     value %= 1;\r
442                                     value *= 60.0;\r
443                                     final double longitudeSeconds = value;\r
444                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);\r
445                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LONGITUDE,\r
446                                             RationalNumber.valueOf(longitudeDegrees),\r
447                                             RationalNumber.valueOf(longitudeMinutes),\r
448                                             RationalNumber.valueOf(longitudeSeconds));\r
449                                 }\r
450                                 {\r
451                                     double value = latitude;\r
452                                     final double latitudeDegrees = (long) value;\r
453                                     value %= 1;\r
454                                     value *= 60.0;\r
455                                     final double latitudeMinutes = (long) value;\r
456                                     value %= 1;\r
457                                     value *= 60.0;\r
458                                     final double latitudeSeconds = value;\r
459                                     gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE);\r
460                                     gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE,\r
461                                             RationalNumber.valueOf(latitudeDegrees),\r
462                                             RationalNumber.valueOf(latitudeMinutes),\r
463                                             RationalNumber.valueOf(latitudeSeconds));\r
464                                 }\r
465 \r
466                                 outDir.mkdir();\r
467                                 ExifRewriter rewriter = new ExifRewriter();\r
468                                 try {\r
469                                     fos = new FileOutputStream(new File(outDir, imageName));\r
470                                     rewriter.updateExifMetadataLossy(image, fos, outputSet);\r
471                                 }\r
472                                 finally {\r
473                                     if (fos != null) {\r
474                                         fos.close();\r
475                                     }\r
476                                 }\r
477                             }\r
478 \r
479                             Element temp = getCopy(gpx.getOwnerDocument(), wpt);\r
480                             gpx.appendChild(temp);\r
481                         }\r
482                     }\r
483                 }\r
484             }\r
485         }\r
486         return ret;\r
487     }\r
488         \r
489     static Document document;\r
490 \r
491     /**\r
492      * 2012-06-10T05:09:46Z  (日本時間の'2012-06-10T14:09:46')\r
493      */\r
494     public static final String TIME_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss";\r
495     public static SimpleDateFormat dfjp = new SimpleDateFormat(TIME_FORMAT_STRING);\r
496     public static SimpleDateFormat dfuk = new SimpleDateFormat(TIME_FORMAT_STRING +"'Z'");\r
497 \r
498     /**\r
499      * XMLエレメント<trkpt>をTIMEでキー付したHashMapを生成する<br>\r
500      * \r
501      *  <trk><trkseg><trkpt><time>2014-01-01T00:59:09Z</time></trkpt></trkseg></trk>\r
502      * \r
503      * @param trk\r
504      * @param map\r
505      * @throws ParseException\r
506      */\r
507     public static void trkptMap(Element trk, TreeMap<Long,Element> map) throws ParseException {\r
508         dfuk.setTimeZone(TimeZone.getTimeZone("GMT"));\r
509 \r
510         NodeList nodes1 = trk.getChildNodes();\r
511         for (int i1=0; i1 < nodes1.getLength(); i1++) {\r
512             Node node2 = nodes1.item(i1);\r
513             if (node2.getNodeName().equals("trkseg")) {\r
514                 Element trkseg = (Element) node2;\r
515                 NodeList nodes2 = trkseg.getChildNodes();\r
516                 for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
517                     Node node3 = nodes2.item(i2);\r
518                     if (node3.getNodeName().equals("trkpt")) {\r
519                         Element trkpt = (Element) node3;\r
520 \r
521                         NodeList nodes3 = trkpt.getChildNodes();\r
522                         for (int i3=0; i3 < nodes3.getLength(); i3++) {\r
523                             Node node4 = nodes3.item(i3);\r
524                             if (node4.getNodeName().equals("time")) {\r
525                                 Element time = (Element) node4;\r
526                                 NodeList nodes4 = time.getChildNodes();      // 子ノードを取得\r
527                                 for (int i4=0; i4< nodes4.getLength(); i4++) {\r
528                                     Node node5 = nodes4.item(i4);\r
529                                     if (node5 != null) {\r
530                                         if (node5.getNodeType() == Node.TEXT_NODE) {\r
531                                             String timeStr = node5.getNodeValue();\r
532                                             long t = dfuk.parse(timeStr).getTime();\r
533                                             map.put(t, getCopy(trk.getOwnerDocument(), trkpt));\r
534                                         }\r
535                                     }\r
536                                 }\r
537                             }\r
538                         }\r
539                     }\r
540                 }\r
541             }\r
542         }\r
543     }\r
544 \r
545     /**\r
546      *  <trkpt lat="35.32123832" lon="139.56965631">\r
547      *          <ele>47.20000076293945</ele>\r
548      *          <time>2012-06-15T03:00:29Z</time>\r
549      *  </trkpt>\r
550      * @return\r
551      * @param map\r
552      * @param jptime\r
553      * @throws ParseException\r
554      */\r
555     public static Element trkpt(TreeMap<Long,Element> map, Date jptime) throws ParseException {\r
556         Double R = 20000000 / Math.PI;\r
557         long sa = 2L * 3600000L;\r
558         long jpt = jptime.getTime();\r
559         Element ret = null;\r
560         Element mae = null;\r
561 \r
562         Set<Long> keySet = map.keySet();  //すべてのキー値を取得\r
563         Iterator<Long> keyIte = keySet.iterator();\r
564         while (keyIte.hasNext()) {    //ループ。反復子iteratorによる キー 取得\r
565             Long time = keyIte.next();\r
566             long t = time;\r
567             if (Math.abs(jpt - t) < sa) {\r
568                 sa = Math.abs(jpt - t);\r
569                 ret = map.get(time);\r
570 \r
571                 // <MAGVAR>がなければ、\r
572                 // 直前の位置と、現在地から進行方向を求める\r
573                 NodeList nodes3 = ret.getChildNodes();\r
574                 Element magvar = null;\r
575                 for (int i3=0; i3 < nodes3.getLength(); i3++) {\r
576                     Node node4 = nodes3.item(i3);\r
577                     if (node4.getNodeName().toLowerCase().equals("magvar")) {\r
578                         magvar = (Element) node4;\r
579                         break;\r
580                     }\r
581                 }\r
582                 if (magvar == null) {\r
583                     if (mae != null) {\r
584                         Double maeLAT = null;\r
585                         Double maeLON = null;\r
586                         Double imaLAT = null;\r
587                         Double imaLON =null;\r
588 \r
589                         // 経度(longitude)と経度から進行方向を求める\r
590                         NamedNodeMap nodeMap = mae.getAttributes();\r
591                         if (null != nodeMap) {\r
592                             for (int j=0; j < nodeMap.getLength(); j++ ) {\r
593                                 switch (nodeMap.item(j).getNodeName()) {\r
594                                     case "lat":\r
595                                         String latStr = nodeMap.item(j).getNodeValue();\r
596                                         maeLAT = new Double(latStr);\r
597                                         break;\r
598                                     case "lon":\r
599                                         String lonStr = nodeMap.item(j).getNodeValue();\r
600                                         maeLON = new Double(lonStr);\r
601                                         break;\r
602                                 }\r
603                             }\r
604                             nodeMap = ret.getAttributes();\r
605                             for (int j=0; j < nodeMap.getLength(); j++ ) {\r
606                                 switch (nodeMap.item(j).getNodeName()) {\r
607                                     case "lat":\r
608                                         String latStr = nodeMap.item(j).getNodeValue();\r
609                                         imaLAT = new Double(latStr);\r
610                                         break;\r
611                                     case "lon":\r
612                                         String lonStr = nodeMap.item(j).getNodeValue();\r
613                                         imaLON = new Double(lonStr);\r
614                                         break;\r
615                                 }\r
616                             }\r
617                             Double r = Math.cos(Math.toRadians((imaLAT + maeLAT) / 2)) * R;\r
618                             Double x = Math.toRadians(imaLON - maeLON) * r;\r
619                             Double y = Math.toRadians(imaLAT - maeLAT) * R;\r
620                             double rad = Math.toDegrees(Math.atan2(y, x));\r
621                             \r
622                             if (y >= 0) {\r
623                                 if (x >= 0) {\r
624                                     rad = 0 - (rad - 90);\r
625                                 }\r
626                                 else {\r
627                                     rad = 360 - (rad - 90);\r
628                                 }\r
629                             }\r
630                             else {\r
631                                 if (x >= 0) {\r
632                                     rad = 90 - rad;\r
633                                 }\r
634                                 else {\r
635                                     rad = 90 - rad;\r
636                                 }\r
637                             }\r
638 \r
639                             magvar = ret.getOwnerDocument().createElement("magvar");\r
640                             String str = Double.toString(rad);\r
641                             int iDot = str.indexOf('.');\r
642                             if (iDot > 0) {\r
643                                 str = str.substring(0, iDot);\r
644                             }\r
645                             magvar.setTextContent(str);\r
646                             ret.appendChild(magvar);\r
647                             \r
648                             Element speed = ret.getOwnerDocument().createElement("speed");\r
649                             str = Double.toString(Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));\r
650                             iDot = str.indexOf('.');\r
651                             if (iDot > 0) {\r
652                                 str = str.substring(0, iDot);\r
653                             }\r
654                             speed.setTextContent(str);\r
655                             ret.appendChild(speed);\r
656                         }\r
657                     }\r
658                 }\r
659             }\r
660             mae = map.get(time);\r
661         }\r
662 \r
663         if (sa < (60000L * 10L)) {\r
664             // System.out.println(dfuk.format(jpt) +" ("+ sa +")");\r
665             return ret;\r
666         }\r
667         return null;\r
668     }\r
669 \r
670     /**\r
671      * 対象は '*.JPG' のみ対象とする\r
672      * @return \r
673      * @param name\r
674      */\r
675     public static boolean checkFile(String name) {\r
676         return ((name != null) && name.toUpperCase().endsWith(".JPG"));\r
677     }\r
678 \r
679     /**\r
680      *  <wpt lat="35.25714922" lon="139.15490497">\r
681      *          <ele>62.099998474121094</ele>\r
682      *          <time>2012-06-11T00:44:38Z</time>\r
683      *          <name><![CDATA[写真]]></name>\r
684      *          <link href="2012-06-11_09-44-38.jpg">\r
685      *                  <text>2012-06-11_09-44-38.jpg</text>\r
686      *          </link>\r
687      *  </wpt>\r
688      *\r
689      *  <trkpt lat="35.32123832" lon="139.56965631">\r
690      *          <ele>47.20000076293945</ele>\r
691      *          <time>2012-06-15T03:00:29Z</time>\r
692      *  </trkpt>\r
693      *\r
694      * @return\r
695      * @param iFile\r
696      * @param timestamp\r
697      * @param trkpt\r
698      */\r
699     public Element createWptTag(File iFile, long timestamp, Element trkpt) {\r
700         Element wpt = document.createElement("wpt");\r
701 \r
702         NamedNodeMap nodeMap = trkpt.getAttributes();\r
703         if (null != nodeMap) {\r
704             for (int j=0; j < nodeMap.getLength(); j++ ) {\r
705                 switch (nodeMap.item(j).getNodeName()) {\r
706                 case "lat":\r
707                     String lat = nodeMap.item(j).getNodeValue();\r
708                     wpt.setAttribute("lat", lat);\r
709                     break;\r
710                 case "lon":\r
711                     String lon = nodeMap.item(j).getNodeValue();\r
712                     wpt.setAttribute("lon", lon);\r
713                     break;\r
714                 }\r
715             }\r
716         }\r
717 \r
718         NodeList nodes1 = trkpt.getChildNodes();\r
719         for (int i1=0; i1 < nodes1.getLength(); i1++) {\r
720             Node node1 = nodes1.item(i1);\r
721             NodeList nodes2 = node1.getChildNodes();\r
722             switch (node1.getNodeName()) {\r
723             case "ele":\r
724                 for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
725                     Node node2 = nodes2.item(i2);\r
726                     if (node2 != null) {\r
727                         if (node2.getNodeType() == Node.TEXT_NODE) {\r
728                             String eleStr = node2.getNodeValue();\r
729                             Element eleE = document.createElement("ele");\r
730                             eleE.setTextContent(eleStr);\r
731                             wpt.appendChild(eleE);\r
732                         }\r
733                     }\r
734                 }\r
735                 break;\r
736             case "time":\r
737                 for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
738                     Node node2 = nodes2.item(i2);\r
739                     if (node2 != null) {\r
740                         if (node2.getNodeType() == Node.TEXT_NODE) {\r
741                             String timeStr = node2.getNodeValue();\r
742                             Element timeE = document.createElement("time");\r
743                             timeE.setTextContent(timeStr);\r
744                             wpt.appendChild(timeE);\r
745                         }\r
746                     }\r
747                 }\r
748                 break;\r
749             case "magvar":\r
750                 for (int i2=0; i2 < nodes2.getLength(); i2++) {\r
751                     Node node2 = nodes2.item(i2);\r
752                     if (node2 != null) {\r
753                         if (node2.getNodeType() == Node.TEXT_NODE) {\r
754                             String magvarStr = node2.getNodeValue();\r
755                             Element magvarE = document.createElement("magvar");\r
756                             magvarE.setTextContent(magvarStr);\r
757                             wpt.appendChild(magvarE);\r
758                         }\r
759                     }\r
760                 }\r
761                 break;\r
762             }\r
763         }\r
764 \r
765         Element name = document.createElement("name");\r
766         name.appendChild(document.createCDATASection("写真"));\r
767         wpt.appendChild(name);\r
768 \r
769         Element link = document.createElement("link");\r
770         link.setAttribute("href", getShortPathName(imgDir, iFile));\r
771         Element text = document.createElement("text");\r
772         text.setTextContent(iFile.getName());\r
773         link.appendChild(text);\r
774         wpt.appendChild(link);\r
775 \r
776         return wpt;\r
777     }\r
778         \r
779     static String getShortPathName(File dir, File iFile) {\r
780         String dirPath = dir.getAbsolutePath();\r
781         String filePath = iFile.getAbsolutePath();\r
782         if (filePath.startsWith(dirPath)) {\r
783             return filePath.substring(dirPath.length()+1);\r
784         }\r
785         else {\r
786             return filePath;\r
787         }\r
788     }\r
789 \r
790     public static Element getCopy(Document doc, Node node) {\r
791         Element root = doc.createElement(node.getNodeName());\r
792 \r
793         NamedNodeMap nodeMap = node.getAttributes();\r
794         if (null != nodeMap) {\r
795             for (int j=0; j < nodeMap.getLength(); j++ ) {\r
796                 root.setAttribute(nodeMap.item(j).getNodeName(), nodeMap.item(j).getNodeValue());\r
797             }\r
798         }\r
799 \r
800         NodeList nodes = node.getChildNodes();\r
801         for (int i=0; i < nodes.getLength(); i++) {\r
802             Node node2 = nodes.item(i);\r
803             if (node2.getNodeType() == Node.ELEMENT_NODE) {\r
804                 root.appendChild(getCopy(doc, node2));\r
805             }\r
806             else if (node2.getNodeType() == Node.TEXT_NODE) {\r
807                 String str = node2.getNodeValue();\r
808                 Text textContents = doc.createTextNode(str);\r
809                 root.appendChild(textContents);\r
810             }\r
811             else if (node2.getNodeType() == Node.CDATA_SECTION_NODE) {\r
812                 String str = node2.getNodeValue();\r
813                 CDATASection cdataSection = doc.createCDATASection(str);\r
814                 root.appendChild(cdataSection);\r
815             }\r
816         }\r
817         return root;\r
818     }\r
819         \r
820     /**\r
821      * ファイル名の順序に並び替えるためのソートクラス\r
822      * \r
823      * @author hayashi\r
824      */\r
825     static class FileSort implements Comparator<File>{\r
826         @Override\r
827         public int compare(File src, File target){\r
828             int diff = src.getName().compareTo(target.getName());\r
829             return diff;\r
830         }\r
831     }\r
832 \r
833 }