Ticket #24458: 24458.patch
| File 24458.patch, 12.6 KB (added by , 2 months ago) |
|---|
-
src/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTagger.java
41 41 * @param imageFile A source image file. 42 42 * @param dst The output file. 43 43 * @param imageEntry the image object from Josm core 44 * @param writeGpsTime write the EXIF tags GPSDateStamp and GPSTimeStamp 44 45 * @param lossy whether to use lossy approach when writing metadata (overwriting unknown tags) 45 46 * @throws IOException in case of I/O error 46 47 * @since 36436 separate image parameters (lat, lon, gpsTime, speed, ele, imgDir), replaced by the whole ImageEntry object. 48 * @since xxx added writeGpsTime parameter 47 49 */ 48 50 49 51 public static void setExifGPSTag(File imageFile, File dst, ImageEntry imageEntry, 50 boolean lossy) throws IOException {52 boolean writeGpsTime, boolean lossy) throws IOException { 51 53 try { 52 setExifGPSTagWorker(imageFile, dst, imageEntry, lossy);54 setExifGPSTagWorker(imageFile, dst, imageEntry, writeGpsTime, lossy); 53 55 } catch (ImagingException ire) { 54 56 // This used to be two separate exceptions; ImageReadException and imageWriteException 55 57 throw new IOException(tr("Read/write error: " + ire.getMessage()), ire); … … 57 59 } 58 60 59 61 public static void setExifGPSTagWorker(File imageFile, File dst, ImageEntry imageEntry, 60 boolean lossy) throws IOException {62 boolean writeGpsTime, boolean lossy) throws IOException { 61 63 62 64 TiffOutputSet outputSet = null; 63 65 ImageMetadata metadata = Imaging.getMetadata(imageFile); … … 79 81 gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_VERSION_ID); 80 82 gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_VERSION_ID, (byte) 2, (byte) 3, (byte) 0, (byte) 0); 81 83 82 if ( imageEntry.getGpsInstant() != null) {84 if (writeGpsTime && imageEntry.getGpsInstant() != null) { 83 85 Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC")); 84 86 calendar.setTimeInMillis(imageEntry.getGpsInstant().toEpochMilli()); 85 87 -
src/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingAction.java
55 55 56 56 /** 57 57 * The action to ask the user for confirmation and then do the tagging. 58 * @since xxx added checkbox option to write GPS date and time 58 59 */ 59 60 class GeotaggingAction extends AbstractAction implements LayerAction { 60 61 … … 136 137 settingsPanel.setBorder(BorderFactory.createTitledBorder(tr("settings"))); 137 138 cont.add(settingsPanel, GBC.eol().insets(3, 10, 3, 0)); 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 final JCheckBox cbWriteGpsTime = new JCheckBox(tr("Write EXIF GPS date and time"), false); 141 settingsPanel.add(cbWriteGpsTime, GBC.eol().insets(3, 3, 0, 0)); 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 final JCheckBox cbBackups = new JCheckBox(tr("Keep backup files"), Config.getPref().getBoolean(KEEP_BACKUP, true)); 144 settingsPanel.add(cbBackups, GBC.eol().insets(3, 3, 0, 0)); 144 145 145 final String[] mTimeModeArray = {"----", tr("to gps time"), tr("to previous value (unchanged mtime)")}; 146 final JCheckBox cbSetMTime = new JCheckBox(tr("Change file modification time:"), Config.getPref().getBoolean(CHANGE_MTIME, false)); 147 settingsPanel.add(cbSetMTime, GBC.std().insets(3, 3, 5, 3)); 148 149 final String[] mTimeModeArray = {"----", tr("to GPS time"), tr("to previous value (unchanged mtime)")}; 146 150 final JComboBox<String> mTimeMode = new JComboBox<>(mTimeModeArray); 147 151 148 152 String mTimeModePrefName = Config.getPref().get(MTIME_MODE, null); … … 152 156 } else if ("previous".equals(mTimeModePrefName)) { 153 157 mTimeIdx = 2; 154 158 } 155 mTimeMode.setSelectedIndex( setMTime.isSelected() ? mTimeIdx : 0);159 mTimeMode.setSelectedIndex(cbSetMTime.isSelected() ? mTimeIdx : 0); 156 160 157 161 settingsPanel.add(mTimeMode, GBC.eol().insets(3, 3, 3, 3)); 158 162 159 setMTime.addActionListener(e -> {160 if ( setMTime.isSelected()) {163 cbSetMTime.addActionListener(e -> { 164 if (cbSetMTime.isSelected()) { 161 165 mTimeMode.setEnabled(true); 162 166 } else { 163 167 mTimeMode.setSelectedIndex(0); … … 166 170 }); 167 171 168 172 // Toggle the checkbox to fire actionListener 169 setMTime.setSelected(!setMTime.isSelected());170 setMTime.doClick();173 cbSetMTime.setSelected(!cbSetMTime.isSelected()); 174 cbSetMTime.doClick(); 171 175 172 176 int result = new ExtendedDialog( 173 177 MainApplication.getMainFrame(), … … 182 186 if (result != 1) 183 187 return; 184 188 185 final boolean keep_backup = backups.isSelected(); 186 final boolean change_mtime = setMTime.isSelected(); 189 final boolean write_gpstime = cbWriteGpsTime.isSelected(); 190 final boolean keep_backup = cbBackups.isSelected(); 191 final boolean change_mtime = cbSetMTime.isSelected(); 187 192 Config.getPref().putBoolean(KEEP_BACKUP, keep_backup); 188 193 Config.getPref().putBoolean(CHANGE_MTIME, change_mtime); 189 194 if (change_mtime) { … … 201 206 Config.getPref().put(MTIME_MODE, mTimeModePref); 202 207 } 203 208 204 MainApplication.worker.execute(new GeoTaggingRunnable(images, keep_backup, mTimeMode.getSelectedIndex()));209 MainApplication.worker.execute(new GeoTaggingRunnable(images, write_gpstime, keep_backup, mTimeMode.getSelectedIndex())); 205 210 } 206 211 207 212 static class GeoTaggingRunnable extends PleaseWaitRunnable { 208 213 private final List<ImageEntry> images; 214 private final boolean write_gpstime; 209 215 private final boolean keep_backup; 210 216 private final int mTimeMode; 211 217 … … 218 224 219 225 private int currentIndex; 220 226 221 GeoTaggingRunnable(List<ImageEntry> images, boolean keep_backup, int mTimeMode) {227 GeoTaggingRunnable(List<ImageEntry> images, boolean write_gpstime, boolean keep_backup, int mTimeMode) { 222 228 super(tr("Photo Geotagging Plugin")); 223 229 this.images = images; 230 this.write_gpstime = write_gpstime; 224 231 this.keep_backup = keep_backup; 225 232 this.mTimeMode = mTimeMode; 226 233 } … … 370 377 371 378 chooseFiles(e.getFile()); 372 379 if (canceled) return; 373 ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e, lossy);380 ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e, write_gpstime, lossy); 374 381 375 382 if (mTime != null) { 376 383 if (!fileTo.setLastModified(mTime.toEpochMilli())) … … 536 543 public boolean supportLayers(List<Layer> layers) { 537 544 return layers.size() == 1 && layers.get(0) instanceof GeoImageLayer; 538 545 } 539 } 540 546 } 547 No newline at end of file -
test/unit/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTaggerTest.java
2 2 // SPDX-License-Identifier: GPL-2.0-or-later 3 3 package org.openstreetmap.josm.plugins.photo_geotagging; 4 4 5 import static org.junit.Assert.assertThrows; 5 6 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; 6 7 import static org.junit.jupiter.api.Assertions.assertEquals; 7 8 … … 22 23 import org.openstreetmap.josm.data.coor.LatLon; 23 24 import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry; 24 25 import org.openstreetmap.josm.tools.ExifReader; 26 import org.openstreetmap.josm.tools.date.DateUtils; 25 27 26 28 class ExifGPSTaggerTest { 27 29 … … 44 46 final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg"); 45 47 final File out = new File(tempFolder, in.getName()); 46 48 final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI); 47 assertDoesNotThrow(() -> ExifGPSTagger.setExifGPSTag(in, out, image, true ));49 assertDoesNotThrow(() -> ExifGPSTagger.setExifGPSTag(in, out, image, true, true)); 48 50 } 49 51 50 52 @Test … … 62 64 final File in = new File(TestUtils.getTestDataRoot(), "IMG_7250_small.JPG"); 63 65 final File out = new File(tempFolder, in.getName()); 64 66 final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI); 65 ExifGPSTagger.setExifGPSTag(in, out, image, true );67 ExifGPSTagger.setExifGPSTag(in, out, image, true, true); 66 68 try { 67 69 final Process jhead = Runtime.getRuntime().exec(new String[]{"jhead", out.getAbsolutePath()}); 68 70 assertEquals(jhead.getErrorStream().available(), 0); … … 73 75 } 74 76 75 77 @Test 76 public void testTicket24278() throws Exception {78 public void testTicket24278() throws Exception { 77 79 final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg"); 78 80 final File out = new File(tempFolder, in.getName()); 79 81 final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI); … … 84 86 image.setExifHPosErr(1.2d); 85 87 image.setExifGpsDop(2.5d); 86 88 image.setExifGpsDatum("WGS84"); 87 ExifGPSTagger.setExifGPSTag(in, out, image, true );89 ExifGPSTagger.setExifGPSTag(in, out, image, true, true); 88 90 assertEquals(Math.PI, ExifReader.readDirection(out), 0.001); 89 91 assertEquals(97.99, ExifReader.readGpsTrackDirection(out)); 90 92 assertEquals(1, ExifReader.readGpsDiffMode(out)); … … 94 96 assertEquals(2.5, ExifReader.readGpsDop(out)); 95 97 assertEquals("WGS84", ExifReader.readGpsDatum(out)); 96 98 } 99 100 @Test 101 public void testTicket24458() throws Exception { 102 final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg"); 103 final File out = new File(tempFolder, in.getName()); 104 final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI); 105 image.setGpsTime(DateUtils.parseInstant("2025:10:26 12:00:00")); 106 // Test writing EXIF GPSDateStamp and GPSTimeStamp 107 ExifGPSTagger.setExifGPSTag(in, out, image, true, true); 108 assertEquals(DateUtils.parseInstant("2025:10:26 12:00:00"), ExifReader.readGpsInstant(out)); 109 // Test not writing GPSDateStamp and GPSTimeStamp 110 ExifGPSTagger.setExifGPSTag(in, out, image, false, true); 111 assertThrows(NullPointerException.class, () -> ExifReader.readGpsInstant(out)); 112 } 97 113 } -
test/unit/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingActionTest.java
34 34 entry.setPos(new LatLon(1, 2)); 35 35 List<ImageEntry> list = Arrays.asList(entry); 36 36 37 GeoTaggingRunnable runnable = new GeotaggingAction.GeoTaggingRunnable(list, true, 0);37 GeoTaggingRunnable runnable = new GeotaggingAction.GeoTaggingRunnable(list, true, true, 0); 38 38 //this causes some warnings from the PleaseWaitRunnable because not all resources are available 39 39 //but that's irrelevant to the test 40 40 runnable.getProgressMonitor().beginTask("test"); … … 44 44 //test if overriding backup works: 45 45 assertEquals(0, runnable.processEntries(list, true).size()); 46 46 47 runnable = new GeotaggingAction.GeoTaggingRunnable(list, false, 0);47 runnable = new GeotaggingAction.GeoTaggingRunnable(list, true, false, 0); 48 48 runnable.getProgressMonitor().beginTask("test"); 49 49 //file is now "repaired" from operation above and lossless writing should work: 50 50 assertEquals(0, runnable.processEntries(list, false).size());
