package osm.jp.gpx;\r
import java.io.*;\r
+import java.text.DecimalFormat;\r
import java.text.ParseException;\r
import java.text.SimpleDateFormat;\r
import java.util.ArrayList;\r
import java.util.Arrays;\r
+import java.util.Calendar;\r
import java.util.Comparator;\r
import java.util.Date;\r
+import java.util.GregorianCalendar;\r
import java.util.HashMap;\r
import java.util.Iterator;\r
import java.util.Set;\r
import javax.xml.transform.dom.DOMSource;\r
import javax.xml.transform.stream.StreamResult;\r
\r
+import org.apache.commons.imaging.ImageReadException;\r
+import org.apache.commons.imaging.ImageWriteException;\r
+import org.apache.commons.imaging.Imaging;\r
+import org.apache.commons.imaging.common.ImageMetadata;\r
+import org.apache.commons.imaging.common.RationalNumber;\r
+import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;\r
+import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter;\r
+import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;\r
+import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;\r
+import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants;\r
+import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;\r
+import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;\r
import org.w3c.dom.*;\r
import org.xml.sax.SAXException;\r
\r
public class ImportPicture {\r
public static File gpxDir = new File(".");\r
+ public static File outDir = null;\r
\r
/**\r
* ログ設定プロパティファイルのファイル内容\r
= "handlers=java.util.logging.ConsoleHandler\n"\r
+ ".level=FINEST\n"\r
+ "java.util.logging.ConsoleHandler.level=INFO\n"\r
- + "java.util.logging.ConsoleHandler.formatter=hayashi.yuu.tools.logger.YuuLogFormatter";\r
+ + "java.util.logging.ConsoleHandler.formatter=osm.jp.gpx.YuuLogFormatter";\r
\r
/**\r
* static initializer によるログ設定の初期化\r
*/\r
- public static final Logger logger = Logger.getLogger("SampleLogging");\r
+ public static final Logger logger = Logger.getLogger("CommandLogging");\r
static {\r
InputStream inStream = null;\r
try {\r
* argv[0] = 画像ファイルが格納されているディレクトリ\r
* argv[1] = 時刻補正の基準とする画像ファイル\r
* argv[2] = 基準画像ファイルの精確な撮影日時 "yyyy-MM-dd'T'HH:mm:ss"\r
- * argv[3] = 撮影位置をロギングしたGPXファイル\r
+ * argv[3] = [EXIF] EXIF情報の書き換えを行う / [not] EXIF情報の書き換えを行わない\r
+ * argv[4] = 撮影位置をロギングしたGPXファイル\r
* \r
* @throws IOException\r
+ * @throws ImageReadException \r
*/\r
- public static void main(String[] argv) throws IOException\r
+ public static void main(String[] argv) throws Exception\r
{\r
Date jptime;\r
\r
gpxDir = new File(argv[0]);\r
}\r
\r
- if (argv.length < 3) {\r
- System.out.println("> java -jar importPicture.jar <targetDir> <time base image> <time> (gpx)");\r
- System.out.println("> java -jar importPicture.jar . IMG_01234.JPG 2012-06-15T12:52:22");\r
+ if (argv.length < 4) {\r
+ System.out.println("!!! Illigal command call. !!!");\r
+ System.out.println("> java -cp .:AdjustTime.jar:commons-imaging-1.0-SNAPSHOT.jar <targetDir> <time base image> <time> {EXIF/not} (gpx)");\r
+ System.out.println("> java -cp .:AdjustTime.jar:commons-imaging-1.0-SNAPSHOT.jar. IMG_01234.JPG 2012-06-15T12:52:22 EXIF");\r
+ System.out.println("> java -cp .:AdjustTime.jar . IMG_01234.JPG 2012-06-15T12:52:22 not");\r
+ System.out.println();\r
+ return;\r
}\r
\r
// 基準時刻ファイルの「更新日時」を使って時刻合わせを行う。\r
File baseFile = new File(gpxDir, argv[1]);\r
jptime = new Date(baseFile.lastModified());\r
\r
- // 第5引数が指定されなければ、指定されたディレクトリ内のGPXファイルすべてを対象とする\r
+ // \r
+ boolean exif = false;\r
+ if (argv[3].toUpperCase().equals("EXIF")) {\r
+ exif = true;\r
+ }\r
+ \r
+ // 第6引数が指定されなければ、指定されたディレクトリ内のGPXファイルすべてを対象とする\r
ArrayList<File> gpxFiles = new ArrayList<File>();\r
- if (argv.length > 3) {\r
- gpxFiles.add(new File(gpxDir, argv[3]));\r
+ if (argv.length > 4) {\r
+ gpxFiles.add(new File(gpxDir, argv[4]));\r
}\r
else {\r
File[] files = gpxDir.listFiles();\r
System.out.println("GPX start time: "+ dfjp.format(new Date(gpxStartTime)) + "\t[GMT " + dfuk.format(new Date(gpxStartTime))+"]");\r
System.out.println(" GPX end time: "+ dfjp.format(new Date(gpxEndTime)) + "\t[GMT " + dfuk.format(new Date(gpxEndTime))+"]");\r
System.out.println();\r
- System.out.println("------------|--------------------|--------------------|------------|----------|--------");\r
- System.out.println(" name | UpdateTime | GPStime | LAT | LON | ele");\r
- System.out.println("------------|--------------------|--------------------|------------|----------|--------");\r
- proc(gpxDir, delta, gpxStartTime, gpxEndTime, map, gpx);\r
- System.out.println("------------|--------------------|--------------------|------------|----------|--------");\r
+ System.out.println("------------|--------------------|--------------------|------------|------------|--------");\r
+ System.out.println(" name | UpdateTime | GPStime | Latitude | Longitude | ele");\r
+ System.out.println("------------|--------------------|--------------------|------------|------------|--------");\r
+ proc(gpxDir, delta, gpxStartTime, gpxEndTime, map, exif, gpx);\r
+ System.out.println("------------|--------------------|--------------------|------------|------------|--------");\r
}\r
catch (ParseException e) {\r
System.out.println("'"+ timeStr +"' の書式が違います("+ TIME_FORMAT_STRING +")");\r
/**\r
* 再帰メソッド\r
* @throws ParseException \r
+ * @throws IOException \r
+ * @throws ImageReadException \r
+ * @throws ImageWriteException \r
*/\r
- static void proc(File dir, long delta, long gpxStartTime, long gpxEndTime, HashMap<Long,Element> map, Node gpx) throws ParseException {\r
+ static void proc(File dir, long delta, long gpxStartTime, long gpxEndTime, HashMap<Long,Element> map, boolean exifWrite, Node gpx) throws ParseException, ImageReadException, IOException, ImageWriteException {\r
+ DecimalFormat yearFormatter = new DecimalFormat("0000");\r
+ DecimalFormat monthFormatter = new DecimalFormat("00");\r
+ DecimalFormat dayFormatter = new DecimalFormat("00");\r
+ \r
File[] files = dir.listFiles();\r
Arrays.sort(files, new FileSort());\r
for (File image : files) {\r
if (image.isDirectory()) {\r
- proc(image, delta, gpxStartTime, gpxEndTime, map, gpx);\r
+ proc(image, delta, gpxStartTime, gpxEndTime, map, exifWrite, gpx);\r
}\r
else {\r
String imageName = image.getName();\r
if ((uktime.getTime() >= gpxStartTime) && (uktime.getTime() <= gpxEndTime)) {\r
Element trkpt = trkpt(map, uktime);\r
if (trkpt != null) {\r
- System.out.print(String.format("%12s ", image.getName()));\r
+ System.out.print(String.format("%12s|", image.getName()));\r
System.out.print(String.format("%20s ", dfjp.format(itime)));\r
- System.out.print(String.format("%20s ", dfjp.format(uktime)));\r
+ System.out.print(String.format("%20s|", dfjp.format(uktime)));\r
\r
Element wpt = createWptTag(image, uktime.getTime(), trkpt);\r
- System.out.print(String.format("%12s ", wpt.getAttribute("lat")));\r
+ String latStr = wpt.getAttribute("lat");\r
String lonStr = wpt.getAttribute("lon");\r
- //System.out.print(String.format("%12s "+ lonStr));\r
- System.out.print(lonStr + " ");\r
+ System.out.print(String.format("%12s %12s|", latStr, lonStr));\r
+ double latitude = Double.parseDouble(latStr);\r
+ double longitude = Double.parseDouble(lonStr);\r
\r
+ String eleStr = null;\r
NodeList nodes = wpt.getChildNodes(); // 子ノードを取得\r
for (int i4=0; i4< nodes.getLength(); i4++) {\r
Node node = nodes.item(i4);\r
if (node != null) {\r
if (node.getNodeName().equals("ele")) {\r
- String eleStr = node.getFirstChild().getNodeValue();\r
- System.out.println(eleStr);\r
+ eleStr = node.getFirstChild().getNodeValue();\r
+ System.out.println(String.format("%8s|", eleStr));\r
+ break;\r
}\r
}\r
else {\r
System.out.println("-");\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if (exifWrite) {\r
+ TiffOutputSet outputSet = null;\r
+ FileOutputStream fos = null;\r
+ \r
+ ImageMetadata meta = Imaging.getMetadata(image);\r
+ JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta;\r
+ if (jpegMetadata != null) {\r
+ TiffImageMetadata exif = jpegMetadata.getExif();\r
+ if (exif != null) {\r
+ outputSet = exif.getOutputSet();\r
+ }\r
+ }\r
+ \r
+ if (outputSet == null) {\r
+ System.out.println("added : new tiff output set");\r
+ outputSet = new TiffOutputSet();\r
+ }\r
+ \r
+ //---- EXIF_TAG_DATE_TIME_ORIGINAL / 「撮影日時/オリジナル画像の生成日時」----\r
+ TiffOutputDirectory exifDir = outputSet.getOrCreateExifDirectory();\r
+ {\r
+ Calendar cal = GregorianCalendar.getInstance();\r
+ cal.setTime(uktime);\r
+ exifDir.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL);\r
+ exifDir.add(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, new SimpleDateFormat("yyyy:MM:dd HH:mm:ss").format(cal.getTime()));\r
+ }\r
+ \r
+ //---- EXIF GPS_TIME_STAMP ----\r
+ TiffOutputDirectory gpsDir = outputSet.getOrCreateGPSDirectory();\r
+ {\r
+ Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));\r
+ cal.setTime(uktime);\r
+ final String yearStr = yearFormatter.format(cal.get(Calendar.YEAR));\r
+ final String monthStr = monthFormatter.format(cal.get(Calendar.MONTH) + 1);\r
+ final String dayStr = dayFormatter.format(cal.get(Calendar.DAY_OF_MONTH));\r
+ final String dateStamp = yearStr +":"+ monthStr +":"+ dayStr;\r
+ \r
+ gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP);\r
+ gpsDir.add(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP,\r
+ RationalNumber.valueOf(cal.get(Calendar.HOUR_OF_DAY)),\r
+ RationalNumber.valueOf(cal.get(Calendar.MINUTE)),\r
+ RationalNumber.valueOf(cal.get(Calendar.SECOND)));\r
+ gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP);\r
+ gpsDir.add(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP, dateStamp);\r
+ }\r
+ \r
+ //---- EXIF GPS elevation/ALTITUDE ----\r
+ if (eleStr != null) {\r
+ final double altitude = Double.parseDouble(eleStr);\r
+ gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE);\r
+ gpsDir.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(altitude));\r
+ }\r
+ \r
+ //---- EXIF GPS_ ----\r
+ final String longitudeRef = (longitude < 0 ? "W" : "E");\r
+ longitude = Math.abs(longitude);\r
+ final String latitudeRef = (latitude < 0 ? "S" : "N");\r
+ latitude = Math.abs(latitude);\r
+ \r
+ gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF);\r
+ gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF, longitudeRef);\r
+ gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF);\r
+ gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF, latitudeRef);\r
+ {\r
+ double value = longitude;\r
+ final double longitudeDegrees = (long) value;\r
+ value %= 1;\r
+ value *= 60.0;\r
+ final double longitudeMinutes = (long) value;\r
+ value %= 1;\r
+ value *= 60.0;\r
+ final double longitudeSeconds = value;\r
+ gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LONGITUDE);\r
+ gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LONGITUDE,\r
+ RationalNumber.valueOf(longitudeDegrees),\r
+ RationalNumber.valueOf(longitudeMinutes),\r
+ RationalNumber.valueOf(longitudeSeconds));\r
+ }\r
+ {\r
+ double value = latitude;\r
+ final double latitudeDegrees = (long) value;\r
+ value %= 1;\r
+ value *= 60.0;\r
+ final double latitudeMinutes = (long) value;\r
+ value %= 1;\r
+ value *= 60.0;\r
+ final double latitudeSeconds = value;\r
+ gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_LATITUDE);\r
+ gpsDir.add(GpsTagConstants.GPS_TAG_GPS_LATITUDE,\r
+ RationalNumber.valueOf(latitudeDegrees),\r
+ RationalNumber.valueOf(latitudeMinutes),\r
+ RationalNumber.valueOf(latitudeSeconds));\r
+ }\r
+ \r
+ ExifRewriter rewriter = new ExifRewriter();\r
+ try {\r
+ if (outDir == null) {\r
+ outDir = new File(dir, "converted");\r
+ outDir.mkdir();\r
+ }\r
+ fos = new FileOutputStream(new File(outDir, imageName));\r
+ rewriter.updateExifMetadataLossy(image, fos, outputSet);\r
+ }\r
+ finally {\r
+ if (fos != null) {\r
+ fos.close();\r
+ }\r
}\r
}\r
\r
}\r
}\r
}\r
-\r
}\r
-\r
+ \r
static Document document;\r
\r
/**\r