Changeset 36466 in osm for applications


Ignore:
Timestamp:
2026-01-05T14:20:42+01:00 (13 days ago)
Author:
stoecker
Message:

fix #24458 - patch by StephaneP, Don't modify image GPS Date/Time when writing new coordinates

Location:
applications/editors/josm/plugins/photo_geotagging
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/photo_geotagging/src/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTagger.java

    r36436 r36466  
    4242     * @param dst The output file.
    4343     * @param imageEntry the image object from Josm core
     44     * @param writeGpsTime write the EXIF tags GPSDateStamp and GPSTimeStamp
    4445     * @param lossy whether to use lossy approach when writing metadata (overwriting unknown tags)
    4546     * @throws IOException in case of I/O error
    4647     * @since 36436 separate image parameters (lat, lon, gpsTime, speed, ele, imgDir), replaced by the whole ImageEntry object.
     48     * @since xxx added writeGpsTime parameter
    4749     */
    4850
    4951    public static void setExifGPSTag(File imageFile, File dst, ImageEntry imageEntry,
    50             boolean lossy) throws IOException {
     52            boolean writeGpsTime, boolean lossy) throws IOException {
    5153        try {
    52             setExifGPSTagWorker(imageFile, dst, imageEntry, lossy);
     54            setExifGPSTagWorker(imageFile, dst, imageEntry, writeGpsTime, lossy);
    5355        } catch (ImagingException ire) {
    5456            // This used to be two separate exceptions; ImageReadException and imageWriteException
     
    5860
    5961    public static void setExifGPSTagWorker(File imageFile, File dst, ImageEntry imageEntry,
    60             boolean lossy) throws IOException {
     62            boolean writeGpsTime, boolean lossy) throws IOException {
    6163
    6264        TiffOutputSet outputSet = null;
     
    8082        gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_VERSION_ID, (byte) 2, (byte) 3, (byte) 0, (byte) 0);
    8183
    82         if (imageEntry.getGpsInstant() != null) {
     84        if (writeGpsTime && imageEntry.getGpsInstant() != null) {
    8385            Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    8486            calendar.setTimeInMillis(imageEntry.getGpsInstant().toEpochMilli());
     
    202204    /**
    203205     * Normalizes an angle to the range [0.0, 360.0[ degrees.
    204      * This will fix any angle value <0 and >= 360
     206     * This will fix any angle value &lt; 0 and &gt;= 360
    205207     * @param angle the angle to normalize (in degrees)
    206208     * @return the equivalent angle value in the range [0.0, 360.0[
  • applications/editors/josm/plugins/photo_geotagging/src/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingAction.java

    r36436 r36466  
    5656/**
    5757 * 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
    5859 */
    5960class GeotaggingAction extends AbstractAction implements LayerAction {
     
    137138        cont.add(settingsPanel, GBC.eol().insets(3, 10, 3, 0));
    138139
    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));
    141 
    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));
    144 
    145         final String[] mTimeModeArray = {"----", tr("to gps time"), tr("to previous value (unchanged mtime)")};
     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));
     142
     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));
     145
     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)")};
    146150        final JComboBox<String> mTimeMode = new JComboBox<>(mTimeModeArray);
    147151
     
    153157            mTimeIdx = 2;
    154158        }
    155         mTimeMode.setSelectedIndex(setMTime.isSelected() ? mTimeIdx : 0);
     159        mTimeMode.setSelectedIndex(cbSetMTime.isSelected() ? mTimeIdx : 0);
    156160
    157161        settingsPanel.add(mTimeMode, GBC.eol().insets(3, 3, 3, 3));
    158162
    159         setMTime.addActionListener(e -> {
    160             if (setMTime.isSelected()) {
     163        cbSetMTime.addActionListener(e -> {
     164            if (cbSetMTime.isSelected()) {
    161165                mTimeMode.setEnabled(true);
    162166            } else {
     
    167171
    168172        // Toggle the checkbox to fire actionListener
    169         setMTime.setSelected(!setMTime.isSelected());
    170         setMTime.doClick();
     173        cbSetMTime.setSelected(!cbSetMTime.isSelected());
     174        cbSetMTime.doClick();
    171175
    172176        int result = new ExtendedDialog(
     
    183187            return;
    184188
    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();
    187192        Config.getPref().putBoolean(KEEP_BACKUP, keep_backup);
    188193        Config.getPref().putBoolean(CHANGE_MTIME, change_mtime);
     
    202207        }
    203208
    204         MainApplication.worker.execute(new GeoTaggingRunnable(images, keep_backup, mTimeMode.getSelectedIndex()));
     209        MainApplication.worker.execute(new GeoTaggingRunnable(images, write_gpstime, keep_backup, mTimeMode.getSelectedIndex()));
    205210    }
    206211
    207212    static class GeoTaggingRunnable extends PleaseWaitRunnable {
    208213        private final List<ImageEntry> images;
     214        private final boolean write_gpstime;
    209215        private final boolean keep_backup;
    210216        private final int mTimeMode;
     
    219225        private int currentIndex;
    220226
    221         GeoTaggingRunnable(List<ImageEntry> images, boolean keep_backup, int mTimeMode) {
     227        GeoTaggingRunnable(List<ImageEntry> images, boolean write_gpstime, boolean keep_backup, int mTimeMode) {
    222228            super(tr("Photo Geotagging Plugin"));
    223229            this.images = images;
     230            this.write_gpstime = write_gpstime;
    224231            this.keep_backup = keep_backup;
    225232            this.mTimeMode = mTimeMode;
     
    371378            chooseFiles(e.getFile());
    372379            if (canceled) return;
    373             ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e, lossy);
     380            ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e, write_gpstime, lossy);
    374381
    375382            if (mTime != null) {
     
    538545    }
    539546}
    540 
  • applications/editors/josm/plugins/photo_geotagging/test/unit/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTaggerTest.java

    r36450 r36466  
    33package org.openstreetmap.josm.plugins.photo_geotagging;
    44
     5import static org.junit.Assert.assertThrows;
    56import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
    67import static org.junit.jupiter.api.Assertions.assertEquals;
     
    2324import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
    2425import org.openstreetmap.josm.tools.ExifReader;
     26import org.openstreetmap.josm.tools.date.DateUtils;
    2527
    2628class ExifGPSTaggerTest {
     
    4547        final File out = new File(tempFolder, in.getName());
    4648        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));
    4850    }
    4951
     
    6365        final File out = new File(tempFolder, in.getName());
    6466        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);
    6668        try {
    6769            final Process jhead = Runtime.getRuntime().exec(new String[]{"jhead", out.getAbsolutePath()});
     
    7476
    7577    @Test
    76     public void testTicket24278() throws Exception{
     78    public void testTicket24278() throws Exception {
    7779        final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg");
    7880        final File out = new File(tempFolder, in.getName());
     
    8587        image.setExifGpsDop(2.5d);
    8688        image.setExifGpsDatum("WGS84");
    87         ExifGPSTagger.setExifGPSTag(in, out, image, true);
     89        ExifGPSTagger.setExifGPSTag(in, out, image, true, true);
    8890        assertEquals(Math.PI, ExifReader.readDirection(out), 0.001);
    8991        assertEquals(97.99, ExifReader.readGpsTrackDirection(out));
     
    9597        assertEquals("WGS84", ExifReader.readGpsDatum(out));
    9698    }
     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    }
    97113}
  • applications/editors/josm/plugins/photo_geotagging/test/unit/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingActionTest.java

    r36436 r36466  
    3535        List<ImageEntry> list = Arrays.asList(entry);
    3636
    37         GeoTaggingRunnable runnable = new GeotaggingAction.GeoTaggingRunnable(list, true, 0);
     37        GeoTaggingRunnable runnable = new GeotaggingAction.GeoTaggingRunnable(list, true, true, 0);
    3838        //this causes some warnings from the PleaseWaitRunnable because not all resources are available
    3939        //but that's irrelevant to the test
     
    4545        assertEquals(0, runnable.processEntries(list, true).size());
    4646
    47         runnable = new GeotaggingAction.GeoTaggingRunnable(list, false, 0);
     47        runnable = new GeotaggingAction.GeoTaggingRunnable(list, true, false, 0);
    4848        runnable.getProgressMonitor().beginTask("test");
    4949        //file is now "repaired" from operation above and lossless writing should work:
Note: See TracChangeset for help on using the changeset viewer.