diff --git a/AdjustTime.ini b/AdjustTime.ini new file mode 100644 index 0000000..712bc56 --- /dev/null +++ b/AdjustTime.ini @@ -0,0 +1,15 @@ +#defuilt settings +#Sat Apr 25 18:36:38 JST 2020 +GPX.BASETIME=FILE_UPDATE +IMG.OUTPUT_EXIF=true +GPX.OUTPUT_SPEED=false +IMG.OUTPUT_ALL=false +GPX.noFirstNode=true +IMG.OUTPUT=true +GPX.gpxSplit=true +GPX.REUSE=false +GPX.OVERWRITE_MAGVAR=false +IMG.BASE_FILE= +IMG.SOURCE_FOLDER=/mnt/ssd500/home/yuu/workspace/AdjustTerra/. +GPX.SOURCE_FOLDER=/mnt/ssd500/home/yuu/workspace/AdjustTerra/. +IMG.OUTPUT_FOLDER=/mnt/ssd500/home/yuu/workspace/AdjustTerra/. diff --git a/pom.xml b/pom.xml index 016345a..3f7f5f1 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 osm.surveyor AdjustTerra diff --git a/src/main/java/osm/jp/gpx/GpxFolder.java b/src/main/java/osm/jp/gpx/GpxFolder.java new file mode 100644 index 0000000..293c57b --- /dev/null +++ b/src/main/java/osm/jp/gpx/GpxFolder.java @@ -0,0 +1,100 @@ +package osm.jp.gpx; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; + +public class GpxFolder extends ArrayList { + private static final long serialVersionUID = 6178901459948163548L; + File[] gpxfiles; + AppParameters params; + File gpxDir; + + public GpxFolder(AppParameters params) throws FileNotFoundException { + this.params = params; + gpxDir = params.getGpxSourceFolder(); + + gpxDir = params.getGpxSourceFolder(); + if (gpxDir == null) { + // GPXファイルまたはディレクトリが存在しません。('%s') + throw new FileNotFoundException(String.format(ImportPicture.i18n.getString("msg.100"), gpxDir.getAbsolutePath())); + } + + if (!gpxDir.exists()) { + // GPXファイルまたはディレクトリが存在しません。('%s') + throw new FileNotFoundException(String.format(ImportPicture.i18n.getString("msg.100"), gpxDir.getAbsolutePath())); + } + + if (gpxDir.isFile()) { + if (accept(params, gpxDir.getName())) { + ArrayList fileArray = new ArrayList<>(); + fileArray.add(gpxDir); + gpxfiles = (File[]) fileArray.toArray(); + } + else { + // GPXファイルまたはディレクトリが存在しません。('%s') + throw new FileNotFoundException(String.format(ImportPicture.i18n.getString("msg.100"), gpxDir.getAbsolutePath())); + } + } + else if (gpxDir.isDirectory()) { + // 指定されたディレクトリ内のGPXファイルすべてを対象とする + gpxfiles = gpxDir.listFiles(new GpxFileFilter()); + if (gpxfiles == null) { + // 対象となるGPXファイルがありませんでした。('%s') + throw new FileNotFoundException( + String.format(ImportPicture.i18n.getString("msg.110"), this.gpxDir.getAbsolutePath()) + ); + } + if (params.isImgOutputAll() && (gpxfiles.length > 1)) { + // "複数のGPXファイルがあるときには、'IMG.OUTPUT_ALL'オプションは指定できません。" + throw new FileNotFoundException( + String.format(ImportPicture.i18n.getString("msg.120")) + ); + } + } + else { + // GPXファイルまたはディレクトリが存在しません。('%s') + throw new FileNotFoundException(String.format(ImportPicture.i18n.getString("msg.100"), gpxDir.getAbsolutePath())); + } + + Arrays.sort(gpxfiles, new FileSort()); + } + + /** + * 対象は '*.GPX' のみ対象とする + */ + public static boolean accept(AppParameters params, String name) { + String filename = name.toUpperCase(); + if (filename.endsWith(".GPX")) { + if (!filename.endsWith("_.GPX") || params.isGpxReuse()) { + return true; + } + } + return false; + } + + /** + * ファイル名の順序に並び替えるためのソートクラス + * + */ + static class FileSort implements Comparator { + @Override + public int compare(File src, File target){ + int diff = src.getName().compareTo(target.getName()); + return diff; + } + } + + /** + * GPXファイルフィルター + */ + class GpxFileFilter implements FilenameFilter { + @Override + public boolean accept(File dir, String name) { + return GpxFolder.accept(params, name); + } + } +} diff --git a/src/main/java/osm/jp/gpx/GpxParser.java b/src/main/java/osm/jp/gpx/GpxParser.java index 919c5c0..7084280 100644 --- a/src/main/java/osm/jp/gpx/GpxParser.java +++ b/src/main/java/osm/jp/gpx/GpxParser.java @@ -1,7 +1,6 @@ package osm.jp.gpx; import java.text.ParseException; - import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; diff --git a/src/main/java/osm/jp/gpx/ImgFile.java b/src/main/java/osm/jp/gpx/ImgFile.java new file mode 100644 index 0000000..fb8f09c --- /dev/null +++ b/src/main/java/osm/jp/gpx/ImgFile.java @@ -0,0 +1,282 @@ +package osm.jp.gpx; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.text.DecimalFormat; +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; +import java.util.Map; +import java.util.TimeZone; + +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.imaging.ImageReadException; +import org.apache.commons.imaging.ImageWriteException; +import org.apache.commons.imaging.Imaging; +import org.apache.commons.imaging.common.ImageMetadata; +import org.apache.commons.imaging.common.RationalNumber; +import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata; +import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter; +import org.apache.commons.imaging.formats.tiff.TiffImageMetadata; +import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants; +import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants; +import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory; +import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet; +import org.xml.sax.SAXException; + +@SuppressWarnings("serial") +public class ImgFile extends File { + boolean done = false; + Date imgtime = null; + Date gpstime = null; + double latitude = 0.0D; + double longitude = 0.0D; + String eleStr = "-"; + String magvarStr = "-"; + String speedStr = "-"; + + public ImgFile(File file) { + super(file.getParentFile(), file.getName()); + } + + public void setDone(boolean done) { + this.done = done; + } + + public boolean isDone() { + return this.done; + } + + /** + * 対象は '*.JPG' のみ対象とする + * @return + * @param name + */ + public boolean isImageFile() { + String name = this.getName(); + return ((name != null) && name.toUpperCase().endsWith(".JPG")); + } + + public boolean procImageFile(AppParameters params, long delta, GpxFile gpxFile, File outDir) throws ParseException, ImageReadException, IOException, ImageWriteException, ParserConfigurationException, SAXException { + ElementMapTRKSEG mapTRKSEG = gpxFile.parse(); + boolean exifWrite = params.isImgOutputExif(); + + // itime <-- 画像ファイルの撮影時刻 + // ファイルの更新日時/EXIFの撮影日時 + imgtime = getDate(params); + + // uktime <-- 画像撮影時刻に対応するGPX時刻(補正日時) + gpstime = new Date(imgtime.getTime() + delta); + + // 時刻uktimeにおけるをtrkptに追加する + TagTrkpt trkptT = null; + + for (Map.Entry map : mapTRKSEG.entrySet()) { + ElementMapTRKPT mapTRKPT = map.getValue(); + trkptT = mapTRKPT.getValue(gpstime); + if (trkptT != null) { + break; + } + } + + if (trkptT == null) { + if (!params.isImgOutputAll()) { + return false; + } + } + else { + latitude = trkptT.lat; + longitude = trkptT.lon; + + if (trkptT.eleStr != null) { + eleStr = trkptT.eleStr; + } + + if (trkptT.magvarStr != null) { + magvarStr = trkptT.magvarStr; + } + + if (trkptT.speedStr != null) { + speedStr = trkptT.speedStr; + } + } + + outDir.mkdir(); + if (exifWrite) { + exifWrite(this, gpstime, trkptT, outDir); + } + else { + if (params.isImgOutputAll()) { + // EXIFの変換を伴わない単純なファイルコピー + FileInputStream sStream = new FileInputStream(this); + FileInputStream dStream = new FileInputStream(new File(outDir, this.getName())); + FileChannel srcChannel = sStream.getChannel(); + FileChannel destChannel = dStream.getChannel(); + try { + srcChannel.transferTo(0, srcChannel.size(), destChannel); + } + finally { + srcChannel.close(); + destChannel.close(); + sStream.close(); + dStream.close(); + } + } + } + return true; + } + + String toText() { + String ret = ""; + if (isDone()) { + ret += (String.format("|%-32s|", this.getName())); + ret += (String.format("%20s|", ImportPicture.toUTCString(imgtime))); + ret += (String.format("%20s|", ImportPicture.toUTCString(gpstime))); + ret += (String.format("%14.10f|%14.10f|", latitude, longitude)); + ret += (String.format("%8s|%6s|%6s|", eleStr, magvarStr, speedStr)); + } + else { + ret += (String.format("|%-32s|", this.getName())); + ret += (String.format("%20s|", ImportPicture.toUTCString(imgtime))); + ret += (String.format("%20s|", ImportPicture.toUTCString(gpstime))); + ret += (String.format("%-14s|%-14s|", "", "")); + ret += (String.format("%8s|%6s|%6s|", "", "", "")); + } + return ret; + } + + void exifWrite(File imageFile, Date correctedtime, TagTrkpt trkptT, File outDir) throws ImageReadException, IOException, ImageWriteException { + DecimalFormat yearFormatter = new DecimalFormat("0000"); + DecimalFormat monthFormatter = new DecimalFormat("00"); + DecimalFormat dayFormatter = new DecimalFormat("00"); + + TiffOutputSet outputSet = null; + + ImageMetadata meta = Imaging.getMetadata(imageFile); + JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta; + if (jpegMetadata != null) { + TiffImageMetadata exif = jpegMetadata.getExif(); + if (exif != null) { + outputSet = exif.getOutputSet(); + } + } + + if (outputSet == null) { + outputSet = new TiffOutputSet(); + } + + //---- EXIF_TAG_DATE_TIME_ORIGINAL / 「撮影日時/オリジナル画像の生成日時」---- + TiffOutputDirectory exifDir = outputSet.getOrCreateExifDirectory(); + { + Calendar cal = Calendar.getInstance(); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + cal.setTime(correctedtime); + exifDir.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL); + exifDir.add(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, ImportPicture.toEXIFString(cal.getTime())); + } + + //---- EXIF GPS_TIME_STAMP ---- + TiffOutputDirectory gpsDir = outputSet.getOrCreateGPSDirectory(); + { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); + cal.setTime(correctedtime); + final String yearStr = yearFormatter.format(cal.get(Calendar.YEAR)); + final String monthStr = monthFormatter.format(cal.get(Calendar.MONTH) + 1); + final String dayStr = dayFormatter.format(cal.get(Calendar.DAY_OF_MONTH)); + final String dateStamp = yearStr +":"+ monthStr +":"+ dayStr; + + gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP); + gpsDir.add( + GpsTagConstants.GPS_TAG_GPS_TIME_STAMP, + RationalNumber.valueOf(cal.get(Calendar.HOUR_OF_DAY)), + RationalNumber.valueOf(cal.get(Calendar.MINUTE)), + RationalNumber.valueOf(cal.get(Calendar.SECOND)) + ); + gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP); + gpsDir.add(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP, dateStamp); + } + + if (trkptT != null) { + //---- EXIF GPS elevation/ALTITUDE ---- + if (trkptT.eleStr != null) { + final double altitude = Double.parseDouble(trkptT.eleStr); + gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE); + gpsDir.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(altitude)); + } + + //---- EXIF GPS magvar/IMG_DIRECTION ---- + if (trkptT.magvarStr != null) { + final double magvar = Double.parseDouble(trkptT.magvarStr); + gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION); + gpsDir.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, RationalNumber.valueOf(magvar)); + } + + //---- EXIF GPS_ ---- + outputSet.setGPSInDegrees(trkptT.lon, trkptT.lat); + } + + ExifRewriter rewriter = new ExifRewriter(); + try (FileOutputStream fos = new FileOutputStream(new File(outDir, imageFile.getName()))) { + rewriter.updateExifMetadataLossy(imageFile, fos, outputSet); + } + } + + /** + * 基準時刻ファイルの「更新日時」を取得する + * @param baseFile = new File(this.imgDir, this.params.getProperty(AppParameters.IMG_BASE_FILE)); + * @return + * @throws ImageReadException + * @throws IOException + * @throws ParseException + */ + Date getDate(AppParameters params) throws ImageReadException, IOException, ParseException { + return getDate(params, this); + } + + /** + * 基準時刻ファイルの「更新日時」を取得する + * @param baseFile = new File(this.imgDir, this.params.getProperty(AppParameters.IMG_BASE_FILE)); + * @return + * @throws ImageReadException + * @throws IOException + * @throws ParseException + */ + static Date getDate(AppParameters params, File baseFile) throws ImageReadException, IOException, ParseException { + if (params.isExifBase()) { + // 基準時刻(EXIF撮影日時) + ImageMetadata meta = Imaging.getMetadata(baseFile); + JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta; + if (jpegMetadata == null) { + // "'%s'にEXIF情報がありません" + throw new ImageReadException( + String.format( + ImportPicture.i18n.getString("msg.140"), + baseFile.getAbsolutePath() + ) + ); + } + TiffImageMetadata exif = jpegMetadata.getExif(); + if (exif == null) { + // "'%s'にEXIF情報がありません" + throw new ImageReadException( + String.format( + ImportPicture.i18n.getString("msg.140"), + baseFile.getAbsolutePath() + ) + ); + } + String dateTimeOriginal = exif.getFieldValue(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL)[0]; + return new Date(ImportPicture.toEXIFDate(dateTimeOriginal).getTime()); + } + else { + // 基準時刻(ファイル更新日時) + return new Date(baseFile.lastModified()); + } + } + +} diff --git a/src/main/java/osm/jp/gpx/ImgFileFilter.java b/src/main/java/osm/jp/gpx/ImgFileFilter.java new file mode 100644 index 0000000..906d6bc --- /dev/null +++ b/src/main/java/osm/jp/gpx/ImgFileFilter.java @@ -0,0 +1,17 @@ +package osm.jp.gpx; + +import java.io.File; +import java.io.FilenameFilter; + +/** + * JPEGファイルフィルター + * @author yuu + */ +public class ImgFileFilter implements FilenameFilter { + + @Override + public boolean accept(File dir, String name) { + return name.toUpperCase().matches(".*\\.JPG$"); + } + +} diff --git a/src/main/java/osm/jp/gpx/ImgFolder.java b/src/main/java/osm/jp/gpx/ImgFolder.java index 1f557c0..afdfee0 100644 --- a/src/main/java/osm/jp/gpx/ImgFolder.java +++ b/src/main/java/osm/jp/gpx/ImgFolder.java @@ -1,40 +1,21 @@ package osm.jp.gpx; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FilenameFilter; import java.io.IOException; -import java.nio.channels.FileChannel; -import java.text.DecimalFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.Comparator; -import java.util.Date; -import java.util.Map; -import java.util.TimeZone; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.apache.commons.imaging.ImageReadException; import org.apache.commons.imaging.ImageWriteException; -import org.apache.commons.imaging.Imaging; -import org.apache.commons.imaging.common.ImageMetadata; -import org.apache.commons.imaging.common.RationalNumber; -import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata; -import org.apache.commons.imaging.formats.jpeg.exif.ExifRewriter; -import org.apache.commons.imaging.formats.tiff.TiffImageMetadata; -import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants; -import org.apache.commons.imaging.formats.tiff.constants.GpsTagConstants; -import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory; -import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet; import org.xml.sax.SAXException; -public class ImgFolder extends ArrayList { - File[] imgfiles; +public class ImgFolder extends ArrayList { + private static final long serialVersionUID = -1137199371724546343L; AppParameters params; File imgDir; File outDir; @@ -42,13 +23,11 @@ public ImgFolder(AppParameters params) { this.params = params; imgDir = params.getImgSourceFolder(); - imgfiles = imgDir.listFiles(new JpegFileFilter()); - Arrays.sort(imgfiles, new FileSort()); - } - - public ImgFolder setParams(AppParameters params) { - this.params = params; - return this; + File[] files = imgDir.listFiles(new ImgFileFilter()); + Arrays.sort(files, new FileSort()); + for (File file : files) { + this.add(new ImgFile(file)); + } } public void setOutDir(File outDir) { @@ -59,10 +38,6 @@ return this.imgDir; } - public File getImgBaseFile() { - return new File(imgDir, params.getProperty(AppParameters.IMG_BASE_FILE)); - } - /** * 個別のGPXファイルを処理する * @@ -74,34 +49,7 @@ * @throws ImageReadException * @throws TransformerException */ - void procGPXfile(GpxFile gpxFile) throws ParserConfigurationException, SAXException, IOException, ParseException, ImageReadException, ImageWriteException, TransformerException { - System.gc(); - - ElementMapTRKSEG seg = gpxFile.parse(); - - long delta = 0; - String timeStr = params.getProperty(AppParameters.IMG_TIME); - try { - Date t = ImportPicture.toUTCDate(timeStr); - - // 基準時刻ファイルの「更新日時」を使って時刻合わせを行う。 - // argv[1] --> AppParameters.IMG_BASE_FILE に置き換え - Date imgtime = adjustTime(getImgBaseFile()); - delta = t.getTime() - imgtime.getTime(); - } - catch (ParseException e) { - // "'%s'の書式が違います(%s)" - System.out.println( - String.format( - ImportPicture.i18n.getString("msg.130"), - timeStr, - ImportPicture.TIME_FORMAT_STRING - ) - ); - return; - } - - + void procGPXfile(GpxFile gpxFile, long delta) throws ParserConfigurationException, SAXException, IOException, ParseException, ImageReadException, ImageWriteException, TransformerException { System.out.println("time difference: "+ (delta / 1000) +"(sec)"); System.out.println(" Target GPX: ["+ gpxFile.getAbsolutePath() +"]"); System.out.println(" EXIF: "+ (params.isImgOutputExif() ? ("convert to '" + outDir.getAbsolutePath() +"'") : "off")); @@ -112,305 +60,28 @@ System.out.println("| name | Camera Time | GPStime | Latitude | Longitude | ele |magvar| km/h |"); System.out.println("|--------------------------------|--------------------|--------------------|--------------|--------------|--------|------|------|"); - proc(delta, seg, params.isImgOutputExif(), gpxFile); + //ElementMapTRKSEG seg = gpxFile.parse(); + for (ImgFile image : this) { + try { + if (!image.isDone()) { + if(image.procImageFile(params, delta, gpxFile, outDir)) { + System.out.println(image.toText()); + image.setDone(true); + } + } + } + catch(Exception e) { + System.out.print(String.format("%s", e.toString())); + continue; + } + } System.out.println("|--------------------------------|--------------------|--------------------|--------------|--------------|--------|------|------|"); } /** - * 再帰メソッド - * @throws ParseException - * @throws IOException - * @throws ImageReadException - * @throws ImageWriteException - */ - boolean proc(long delta, ElementMapTRKSEG mapTRKSEG, boolean exifWrite, GpxFile gpxFile) throws ParseException, ImageReadException, IOException, ImageWriteException { - boolean ret = false; - for (File image : imgfiles) { - System.out.print(String.format("|%-32s|", image.getName())); - if (image.isDirectory()) { - ret = (new ImgFolder(params)).proc(delta, mapTRKSEG, exifWrite, gpxFile); - continue; - } - - String imageName = image.getName(); - if (!checkFile(imageName)) { - System.out.println(String.format("%20s ", "it is not image file.")); - continue; - } - - Discripter result = procImageFile(image, delta, mapTRKSEG, exifWrite, gpxFile); - ret |= result.ret; - switch (result.control) { - case Discripter.CONTINUE: - continue; - case Discripter.BREAK: - break; - } - } - return ret; - } - - Discripter procImageFile(File imageFile, long delta, ElementMapTRKSEG mapTRKSEG, boolean exifWrite, GpxFile gpxFile) throws ParseException, ImageReadException, IOException, ImageWriteException { - Discripter result = new Discripter(false); - - // itime <-- 画像ファイルの撮影時刻 - // ファイルの更新日時/EXIFの撮影日時 - Date itime = new Date(imageFile.lastModified()); - if (params.isExifBase()) { - // 基準時刻(EXIF撮影日時) - ImageMetadata meta = Imaging.getMetadata(imageFile); - JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta; - if (jpegMetadata == null) { - // "'%s'にEXIF情報がありません" - System.out.println( - String.format( - ImportPicture.i18n.getString("msg.140"), - imageFile.getAbsolutePath() - ) - ); - result.control = Discripter.CONTINUE; - return result; - } - TiffImageMetadata exif = jpegMetadata.getExif(); - if (exif == null) { - // "'%s'にEXIF情報がありません" - System.out.println( - String.format( - ImportPicture.i18n.getString("msg.140"), - imageFile.getAbsolutePath() - ) - ); - result.control = Discripter.CONTINUE; - return result; - } - String dateTimeOriginal = exif.getFieldValue(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL)[0]; - itime = ImportPicture.toEXIFDate(dateTimeOriginal); - } - System.out.print(String.format("%20s|", ImportPicture.toUTCString(itime))); - - // uktime <-- 画像撮影時刻に対応するGPX時刻(補正日時) - Date correctedtime = new Date(itime.getTime() + delta); - System.out.print(String.format("%20s|", ImportPicture.toUTCString(correctedtime))); - - // 時刻uktimeにおけるをtrkptに追加する - String eleStr = "-"; - String magvarStr = "-"; - String speedStr = "-"; - TagTrkpt trkptT = null; - - for (Map.Entry map : mapTRKSEG.entrySet()) { - ElementMapTRKPT mapTRKPT = map.getValue(); - trkptT = mapTRKPT.getValue(correctedtime); - if (trkptT != null) { - break; - } - } - - if (trkptT == null) { - System.out.print(String.format("%-14s|%-14s|", "", "")); - System.out.println(String.format("%8s|%6s|%6s|", "", "", "")); - if (!params.isImgOutputAll()) { - result.control = Discripter.CONTINUE; - return result; - } - } - else { - double latitude = trkptT.lat; - double longitude = trkptT.lon; - - if (trkptT.eleStr != null) { - eleStr = trkptT.eleStr; - } - - if (trkptT.magvarStr != null) { - magvarStr = trkptT.magvarStr; - } - - if (trkptT.speedStr != null) { - speedStr = trkptT.speedStr; - } - System.out.print(String.format("%14.10f|%14.10f|", latitude, longitude)); - System.out.println(String.format("%8s|%6s|%6s|", eleStr, magvarStr, speedStr)); - } - - result.ret = true; - outDir.mkdir(); - - if (exifWrite) { - exifWrite(imageFile, correctedtime, trkptT); - } - else { - if (params.isImgOutputAll()) { - // EXIFの変換を伴わない単純なファイルコピー - FileInputStream sStream = new FileInputStream(imageFile); - FileInputStream dStream = new FileInputStream(new File(outDir, imageFile.getName())); - FileChannel srcChannel = sStream.getChannel(); - FileChannel destChannel = dStream.getChannel(); - try { - srcChannel.transferTo(0, srcChannel.size(), destChannel); - } - finally { - srcChannel.close(); - destChannel.close(); - sStream.close(); - dStream.close(); - } - } - } - result.control = Discripter.NEXT; - return result; - } - - void exifWrite(File imageFile, Date correctedtime, TagTrkpt trkptT) throws ImageReadException, IOException, ImageWriteException { - DecimalFormat yearFormatter = new DecimalFormat("0000"); - DecimalFormat monthFormatter = new DecimalFormat("00"); - DecimalFormat dayFormatter = new DecimalFormat("00"); - - TiffOutputSet outputSet = null; - - ImageMetadata meta = Imaging.getMetadata(imageFile); - JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta; - if (jpegMetadata != null) { - TiffImageMetadata exif = jpegMetadata.getExif(); - if (exif != null) { - outputSet = exif.getOutputSet(); - } - } - - if (outputSet == null) { - outputSet = new TiffOutputSet(); - } - - //---- EXIF_TAG_DATE_TIME_ORIGINAL / 「撮影日時/オリジナル画像の生成日時」---- - TiffOutputDirectory exifDir = outputSet.getOrCreateExifDirectory(); - { - Calendar cal = Calendar.getInstance(); - cal.setTimeZone(TimeZone.getTimeZone("UTC")); - cal.setTime(correctedtime); - exifDir.removeField(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL); - exifDir.add(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, ImportPicture.toEXIFString(cal.getTime())); - } - - //---- EXIF GPS_TIME_STAMP ---- - TiffOutputDirectory gpsDir = outputSet.getOrCreateGPSDirectory(); - { - Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); - cal.setTime(correctedtime); - final String yearStr = yearFormatter.format(cal.get(Calendar.YEAR)); - final String monthStr = monthFormatter.format(cal.get(Calendar.MONTH) + 1); - final String dayStr = dayFormatter.format(cal.get(Calendar.DAY_OF_MONTH)); - final String dateStamp = yearStr +":"+ monthStr +":"+ dayStr; - - gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP); - gpsDir.add( - GpsTagConstants.GPS_TAG_GPS_TIME_STAMP, - RationalNumber.valueOf(cal.get(Calendar.HOUR_OF_DAY)), - RationalNumber.valueOf(cal.get(Calendar.MINUTE)), - RationalNumber.valueOf(cal.get(Calendar.SECOND)) - ); - gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP); - gpsDir.add(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP, dateStamp); - } - - if (trkptT != null) { - //---- EXIF GPS elevation/ALTITUDE ---- - if (trkptT.eleStr != null) { - final double altitude = Double.parseDouble(trkptT.eleStr); - gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE); - gpsDir.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(altitude)); - } - - //---- EXIF GPS magvar/IMG_DIRECTION ---- - if (trkptT.magvarStr != null) { - final double magvar = Double.parseDouble(trkptT.magvarStr); - gpsDir.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION); - gpsDir.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, RationalNumber.valueOf(magvar)); - } - - //---- EXIF GPS_ ---- - outputSet.setGPSInDegrees(trkptT.lon, trkptT.lat); - } - - ExifRewriter rewriter = new ExifRewriter(); - try (FileOutputStream fos = new FileOutputStream(new File(outDir, imageFile.getName()))) { - rewriter.updateExifMetadataLossy(imageFile, fos, outputSet); - } - } - - /** - * 基準時刻ファイルの「更新日時」を使って時刻合わせを行う。 - * @param baseFile = new File(this.imgDir, this.params.getProperty(AppParameters.IMG_BASE_FILE)); - * @return - * @throws ImageReadException - * @throws IOException - * @throws ParseException - */ - private Date adjustTime(File baseFile) throws ImageReadException, IOException, ParseException { - if (params.isExifBase()) { - // 基準時刻(EXIF撮影日時) - ImageMetadata meta = Imaging.getMetadata(baseFile); - JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta; - if (jpegMetadata == null) { - // "'%s'にEXIF情報がありません" - System.out.println( - String.format( - ImportPicture.i18n.getString("msg.140"), - baseFile.getAbsolutePath() - ) - ); - return null; - } - TiffImageMetadata exif = jpegMetadata.getExif(); - if (exif == null) { - // "'%s'にEXIF情報がありません" - System.out.println( - String.format( - ImportPicture.i18n.getString("msg.140"), - baseFile.getAbsolutePath() - ) - ); - return null; - } - String dateTimeOriginal = exif.getFieldValue(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL)[0]; - return new Date(ImportPicture.toEXIFDate(dateTimeOriginal).getTime()); - } - else { - // 基準時刻(ファイル更新日時) - return new Date(baseFile.lastModified()); - } - } - - /** - * 対象は '*.JPG' のみ対象とする - * @return - * @param name - */ - public static boolean checkFile(String name) { - return ((name != null) && name.toUpperCase().endsWith(".JPG")); - } - - - private static final long serialVersionUID = -1137199371724546343L; - - class Discripter { - static final int NEXT = 0; - static final int CONTINUE = -1; - static final int BREAK = 1; - - public boolean ret; - public int control; - public Discripter(boolean ret) { - this.ret = ret; - this.control = Discripter.NEXT; - } - } - - /** * ファイル名の順序に並び替えるためのソートクラス * - * @author hayashi */ static class FileSort implements Comparator { @Override @@ -419,16 +90,4 @@ return diff; } } - - /** - * JPEGファイルフィルター - * @author yuu - */ - class JpegFileFilter implements FilenameFilter { - @Override - public boolean accept(File dir, String name) { - return name.toUpperCase().matches(".*\\.JPG$"); - } - } - } diff --git a/src/main/java/osm/jp/gpx/ImportPicture.java b/src/main/java/osm/jp/gpx/ImportPicture.java index 9cacf81..f4dc69a 100644 --- a/src/main/java/osm/jp/gpx/ImportPicture.java +++ b/src/main/java/osm/jp/gpx/ImportPicture.java @@ -4,7 +4,6 @@ import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Date; import java.util.ResourceBundle; import java.util.TimeZone; @@ -85,8 +84,7 @@ public File gpxDir; public ImgFolder imgFolder; - //public File outDir; - public ArrayList gpxFiles = new ArrayList<>(); + public GpxFolder gpxFolder; public AppParameters params; private static final String EXIF_DATE_TIME_FORMAT_STRING = "yyyy:MM:dd HH:mm:ss"; @@ -101,61 +99,7 @@ // AppParameters.IMG_SOURCE_FOLDER に置き換え imgFolder = new ImgFolder(params); - - this.gpxDir = params.getGpxSourceFolder(); - if (this.gpxDir != null) { - if (!this.gpxDir.exists()) { - // GPXファイルまたはディレクトリが存在しません。('%s') - System.out.println( - String.format(i18n.getString("msg.100"), gpxDir.getAbsolutePath()) - ); - return; - } - } - else { - this.gpxDir = imgFolder.getImgDir(); - } - - // 指定されたディレクトリ内のGPXファイルすべてを対象とする - if (this.gpxDir.isDirectory()) { - File[] files = this.gpxDir.listFiles(); - if (files == null) { - // 対象となるGPXファイルがありませんでした。('%s') - System.out.println( - String.format(i18n.getString("msg.110"), this.gpxDir.getAbsolutePath()) - ); - return; - } - if (params.isImgOutputAll() && (files.length > 1)) { - // "複数のGPXファイルがあるときには、'IMG.OUTPUT_ALL'オプションは指定できません。" - System.out.println( - i18n.getString("msg.120") - ); - return; - } - - java.util.Arrays.sort( - files, new java.util.Comparator() { - @Override - public int compare(File file1, File file2){ - return file1.getName().compareTo(file2.getName()); - } - } - ); - for (File file : files) { - if (file.isFile()) { - String filename = file.getName().toUpperCase(); - if (filename.toUpperCase().endsWith(".GPX")) { - if (!filename.toUpperCase().endsWith("_.GPX") || params.isGpxReuse()) { - this.gpxFiles.add(file); - } - } - } - } - } - else { - this.gpxFiles.add(this.gpxDir); - } + gpxFolder = new GpxFolder(params); // 出力ファイル // AppParameters.IMG_OUTPUT に置き換え @@ -195,9 +139,40 @@ @Override public void run() { try { - for (File gpxFile : this.gpxFiles) { - imgFolder.procGPXfile(new GpxFile(params, gpxFile)); + long delta = 0; + String timeStr = params.getProperty(AppParameters.IMG_TIME); + try { + Date t = ImportPicture.toUTCDate(timeStr); + + // 基準時刻ファイルの「更新日時」を使って時刻合わせを行う。 + // argv[1] --> AppParameters.IMG_BASE_FILE に置き換え + Date imgtime = ImgFile.getDate(params, getImgBaseFile()); + delta = t.getTime() - imgtime.getTime(); } + catch (ParseException e) { + // "'%s'の書式が違います(%s)"0 + System.out.println( + String.format( + ImportPicture.i18n.getString("msg.130"), + timeStr, + ImportPicture.TIME_FORMAT_STRING + ) + ); + return; + } + + for (File gpxFile : gpxFolder) { + imgFolder.procGPXfile(new GpxFile(params, gpxFile), delta); + } + + // imgDir内の画像ファイルを処理する + System.out.println("|--------------------------------|--------------------|--------------------|--------------|--------------|--------|------|------|"); + System.out.println("| name | Camera Time | GPStime | Latitude | Longitude | ele |magvar| km/h |"); + System.out.println("|--------------------------------|--------------------|--------------------|--------------|--------------|--------|------|------|"); + for (ImgFile image : imgFolder) { + System.out.println(image.toText()); + } + System.out.println("|--------------------------------|--------------------|--------------------|--------------|--------------|--------|------|------|"); } catch(ParserConfigurationException | SAXException | IOException | ParseException | ImageReadException | ImageWriteException | IllegalArgumentException | TransformerException e) { e.printStackTrace(); @@ -205,6 +180,7 @@ } } + @@ -246,6 +222,10 @@ //dfUTC.setTimeZone(TimeZone.getTimeZone("UTC")); return dfUTC.parse(timeStr); } + + public File getImgBaseFile() { + return new File(imgFolder.getImgDir(), params.getProperty(AppParameters.IMG_BASE_FILE)); + } static String getShortPathName(File dir, File iFile) { String dirPath = dir.getAbsolutePath();