Ticket #24458: 24458.patch

File 24458.patch, 12.6 KB (added by StephaneP, 2 months ago)

Replace the previous patch

  • src/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTagger.java

     
    4141     * @param imageFile A source image file.
    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
    5557            throw new IOException(tr("Read/write error: " + ire.getMessage()), ire);
     
    5759    }
    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;
    6365        ImageMetadata metadata = Imaging.getMetadata(imageFile);
     
    7981        gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_VERSION_ID);
    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());
    8587
  • src/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingAction.java

     
    5555
    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 {
    6061
     
    136137        settingsPanel.setBorder(BorderFactory.createTitledBorder(tr("settings")));
    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));
     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));
    141142
    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));
    144145
    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)")};
    146150        final JComboBox<String> mTimeMode = new JComboBox<>(mTimeModeArray);
    147151
    148152        String mTimeModePrefName = Config.getPref().get(MTIME_MODE, null);
     
    152156        } else if ("previous".equals(mTimeModePrefName)) {
    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 {
    163167                mTimeMode.setSelectedIndex(0);
     
    166170        });
    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(
    173177                MainApplication.getMainFrame(),
     
    182186        if (result != 1)
    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);
    189194        if (change_mtime) {
     
    201206            Config.getPref().put(MTIME_MODE, mTimeModePref);
    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;
    211217
     
    218224
    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;
    226233        }
     
    370377
    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) {
    376383                if (!fileTo.setLastModified(mTime.toEpochMilli()))
     
    536543    public boolean supportLayers(List<Layer> layers) {
    537544        return layers.size() == 1 && layers.get(0) instanceof GeoImageLayer;
    538545    }
    539 }
    540 
     546}
     547 No newline at end of file
  • test/unit/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTaggerTest.java

     
    22// SPDX-License-Identifier: GPL-2.0-or-later
    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;
    78
     
    2223import org.openstreetmap.josm.data.coor.LatLon;
    2324import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
    2425import org.openstreetmap.josm.tools.ExifReader;
     26import org.openstreetmap.josm.tools.date.DateUtils;
    2527
    2628class ExifGPSTaggerTest {
    2729
     
    4446        final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg");
    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
    5052    @Test
     
    6264        final File in = new File(TestUtils.getTestDataRoot(), "IMG_7250_small.JPG");
    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()});
    6870            assertEquals(jhead.getErrorStream().available(), 0);
     
    7375    }
    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());
    7981        final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI);
     
    8486        image.setExifHPosErr(1.2d);
    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));
    9092        assertEquals(1, ExifReader.readGpsDiffMode(out));
     
    9496        assertEquals(2.5, ExifReader.readGpsDop(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}
  • test/unit/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingActionTest.java

     
    3434        entry.setPos(new LatLon(1, 2));
    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
    4040        runnable.getProgressMonitor().beginTask("test");
     
    4444        //test if overriding backup works:
    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:
    5050        assertEquals(0, runnable.processEntries(list, false).size());