Changeset 36436 in osm
- Timestamp:
- 2025-04-30T22:41:56+02:00 (6 days ago)
- Location:
- applications/editors/josm/plugins/photo_geotagging
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/photo_geotagging/build.xml
r36276 r36436 5 5 <property name="commit.message" value=""/> 6 6 <!-- enter the *lowest* JOSM version this plugin is currently compatible with --> 7 <property name="plugin.main.version" value="19 044"/>7 <property name="plugin.main.version" value="19389"/> 8 8 9 9 <property name="plugin.author" value="Paul Hartmann"/> -
applications/editors/josm/plugins/photo_geotagging/pom.xml
r36422 r36436 17 17 <properties> 18 18 <plugin.src.dir>src</plugin.src.dir> 19 <plugin.main.version>19 044</plugin.main.version>19 <plugin.main.version>19389</plugin.main.version> 20 20 <plugin.author>Paul Hartmann</plugin.author> 21 21 <plugin.class>org.openstreetmap.josm.plugins.photo_geotagging.GeotaggingPlugin</plugin.class> … … 32 32 <version>1.0-SNAPSHOT</version> 33 33 <scope>provided</scope> 34 </dependency> 35 <dependency> 36 <groupId>org.junit.jupiter</groupId> 37 <artifactId>junit-jupiter</artifactId> 38 <scope>test</scope> 39 </dependency> 40 <dependency> 41 <groupId>org.wiremock</groupId> 42 <artifactId>wiremock</artifactId> 43 <scope>test</scope> 44 </dependency> 45 <dependency> 46 <groupId>org.junit.vintage</groupId> 47 <artifactId>junit-vintage-engine</artifactId> 48 <scope>test</scope> 34 49 </dependency> 35 50 </dependencies> -
applications/editors/josm/plugins/photo_geotagging/src/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTagger.java
r36275 r36436 10 10 import java.io.IOException; 11 11 import java.text.DecimalFormat; 12 import java.time.Instant;13 12 import java.util.Calendar; 14 13 import java.util.GregorianCalendar; … … 26 25 import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory; 27 26 import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet; 27 import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry; 28 28 29 29 /** … … 41 41 * @param imageFile A source image file. 42 42 * @param dst The output file. 43 * @param lat latitude 44 * @param lon longitude 45 * @param gpsTime time - can be null if not available 46 * @param speed speed in km/h - can be null if not available 47 * @param ele elevation - can be null if not available 48 * @param imgDir image direction in degrees (0..360) - can be null if not available 43 * @param imageEntry the image object from Josm core 49 44 * @param lossy whether to use lossy approach when writing metadata (overwriting unknown tags) 50 45 * @throws IOException in case of I/O error 46 * @since 36436 separate image parameters (lat, lon, gpsTime, speed, ele, imgDir), replaced by the whole ImageEntry object. 51 47 */ 52 public static void setExifGPSTag(File imageFile, File dst, double lat, double lon, Instant gpsTime, Double speed, 53 Double ele, Double imgDir, boolean lossy) throws IOException { 48 49 public static void setExifGPSTag(File imageFile, File dst, ImageEntry imageEntry, 50 boolean lossy) throws IOException { 54 51 try { 55 setExifGPSTagWorker(imageFile, dst, lat, lon, gpsTime, speed, ele, imgDir, lossy);52 setExifGPSTagWorker(imageFile, dst, imageEntry, lossy); 56 53 } catch (ImagingException ire) { 57 54 // This used to be two separate exceptions; ImageReadException and imageWriteException … … 60 57 } 61 58 62 public static void setExifGPSTagWorker(File imageFile, File dst, double lat, double lon, Instant gpsTime, Double speed,63 Double ele, Double imgDir,boolean lossy) throws IOException {59 public static void setExifGPSTagWorker(File imageFile, File dst, ImageEntry imageEntry, 60 boolean lossy) throws IOException { 64 61 65 62 TiffOutputSet outputSet = null; … … 81 78 TiffOutputDirectory gpsDirectory = outputSet.getOrCreateGpsDirectory(); 82 79 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_VERSION_ID); 83 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_VERSION_ID, (byte)2, (byte)3, (byte)0, (byte)0); 84 85 if ( gpsTime!= null) {80 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_VERSION_ID, (byte) 2, (byte) 3, (byte) 0, (byte) 0); 81 82 if (imageEntry.getGpsInstant() != null) { 86 83 Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 87 calendar.setTimeInMillis( gpsTime.toEpochMilli());88 89 final int year = 90 final int month = 91 final int day = 92 final int hour = 84 calendar.setTimeInMillis(imageEntry.getGpsInstant().toEpochMilli()); 85 86 final int year = calendar.get(Calendar.YEAR); 87 final int month = calendar.get(Calendar.MONTH) + 1; 88 final int day = calendar.get(Calendar.DAY_OF_MONTH); 89 final int hour = calendar.get(Calendar.HOUR_OF_DAY); 93 90 final int minute = calendar.get(Calendar.MINUTE); 94 91 final int second = calendar.get(Calendar.SECOND); … … 118 115 } 119 116 120 outputSet.setGpsInDegrees( lon, lat);121 122 if ( speed!= null) {117 outputSet.setGpsInDegrees(imageEntry.getPos().lon(), imageEntry.getPos().lat()); 118 119 if (imageEntry.getSpeed() != null) { 123 120 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_SPEED_REF); 124 121 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_SPEED_REF, … … 126 123 127 124 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_SPEED); 128 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_SPEED, RationalNumber.valueOf( speed));129 } 130 131 if ( ele!= null) {132 byte eleRef = ele>= 0 ? (byte) 0 : (byte) 1;125 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_SPEED, RationalNumber.valueOf(imageEntry.getSpeed())); 126 } 127 128 if (imageEntry.getElevation() != null) { 129 byte eleRef = imageEntry.getElevation() >= 0 ? (byte) 0 : (byte) 1; 133 130 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE_REF); 134 131 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE_REF, eleRef); 135 132 136 133 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE); 137 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(Math.abs( ele)));138 } 139 140 if (im gDir!= null) {134 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(Math.abs(imageEntry.getElevation()))); 135 } 136 137 if (imageEntry.getExifImgDir() != null) { 141 138 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF); 142 139 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF, 143 140 GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF_VALUE_TRUE_NORTH); 144 // make sure the value is in the range 0.0...<360.0 145 if (imgDir < 0.0) { 146 imgDir %= 360.0; // >-360.0...-0.0 147 imgDir += 360.0; // >0.0...360.0 148 } 149 if (imgDir >= 360.0) { 150 imgDir %= 360.0; 151 } 141 Double imgDir = checkAngle(imageEntry.getExifImgDir()); 152 142 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION); 153 143 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, RationalNumber.valueOf(imgDir)); 144 } 145 146 if (imageEntry.getExifGpsTrack() != null) { 147 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_TRACK_REF); 148 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_TRACK_REF, 149 GpsTagConstants.GPS_TAG_GPS_TRACK_REF_VALUE_TRUE_NORTH); 150 // make sure the value is in the range 0.0...<360.0 151 Double gpsTrack = checkAngle(imageEntry.getExifGpsTrack()); 152 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_TRACK); 153 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_TRACK, RationalNumber.valueOf(gpsTrack)); 154 } 155 156 if (imageEntry.getGpsDiffMode() != null) { 157 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_DIFFERENTIAL); 158 // make sure the gpsDiffMode value is 0 (no diffential) or 1 (differential) 159 if (imageEntry.getGpsDiffMode().equals(0) || imageEntry.getGpsDiffMode().equals(1)) { 160 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_DIFFERENTIAL, imageEntry.getGpsDiffMode().shortValue()); 161 } 162 } 163 164 if (imageEntry.getGps2d3dMode() != null) { 165 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_MEASURE_MODE); 166 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_MEASURE_MODE, imageEntry.getGps2d3dMode().toString()); 167 } 168 169 if (imageEntry.getExifGpsProcMethod() != null) { 170 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_PROCESSING_METHOD); 171 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_PROCESSING_METHOD, imageEntry.getExifGpsProcMethod()); 172 } 173 174 if (imageEntry.getExifGpsDatum() != null) { 175 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_MAP_DATUM); 176 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_MAP_DATUM, imageEntry.getExifGpsDatum().toString()); 177 } 178 179 if (imageEntry.getExifHPosErr() != null) { 180 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_HOR_POSITIONING_ERROR); 181 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_HOR_POSITIONING_ERROR, RationalNumber.valueOf(imageEntry.getExifHPosErr())); 182 } 183 184 if (imageEntry.getExifGpsDop() != null) { 185 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_DOP); 186 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_DOP, RationalNumber.valueOf(imageEntry.getExifGpsDop())); 154 187 } 155 188 … … 166 199 } 167 200 } 201 202 /** 203 * Normalizes an angle to the range [0.0, 360.0[ degrees. 204 * This will fix any angle value <0 and >= 360 205 * @param angle the angle to normalize (in degrees) 206 * @return the equivalent angle value in the range [0.0, 360.0[ 207 */ 208 private static Double checkAngle(Double angle) { 209 if (angle < 0.0) { 210 angle %= 360.0; // >-360.0...-0.0 211 angle += 360.0; // >0.0...360.0 212 } 213 if (angle >= 360.0) { 214 angle %= 360.0; 215 } 216 return angle; 217 } 168 218 } -
applications/editors/josm/plugins/photo_geotagging/src/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingAction.java
r36275 r36436 65 65 static final int MTIME_MODE_PREVIOUS_VALUE = 2; 66 66 67 publicGeotaggingAction() {67 GeotaggingAction() { 68 68 super(tr("Write coordinates to image header"), ImageProvider.get("geotagging")); 69 69 } … … 86 86 87 87 for (ImageEntry e : layer.getImages()) { 88 88 /* Only write lat/lon to the file, if the position is known and 89 89 the GPS data changed. */ 90 90 if (e.getPos() != null && e.hasNewGpsData()) { … … 135 135 final JPanel settingsPanel = new JPanel(new GridBagLayout()); 136 136 settingsPanel.setBorder(BorderFactory.createTitledBorder(tr("settings"))); 137 cont.add(settingsPanel, GBC.eol().insets(3, 10,3,0));137 cont.add(settingsPanel, GBC.eol().insets(3, 10, 3, 0)); 138 138 139 139 final JCheckBox backups = new JCheckBox(tr("keep backup files"), Config.getPref().getBoolean(KEEP_BACKUP, true)); 140 settingsPanel.add(backups, GBC.eol().insets(3, 3,0,0));140 settingsPanel.add(backups, GBC.eol().insets(3, 3, 0, 0)); 141 141 142 142 final JCheckBox setMTime = new JCheckBox(tr("change file modification time:"), Config.getPref().getBoolean(CHANGE_MTIME, false)); 143 settingsPanel.add(setMTime, GBC.std().insets(3, 3,5,3));143 settingsPanel.add(setMTime, GBC.std().insets(3, 3, 5, 3)); 144 144 145 145 final String[] mTimeModeArray = {"----", tr("to gps time"), tr("to previous value (unchanged mtime)")}; 146 146 final JComboBox<String> mTimeMode = new JComboBox<>(mTimeModeArray); 147 { 148 149 150 151 152 153 154 155 156 } 157 settingsPanel.add(mTimeMode, GBC.eol().insets(3, 3,3,3));147 148 String mTimeModePrefName = Config.getPref().get(MTIME_MODE, null); 149 int mTimeIdx = 0; 150 if ("gps".equals(mTimeModePrefName)) { 151 mTimeIdx = 1; 152 } else if ("previous".equals(mTimeModePrefName)) { 153 mTimeIdx = 2; 154 } 155 mTimeMode.setSelectedIndex(setMTime.isSelected() ? mTimeIdx : 0); 156 157 settingsPanel.add(mTimeMode, GBC.eol().insets(3, 3, 3, 3)); 158 158 159 159 setMTime.addActionListener(e -> { … … 219 219 private int currentIndex; 220 220 221 publicGeoTaggingRunnable(List<ImageEntry> images, boolean keep_backup, int mTimeMode) {221 GeoTaggingRunnable(List<ImageEntry> images, boolean keep_backup, int mTimeMode) { 222 222 super(tr("Photo Geotagging Plugin")); 223 223 this.images = images; … … 225 225 this.mTimeMode = mTimeMode; 226 226 } 227 228 227 229 228 @Override … … 258 257 } 259 258 sb.append("</ul><br>") 260 .append(tr("This can likely be fixed by rewriting the entire EXIF section, however some (rare) unknown tags may get lost in the process.<br>" 259 .append(tr("This can likely be fixed by rewriting the entire EXIF section, however some" 260 + " (rare) unknown tags may get lost in the process.<br>" 261 261 + "Would you like to proceed anyway?")); 262 262 … … 360 360 } 361 361 } 362 if ( 362 if (mTimeMode == MTIME_MODE_PREVIOUS_VALUE 363 363 // this is also the fallback if one of the other 364 364 // modes failed to determine the modification time … … 371 371 chooseFiles(e.getFile()); 372 372 if (canceled) return; 373 ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e.getPos().lat(), e.getPos().lon(), 374 e.getGpsInstant(), e.getSpeed(), e.getElevation(), e.getExifImgDir(), lossy); 373 ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e, lossy); 375 374 376 375 if (mTime != null) { … … 391 390 } 392 391 393 File fileBackup = new File(file.getParentFile(),file.getName()+"_"); 392 File fileBackup = new File(file.getParentFile(), file.getName()+"_"); 394 393 if (fileBackup.exists()) { 395 394 confirm_override(); … … 511 510 512 511 private GeoImageLayer getLayer() { 513 return (GeoImageLayer)LayerListDialog.getInstance().getModel().getSelectedLayers().get(0); 512 return (GeoImageLayer) LayerListDialog.getInstance().getModel().getSelectedLayers().get(0); 514 513 } 515 514 … … 539 538 } 540 539 } 540 -
applications/editors/josm/plugins/photo_geotagging/test/unit/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTaggerTest.java
r35933 r36436 1 // License: GPL. For details, see LICENSE file. 2 // SPDX-License-Identifier: GPL-2.0-or-later 1 3 package org.openstreetmap.josm.plugins.photo_geotagging; 2 4 … … 19 21 import org.junit.jupiter.api.io.TempDir; 20 22 import org.openstreetmap.josm.TestUtils; 23 import org.openstreetmap.josm.data.coor.LatLon; 24 import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry; 21 25 22 26 class ExifGPSTaggerTest { … … 25 29 File tempFolder; 26 30 31 private static ImageEntry newImageEntry(String file, Double lat, Double lon, Instant exifTime, 32 Double speed, Double elevation, Double imgDir) { 33 ImageEntry entry = new ImageEntry(new File(file)); 34 entry.setPos(new LatLon(lat, lon)); 35 entry.setExifTime(exifTime); 36 entry.setSpeed(speed); 37 entry.setElevation(elevation); 38 entry.setExifImgDir(imgDir); 39 return entry; 40 } 41 27 42 @Test 28 43 void testTicket11757() { 29 44 final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg"); 30 45 final File out = new File(tempFolder, in.getName()); 31 assertDoesNotThrow(() -> ExifGPSTagger.setExifGPSTag(in, out, 12, 34, Instant.now(), 12.34, Math.E, Math.PI, true)); 46 final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI); 47 assertDoesNotThrow(() -> ExifGPSTagger.setExifGPSTag(in, out, image, true)); 32 48 } 33 49 … … 47 63 final File in = new File(TestUtils.getTestDataRoot(), "IMG_7250_small.JPG"); 48 64 final File out = new File(tempFolder, in.getName()); 49 ExifGPSTagger.setExifGPSTag(in, out, 12, 34, Instant.now(), 12.34, Math.E, Math.PI, false); 65 final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI); 66 ExifGPSTagger.setExifGPSTag(in, out, image, true); 50 67 final Process jhead = Runtime.getRuntime().exec(new String[]{"jhead", out.getAbsolutePath()}); 51 68 final String stdout = new Scanner(jhead.getErrorStream()).useDelimiter("\\A").next(); … … 53 70 assertFalse(stdout.contains("Suspicious offset of first Exif IFD value")); 54 71 } 72 73 @Test 74 public void testTicket24278() { 75 final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg"); 76 final File out = new File(tempFolder, in.getName()); 77 final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI); 78 image.setExifGpsTrack(Math.PI); 79 image.setGpsDiffMode(2); 80 image.setGps2d3dMode(3); 81 image.setExifGpsProcMethod("GPS"); 82 image.setExifHPosErr(1.2d); 83 image.setExifGpsDop(2.5d); 84 image.setExifGpsDatum("WGS84"); 85 assertDoesNotThrow(() -> ExifGPSTagger.setExifGPSTag(in, out, image, true)); 86 /* TODO read temp file and assertEquals EXIF metadata values */ 87 } 55 88 } -
applications/editors/josm/plugins/photo_geotagging/test/unit/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingActionTest.java
r35933 r36436 1 // License: GPL. For details, see LICENSE file. 2 // SPDX-License-Identifier: GPL-2.0-or-later 1 3 package org.openstreetmap.josm.plugins.photo_geotagging; 2 3 4 4 5 import java.io.File;
Note:
See TracChangeset
for help on using the changeset viewer.