3 import java.text.ParseException;
\r
4 import java.text.SimpleDateFormat;
\r
5 import java.util.ArrayList;
\r
6 import java.util.Arrays;
\r
7 import java.util.Comparator;
\r
8 import java.util.Date;
\r
9 import java.util.HashMap;
\r
10 import java.util.Iterator;
\r
11 import java.util.Locale;
\r
12 import java.util.Set;
\r
13 import java.util.logging.LogManager;
\r
14 import java.util.logging.Logger;
\r
16 import javax.xml.parsers.*;
\r
17 import javax.xml.transform.OutputKeys;
\r
18 import javax.xml.transform.Transformer;
\r
19 import javax.xml.transform.TransformerConfigurationException;
\r
20 import javax.xml.transform.TransformerException;
\r
21 import javax.xml.transform.TransformerFactory;
\r
22 import javax.xml.transform.dom.DOMSource;
\r
23 import javax.xml.transform.stream.StreamResult;
\r
25 import org.w3c.dom.*;
\r
26 import org.xml.sax.SAXException;
\r
28 public class ImportPicture {
\r
29 public static File gpxDir = new File(".");
\r
32 * ログ設定プロパティファイルのファイル内容
\r
34 protected static final String LOGGING_PROPERTIES_DATA
\r
35 = "handlers=java.util.logging.ConsoleHandler\n"
\r
37 + "java.util.logging.ConsoleHandler.level=INFO\n"
\r
38 + "java.util.logging.ConsoleHandler.formatter=hayashi.yuu.tools.logger.YuuLogFormatter";
\r
41 * static initializer によるログ設定の初期化
\r
43 public static final Logger logger = Logger.getLogger("SampleLogging");
\r
45 InputStream inStream = null;
\r
47 inStream = new ByteArrayInputStream(LOGGING_PROPERTIES_DATA.getBytes("UTF-8"));
\r
49 LogManager.getLogManager().readConfiguration(inStream);
\r
50 logger.config("ログ設定: LogManagerを設定しました。");
\r
52 catch (IOException e) {
\r
53 logger.warning("ログ設定: LogManager設定の際に例外が発生しました。:" + e.toString());
\r
56 catch (UnsupportedEncodingException e) {
\r
57 logger.severe("ログ設定: UTF-8エンコーディングがサポートされていません。:" + e.toString());
\r
61 if (inStream != null) {
\r
64 } catch (IOException e) {
\r
65 logger.warning("ログ設定: ログ設定プロパティファイルのストリームクローズ時に例外が発生しました。:"+ e.toString());
\r
71 * 画像ファイルをGPXファイルに取り込みます。
\r
73 * ・画像ファイルの更新日付をその画像の撮影日時とします。(Exi情報は無視します)
\r
74 * ※ 対象とするファイルは'*.jpg'のみ
\r
75 * ・精確な時刻との時差を入力することで、撮影日時を補正します。
\r
76 * ・画像ファイルの更新日付リストをCSV形式のファイルとして出力する。
\r
77 * ・・結果は、取り込み元のGPXファイルとは別に、元ファイル名にアンダーバー「_」を付加した.ファイルに出力します。
\r
80 * argv[0] = 画像ファイルが格納されているディレクトリ
\r
81 * argv[1] = 時刻補正の基準とする画像ファイル
\r
82 * argv[2] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd'T'HH:mm:ss"
\r
83 * argv[3] = 撮影位置をロギングしたGPXファイル
\r
85 * @throws IOException
\r
87 public static void main(String[] argv) throws IOException
\r
91 if (argv.length > 0) {
\r
92 gpxDir = new File(argv[0]);
\r
95 if (argv.length < 3) {
\r
96 System.out.println("> java -jar importPicture.jar <targetDir> <time base image> <time> (gpx)");
\r
97 System.out.println("> java -jar importPicture.jar . IMG_01234.JPG 2012-06-15T12:52:22");
\r
100 // 基準時刻ファイルの「更新日時」を使って時刻合わせを行う。
\r
101 File baseFile = new File(gpxDir, argv[1]);
\r
102 jptime = new Date(baseFile.lastModified());
\r
104 // 第5引数が指定されなければ、指定されたディレクトリ内のGPXファイルすべてを対象とする
\r
105 ArrayList<File> gpxFiles = new ArrayList<File>();
\r
106 if (argv.length > 3) {
\r
107 gpxFiles.add(new File(gpxDir, argv[3]));
\r
110 File[] files = gpxDir.listFiles();
\r
111 for (int i=0; i < files.length; i++) {
\r
112 if (files[i].isFile()) {
\r
113 String filename = files[i].getName().toUpperCase();
\r
114 if (filename.endsWith(".GPX")) {
\r
115 if (!filename.endsWith("_.GPX")) {
\r
116 gpxFiles.add(files[i]);
\r
126 <wpt lat="35.25714922" lon="139.15490497">
\r
127 <ele>62.099998474121094</ele>
\r
128 <time>2012-06-11T00:44:38Z</time>
\r
130 <name><![CDATA[写真]]></name>
\r
131 <cmt><![CDATA[精度: 3.0m]]></cmt>
\r
132 <link href="2012-06-11_09-44-38.jpg">
\r
133 <text>2012-06-11_09-44-38.jpg</text>
\r
138 DocumentBuilderFactory factory;
\r
139 DocumentBuilder builder;
\r
143 for (int gpxCnt = 0; gpxCnt < gpxFiles.size(); gpxCnt++) {
\r
144 File gpxFile = gpxFiles.get(gpxCnt);
\r
145 String fileName = gpxFile.getName();
\r
146 String iStr = fileName.substring(0, fileName.length() - 4);
\r
148 File outputFile = new File(gpxFile.getParent(), iStr +"_.gpx");
\r
149 System.out.println(iStr + " => "+ outputFile.getName());
\r
151 factory = DocumentBuilderFactory.newInstance();
\r
152 builder = factory.newDocumentBuilder();
\r
153 factory.setIgnoringElementContentWhitespace(true);
\r
154 factory.setIgnoringComments(true);
\r
155 factory.setValidating(true);
\r
157 // GPX file --> Node root
\r
158 DOMImplementation domImpl = builder.getDOMImplementation();
\r
159 document = domImpl.createDocument("", "gpx", null);
\r
164 <name><![CDATA[Tracked with OSMTracker for Android?]]></name>
\r
165 <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
167 <trkpt lat="35.32123832" lon="139.56965631">
\r
168 <ele>47.20000076293945</ele>
\r
169 <time>2012-06-15T03:00:29Z</time>
\r
174 <wpt lat="35.2564461" lon="139.15437809">
\r
178 Element trk = null;
\r
179 gpx = builder.parse(gpxFile).getFirstChild();
\r
180 NodeList nodes = gpx.getChildNodes();
\r
181 for (int i=0; i < nodes.getLength(); i++) {
\r
182 Node node2 = nodes.item(i);
\r
183 if (node2.getNodeName().equals("trk")) {
\r
184 trk = (Element) node2;
\r
189 HashMap<Long,Element> map = trkptMap(trk);
\r
191 String timeStr = argv[2];
\r
193 Date t = dfjp.parse(timeStr);
\r
194 long delta = t.getTime() - jptime.getTime();
\r
197 * GPXへ割りつける開始時刻と終了時刻を求める
\r
199 long gpxStartTime = (new Date()).getTime(); // 対象とする開始時刻
\r
200 long gpxEndTime = 0L; // 対象とする終了時刻
\r
201 Set<Long> keySet = map.keySet(); //すべてのキー値を取得
\r
202 for (Iterator<Long> keyIte = keySet.iterator(); keyIte.hasNext();) {
\r
203 Long timeLong = (Long)keyIte.next();
\r
204 long gpxTime = timeLong.longValue();
\r
205 if (gpxStartTime > gpxTime) {
\r
206 gpxStartTime = gpxTime;
\r
208 if (gpxEndTime < gpxTime) {
\r
209 gpxEndTime = gpxTime;
\r
213 System.out.println(" 時差: "+ (delta / 1000) +"(sec)");
\r
214 System.out.println(" Target GPX: ["+ gpxFile.getName() +"]");
\r
215 System.out.println("GPX start time: "+ dfjp.format(new Date(gpxStartTime).getTime()));
\r
216 System.out.println(" GPX end time: "+ dfjp.format(new Date(gpxEndTime).getTime()));
\r
217 System.out.println();
\r
218 System.out.println("------------|--------------------|--------------------|--------|-------|--------");
\r
219 System.out.println(" name | UpdateTime | GPStime | LAT | LON | ele");
\r
220 System.out.println("------------|--------------------|--------------------|--------|-------|--------");
\r
221 proc(gpxDir, delta, gpxStartTime, gpxEndTime, map, gpx);
\r
222 System.out.println("------------|--------------------|--------------------|--------|-------|--------");
\r
224 catch (ParseException e) {
\r
225 System.out.println("'"+ timeStr +"' の書式が違います("+ TIME_FORMAT_STRING +")");
\r
230 DOMSource source = new DOMSource(gpx);
\r
231 FileOutputStream os = new FileOutputStream(outputFile);
\r
232 StreamResult result = new StreamResult(os);
\r
233 TransformerFactory transFactory = TransformerFactory.newInstance();
\r
234 Transformer transformer = transFactory.newTransformer();
\r
235 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
\r
236 transformer.setOutputProperty(OutputKeys.METHOD, "xml");
\r
237 transformer.transform(source, result);
\r
240 catch (ParserConfigurationException e) {
\r
241 e.printStackTrace();
\r
243 catch (SAXException e) {
\r
244 e.printStackTrace();
\r
246 catch (TransformerConfigurationException e) {
\r
247 e.printStackTrace();
\r
249 catch (TransformerException e) {
\r
250 e.printStackTrace();
\r
251 } catch (ParseException e) {
\r
252 e.printStackTrace();
\r
260 * @throws ParseException
\r
262 static void proc(File dir, long delta, long gpxStartTime, long gpxEndTime, HashMap<Long,Element> map, Node gpx) throws ParseException {
\r
263 File[] files = dir.listFiles();
\r
264 Arrays.sort(files, new FileSort());
\r
265 for (File image : files) {
\r
266 if (image.isDirectory()) {
\r
267 proc(image, delta, gpxStartTime, gpxEndTime, map, gpx);
\r
270 String imageName = image.getName();
\r
271 if (checkFile(imageName)) {
\r
272 Date itime = new Date(image.lastModified());
\r
273 Date uktime = new Date(itime.getTime() + delta);
\r
274 if ((uktime.getTime() >= gpxStartTime) && (uktime.getTime() <= gpxEndTime)) {
\r
275 Element trkpt = trkpt(map, uktime);
\r
276 if (trkpt != null) {
\r
277 System.out.print(String.format("%12s ", image.getName()));
\r
278 System.out.print(String.format("%19s ", dfjp.format(itime)));
\r
279 System.out.print(String.format("%19s ", dfjp.format(uktime)));
\r
281 Element wpt = createWptTag(image, uktime.getTime(), trkpt);
\r
282 System.out.print(String.format("%12s ", wpt.getAttribute("lat")));
\r
283 System.out.print(String.format("%12s "+ wpt.getAttribute("lon")));
\r
285 NodeList nodes = wpt.getChildNodes(); // 子ノードを取得
\r
286 for (int i4=0; i4< nodes.getLength(); i4++) {
\r
287 Node node = nodes.item(i4);
\r
288 if (node != null) {
\r
289 if (node.getNodeType() == Node.TEXT_NODE) {
\r
290 String eleStr = node.getNodeValue();
\r
291 System.out.println(eleStr);
\r
296 Element temp = getCopy(gpx.getOwnerDocument(), wpt);
\r
297 gpx.appendChild(temp);
\r
306 static Document document;
\r
309 * 2012-06-10T05:09:46Z (日本時間の'2012-06-10T14:09:46')
\r
311 public static final String TIME_FORMAT_STRING = "yyyy-MM-dd'T'HH:mm:ss";
\r
312 public static SimpleDateFormat dfjp = new SimpleDateFormat(TIME_FORMAT_STRING);
\r
313 public static SimpleDateFormat dfuk = new SimpleDateFormat(TIME_FORMAT_STRING +"'Z'", Locale.UK);
\r
316 * XMLエレメント<trkpt>をTIMEでキー付したHashMapを生成する<br>
\r
318 * <trk><trkseg><trkpt><time>2014-01-01T00:59:09Z</time></trkpt></trkseg></trk>
\r
322 * @throws ParseException
\r
324 public static HashMap<Long,Element> trkptMap(Element trk) throws ParseException {
\r
325 HashMap<Long,Element> map = new HashMap<Long,Element>();
\r
327 NodeList nodes1 = trk.getChildNodes();
\r
328 for (int i1=0; i1 < nodes1.getLength(); i1++) {
\r
329 Node node2 = nodes1.item(i1);
\r
330 if (node2.getNodeName().equals("trkseg")) {
\r
331 Element trkseg = (Element) node2;
\r
332 NodeList nodes2 = trkseg.getChildNodes();
\r
333 for (int i2=0; i2 < nodes2.getLength(); i2++) {
\r
334 Node node3 = nodes2.item(i2);
\r
335 if (node3.getNodeName().equals("trkpt")) {
\r
336 Element trkpt = (Element) node3;
\r
338 NodeList nodes3 = trkpt.getChildNodes();
\r
339 for (int i3=0; i3 < nodes3.getLength(); i3++) {
\r
340 Node node4 = nodes3.item(i3);
\r
341 if (node4.getNodeName().equals("time")) {
\r
342 Element time = (Element) node4;
\r
343 NodeList nodes4 = time.getChildNodes(); // 子ノードを取得
\r
344 for (int i4=0; i4< nodes4.getLength(); i4++) {
\r
345 Node node5 = nodes4.item(i4);
\r
346 if (node5 != null) {
\r
347 if (node5.getNodeType() == Node.TEXT_NODE) {
\r
348 String timeStr = node5.getNodeValue();
\r
349 long t = dfuk.parse(timeStr).getTime() + (9L * 3600000L);
\r
350 map.put(new Long(t), getCopy(trk.getOwnerDocument(), trkpt));
\r
363 public static Element trkpt(HashMap<Long,Element> map, Date jptime) throws ParseException {
\r
364 long sa = 2L * 3600000L;
\r
365 long jpt = jptime.getTime();
\r
366 Element ret = null;
\r
368 Set<Long> keySet = map.keySet(); //すべてのキー値を取得
\r
369 Iterator<Long> keyIte = keySet.iterator();
\r
370 while (keyIte.hasNext()) { //ループ。反復子iteratorによる キー 取得
\r
371 Long time = keyIte.next();
\r
372 long t = time.longValue();
\r
373 if (Math.abs(jpt - t) < sa) {
\r
374 sa = Math.abs(jpt - t);
\r
375 ret = map.get(time);
\r
379 if (sa < (60000L * 10L)) {
\r
380 System.out.println(dfuk.format(jpt) +" ("+ sa +")");
\r
387 * 対象は '*.JPG' のみ対象とする
\r
389 public static boolean checkFile(String name) {
\r
390 if (name != null && name.toUpperCase().endsWith(".JPG")) {
\r
397 * <wpt lat="35.25714922" lon="139.15490497">
\r
398 * <ele>62.099998474121094</ele>
\r
399 * <time>2012-06-11T00:44:38Z</time>
\r
400 * <name><![CDATA[写真]]></name>
\r
401 * <link href="2012-06-11_09-44-38.jpg">
\r
402 * <text>2012-06-11_09-44-38.jpg</text>
\r
406 * <trkpt lat="35.32123832" lon="139.56965631">
\r
407 * <ele>47.20000076293945</ele>
\r
408 * <time>2012-06-15T03:00:29Z</time>
\r
414 * @throws IOException
\r
416 public static Element createWptTag(File iFile, long timestamp, Element trkpt) {
\r
417 Element wpt = document.createElement("wpt");
\r
419 NamedNodeMap nodeMap = trkpt.getAttributes();
\r
420 if (null != nodeMap) {
\r
421 for (int j=0; j < nodeMap.getLength(); j++ ) {
\r
422 if (nodeMap.item(j).getNodeName().equals("lat")) {
\r
423 String lat = nodeMap.item(j).getNodeValue();
\r
424 wpt.setAttribute("lat", lat);
\r
426 else if (nodeMap.item(j).getNodeName().equals("lon")) {
\r
427 String lon = nodeMap.item(j).getNodeValue();
\r
428 wpt.setAttribute("lon", lon);
\r
433 NodeList nodes1 = trkpt.getChildNodes();
\r
434 for (int i1=0; i1 < nodes1.getLength(); i1++) {
\r
435 Node node1 = nodes1.item(i1);
\r
436 if (node1.getNodeName().equals("ele")) {
\r
437 NodeList nodes2 = node1.getChildNodes();
\r
438 for (int i2=0; i2 < nodes2.getLength(); i2++) {
\r
439 Node node2 = nodes2.item(i2);
\r
440 if (node2 != null) {
\r
441 if (node2.getNodeType() == Node.TEXT_NODE) {
\r
442 String eleStr = node2.getNodeValue();
\r
443 Element eleE = document.createElement("ele");
\r
444 eleE.setTextContent(eleStr);
\r
445 wpt.appendChild(eleE);
\r
450 else if (node1.getNodeName().equals("time")) {
\r
451 NodeList nodes2 = node1.getChildNodes();
\r
452 for (int i2=0; i2 < nodes2.getLength(); i2++) {
\r
453 Node node2 = nodes2.item(i2);
\r
454 if (node2 != null) {
\r
455 if (node2.getNodeType() == Node.TEXT_NODE) {
\r
456 String timeStr = node2.getNodeValue();
\r
457 Element timeE = document.createElement("time");
\r
458 timeE.setTextContent(timeStr);
\r
459 wpt.appendChild(timeE);
\r
466 Element name = document.createElement("name");
\r
467 name.appendChild(document.createCDATASection("写真"));
\r
468 wpt.appendChild(name);
\r
470 Element link = document.createElement("link");
\r
471 link.setAttribute("href", getShortPathName(gpxDir, iFile));
\r
472 Element text = document.createElement("text");
\r
473 text.setTextContent(iFile.getName());
\r
474 link.appendChild(text);
\r
475 wpt.appendChild(link);
\r
480 static String getShortPathName(File dir, File iFile) {
\r
481 String dirPath = dir.getAbsolutePath();
\r
482 String filePath = iFile.getAbsolutePath();
\r
483 if (filePath.startsWith(dirPath)) {
\r
484 return filePath.substring(dirPath.length()+1);
\r
491 public static Element getCopy(Document doc, Node node) {
\r
492 Element root = doc.createElement(node.getNodeName());
\r
494 NamedNodeMap nodeMap = node.getAttributes();
\r
495 if (null != nodeMap) {
\r
496 for (int j=0; j < nodeMap.getLength(); j++ ) {
\r
497 root.setAttribute(nodeMap.item(j).getNodeName(), nodeMap.item(j).getNodeValue());
\r
501 NodeList nodes = node.getChildNodes();
\r
502 for (int i=0; i < nodes.getLength(); i++) {
\r
503 Node node2 = nodes.item(i);
\r
504 if (node2.getNodeType() == Node.ELEMENT_NODE) {
\r
505 root.appendChild(getCopy(doc, node2));
\r
507 else if (node2.getNodeType() == Node.TEXT_NODE) {
\r
508 String str = node2.getNodeValue();
\r
509 Text textContents = doc.createTextNode(str);
\r
510 root.appendChild(textContents);
\r
512 else if (node2.getNodeType() == Node.CDATA_SECTION_NODE) {
\r
513 String str = node2.getNodeValue();
\r
514 CDATASection cdataSection = doc.createCDATASection(str);
\r
515 root.appendChild(cdataSection);
\r
522 * ファイル名の順序に並び替えるためのソートクラス
\r
526 static class FileSort implements Comparator<File>{
\r
527 public int compare(File src, File target){
\r
528 int diff = src.getName().compareTo(target.getName());
\r