OSDN Git Service

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