OSDN Git Service

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