Ticket #24278: 24278_B.patch

File 24278_B.patch, 22.8 KB (added by StephaneP, 9 months ago)
  • build.xml

     
    44    <!-- enter the SVN commit message -->
    55    <property name="commit.message" value=""/>
    66    <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
    7     <property name="plugin.main.version" value="19044"/>
     7    <property name="plugin.main.version" value="19389"/>
    88
    99    <property name="plugin.author" value="Paul Hartmann"/>
    1010    <property name="plugin.class" value="org.openstreetmap.josm.plugins.photo_geotagging.GeotaggingPlugin"/>
  • pom.xml

     
    1616    </developers>
    1717    <properties>
    1818        <plugin.src.dir>src</plugin.src.dir>
    19         <plugin.main.version>19044</plugin.main.version>
     19        <plugin.main.version>19389</plugin.main.version>
    2020        <plugin.author>Paul Hartmann</plugin.author>
    2121        <plugin.class>org.openstreetmap.josm.plugins.photo_geotagging.GeotaggingPlugin</plugin.class>
    2222        <plugin.description>Write gps position info to the image file header. Run this feature from the right click menu of the image layer.</plugin.description>
  • src/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTagger.java

     
    99import java.io.FileOutputStream;
    1010import java.io.IOException;
    1111import java.text.DecimalFormat;
    12 import java.time.Instant;
    1312import java.util.Calendar;
    1413import java.util.GregorianCalendar;
    1514import java.util.TimeZone;
     
    2524import org.apache.commons.imaging.formats.tiff.write.TiffImageWriterLossy;
    2625import org.apache.commons.imaging.formats.tiff.write.TiffOutputDirectory;
    2726import org.apache.commons.imaging.formats.tiff.write.TiffOutputSet;
     27import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
    2828
    2929/**
    3030 * Wrapper class for sanselan library
     
    4040     *
    4141     * @param imageFile A source image file.
    4242     * @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
    4944     * @param lossy whether to use lossy approach when writing metadata (overwriting unknown tags)
    5045     * @throws IOException in case of I/O error
     46     * @since xxx separate image parameters (lat, lon, gpsTime, speed, ele, imgDir), replaced by the whole ImageEntry object.
    5147     */
    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 {
    5451        try {
    55             setExifGPSTagWorker(imageFile, dst, lat, lon, gpsTime, speed, ele, imgDir, lossy);
     52            setExifGPSTagWorker(imageFile, dst, imageEntry, lossy);
    5653        } catch (ImagingException ire) {
    5754            // This used to be two separate exceptions; ImageReadException and imageWriteException
    5855            throw new IOException(tr("Read/write error: " + ire.getMessage()), ire);
     
    5956        }
    6057    }
    6158
    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 {
    6461
    6562        TiffOutputSet outputSet = null;
    6663        ImageMetadata metadata = Imaging.getMetadata(imageFile);
     
    8077
    8178        TiffOutputDirectory gpsDirectory = outputSet.getOrCreateGpsDirectory();
    8279        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);
     80        gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_VERSION_ID, (byte) 2, (byte) 3, (byte) 0, (byte) 0);
    8481
    85         if (gpsTime != null) {
     82        if (imageEntry.getGpsInstant() != null) {
    8683            Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    87             calendar.setTimeInMillis(gpsTime.toEpochMilli());
     84            calendar.setTimeInMillis(imageEntry.getGpsInstant().toEpochMilli());
    8885
    8986            final int year =   calendar.get(Calendar.YEAR);
    9087            final int month =  calendar.get(Calendar.MONTH) + 1;
     
    117114            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_DATE_STAMP, dateStamp);
    118115        }
    119116
    120         outputSet.setGpsInDegrees(lon, lat);
     117        outputSet.setGpsInDegrees(imageEntry.getPos().lon(), imageEntry.getPos().lat());
    121118
    122         if (speed != null) {
     119        if (imageEntry.getSpeed() != null) {
    123120            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_SPEED_REF);
    124121            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_SPEED_REF,
    125122                             GpsTagConstants.GPS_TAG_GPS_SPEED_REF_VALUE_KMPH);
    126123
    127124            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_SPEED);
    128             gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_SPEED, RationalNumber.valueOf(speed));
     125            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_SPEED, RationalNumber.valueOf(imageEntry.getSpeed()));
    129126        }
    130127
    131         if (ele != null) {
    132             byte eleRef =  ele >= 0 ? (byte) 0 : (byte) 1;
     128        if (imageEntry.getElevation() != null) {
     129            byte eleRef =  imageEntry.getElevation() >= 0 ? (byte) 0 : (byte) 1;
    133130            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE_REF);
    134131            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE_REF, eleRef);
    135132
    136133            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_ALTITUDE);
    137             gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(Math.abs(ele)));
     134            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_ALTITUDE, RationalNumber.valueOf(Math.abs(imageEntry.getElevation())));
    138135        }
    139136
    140         if (imgDir != null) {
     137        if (imageEntry.getExifImgDir() != null) {
    141138            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF);
    142139            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF,
    143140                             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());
    152142            gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION);
    153143            gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, RationalNumber.valueOf(imgDir));
    154144        }
    155145
     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()));
     187        }
     188
    156189        try (BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(dst))) {
    157190            if (metadata instanceof JpegImageMetadata) {
    158191                if (lossy) {
     
    165198            }
    166199        }
    167200    }
     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    }
    168218}
  • src/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingAction.java

     
    8585        DecimalFormat dFormatter = new DecimalFormat("###0.000000");
    8686
    8787        for (ImageEntry e : layer.getImages()) {
    88              /* Only write lat/lon to the file, if the position is known and
     88            /* Only write lat/lon to the file, if the position is known and
    8989                the GPS data changed. */
    9090            if (e.getPos() != null && e.hasNewGpsData()) {
    9191                String pth = e.getFile().getAbsolutePath();
     
    134134
    135135        final JPanel settingsPanel = new JPanel(new GridBagLayout());
    136136        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));
    138138
    139139        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));
    141141
    142142        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));
    144144
    145145        final String[] mTimeModeArray = {"----", tr("to gps time"), tr("to previous value (unchanged mtime)")};
    146146        final JComboBox<String> mTimeMode = new JComboBox<>(mTimeModeArray);
     
    154154            }
    155155            mTimeMode.setSelectedIndex(setMTime.isSelected() ? mTimeIdx : 0);
    156156        }
    157         settingsPanel.add(mTimeMode, GBC.eol().insets(3,3,3,3));
     157        settingsPanel.add(mTimeMode, GBC.eol().insets(3, 3, 3, 3));
    158158
    159159        setMTime.addActionListener(e -> {
    160160            if (setMTime.isSelected()) {
     
    225225            this.mTimeMode = mTimeMode;
    226226        }
    227227
    228 
    229228        @Override
    230229        protected void realRun() {
    231230            List<ImageEntry> failedEntries = processEntries(images, false);
     
    359358                    mTime = e.getExifGpsInstant();
    360359                }
    361360            }
    362             if ( mTimeMode == MTIME_MODE_PREVIOUS_VALUE
     361            if (mTimeMode == MTIME_MODE_PREVIOUS_VALUE
    363362                 // this is also the fallback if one of the other
    364363                 // modes failed to determine the modification time
    365364                 || (mTimeMode != 0 && mTime == null)) {
     
    370369
    371370            chooseFiles(e.getFile());
    372371            if (canceled) return;
    373             ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e.getPos().lat(), e.getPos().lon(),
    374                     e.getGpsInstant(), e.getSpeed(), e.getElevation(), e.getExifImgDir(), lossy);
     372            ExifGPSTagger.setExifGPSTag(fileFrom, fileTo, e, lossy);
    375373
    376374            if (mTime != null) {
    377375                if (!fileTo.setLastModified(mTime.toEpochMilli()))
     
    390388                return;
    391389            }
    392390
    393             File fileBackup = new File(file.getParentFile(),file.getName()+"_");
     391            File fileBackup = new File(file.getParentFile(), file.getName()+"_");
    394392            if (fileBackup.exists()) {
    395393                confirm_override();
    396394                if (canceled)
     
    510508    }
    511509
    512510    private GeoImageLayer getLayer() {
    513         return (GeoImageLayer)LayerListDialog.getInstance().getModel().getSelectedLayers().get(0);
     511        return (GeoImageLayer) LayerListDialog.getInstance().getModel().getSelectedLayers().get(0);
    514512    }
    515513
    516514    /**
     
    538536        return layers.size() == 1 && layers.get(0) instanceof GeoImageLayer;
    539537    }
    540538}
     539
  • test/unit/org/openstreetmap/josm/plugins/photo_geotagging/ExifGPSTaggerTest.java

     
    1818import org.junit.jupiter.api.Test;
    1919import org.junit.jupiter.api.io.TempDir;
    2020import org.openstreetmap.josm.TestUtils;
     21import org.openstreetmap.josm.data.coor.LatLon;
     22import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
    2123
    2224class ExifGPSTaggerTest {
    2325
     
    2426    @TempDir
    2527    File tempFolder;
    2628
     29    private static ImageEntry newImageEntry(String file, Double lat, Double lon, Instant exifTime,
     30                                            Double speed, Double elevation, Double imgDir) {
     31        ImageEntry entry = new ImageEntry(new File(file));
     32        entry.setPos(new LatLon(lat, lon));
     33        entry.setExifTime(exifTime);
     34        entry.setSpeed(speed);
     35        entry.setElevation(elevation);
     36        entry.setExifImgDir(imgDir);
     37        return entry;
     38    }
     39
    2740    @Test
    2841    void testTicket11757() {
    2942        final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg");
    3043        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));
     44        final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI);
     45        assertDoesNotThrow(() -> ExifGPSTagger.setExifGPSTag(in, out, image, true));
    3246    }
    3347
    3448    @Test
     
    4660    void testTicket11902() throws Exception {
    4761        final File in = new File(TestUtils.getTestDataRoot(), "IMG_7250_small.JPG");
    4862        final File out = new File(tempFolder, in.getName());
    49         ExifGPSTagger.setExifGPSTag(in, out, 12, 34, Instant.now(), 12.34, Math.E, Math.PI, false);
     63        final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI);
     64        ExifGPSTagger.setExifGPSTag(in, out, image, true);
    5065        final Process jhead = Runtime.getRuntime().exec(new String[]{"jhead", out.getAbsolutePath()});
    5166        final String stdout = new Scanner(jhead.getErrorStream()).useDelimiter("\\A").next();
    5267        System.out.println(stdout);
    5368        assertFalse(stdout.contains("Suspicious offset of first Exif IFD value"));
    5469    }
     70
     71    @Test
     72    public void testTicket24278() {
     73        final File in = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg");
     74        final File out = new File(tempFolder, in.getName());
     75        final ImageEntry image = newImageEntry("test", 12d, 34d, Instant.now(), 12.34d, Math.E, Math.PI);
     76        image.setExifGpsTrack(Math.PI);
     77        image.setGpsDiffMode(2);
     78        image.setGps2d3dMode(3);
     79        image.setExifGpsProcMethod("GPS");
     80        image.setExifHPosErr(1.2d);
     81        image.setExifGpsDop(2.5d);
     82        image.setExifGpsDatum("WGS84");
     83        assertDoesNotThrow(() -> ExifGPSTagger.setExifGPSTag(in, out, image, true));
     84        /* TODO read temp file and assertEquals EXIF metadata values */
     85    }
    5586}
  • test/unit/org/openstreetmap/josm/plugins/photo_geotagging/GeotaggingActionTest.java

     
    1 package org.openstreetmap.josm.plugins.photo_geotagging;
    2 
    3 
    4 import java.io.File;
    5 import java.io.IOException;
    6 import java.nio.file.Files;
    7 import java.nio.file.StandardCopyOption;
    8 import java.util.Arrays;
    9 import java.util.List;
    10 
    11 import org.junit.jupiter.api.Test;
    12 import org.openstreetmap.josm.TestUtils;
    13 import org.openstreetmap.josm.data.coor.LatLon;
    14 import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
    15 import org.openstreetmap.josm.plugins.photo_geotagging.GeotaggingAction.GeoTaggingRunnable;
    16 
    17 import static org.junit.jupiter.api.Assertions.assertEquals;
    18 import static org.junit.jupiter.api.Assertions.assertTrue;
    19 
    20 class GeotaggingActionTest {
    21 
    22     @Test
    23     void testProcessEntries() throws IOException {
    24         File original = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg");
    25         assertTrue(original.exists());
    26 
    27         File copy = new File(TestUtils.getTestDataRoot(), "_DSC1234.copy.jpg");
    28         if (copy.exists()) copy.delete();
    29         //this method will actually override the file, so use a copy:
    30         Files.copy(original.toPath(), copy.toPath(), StandardCopyOption.REPLACE_EXISTING);
    31 
    32         ImageEntry entry = new ImageEntry(copy);
    33         entry.setPos(new LatLon(1, 2));
    34         List<ImageEntry> list = Arrays.asList(entry);
    35 
    36         GeoTaggingRunnable runnable = new GeotaggingAction.GeoTaggingRunnable(list, true, 0);
    37         //this causes some warnings from the PleaseWaitRunnable because not all resources are available
    38         //but that's irrelevant to the test
    39         runnable.getProgressMonitor().beginTask("test");
    40         runnable.override_backup = true;
    41         assertEquals(1, runnable.processEntries(list, false).size());
    42         assertEquals(0, runnable.processEntries(list, true).size());
    43         //test if overriding backup works:
    44         assertEquals(0, runnable.processEntries(list, true).size());
    45 
    46         runnable = new GeotaggingAction.GeoTaggingRunnable(list, false, 0);
    47         runnable.getProgressMonitor().beginTask("test");
    48         //file is now "repaired" from operation above and lossless writing should work:
    49         assertEquals(0, runnable.processEntries(list, false).size());
    50         assertEquals(0, runnable.processEntries(list, true).size());
    51 
    52         File backup = new File(TestUtils.getTestDataRoot(), "_DSC1234.copy.jpg_");
    53         assertTrue(backup.exists());
    54         backup.delete();
    55         copy.delete();
    56     }
    57 }
     1package org.openstreetmap.josm.plugins.photo_geotagging;
     2
     3
     4import java.io.File;
     5import java.io.IOException;
     6import java.nio.file.Files;
     7import java.nio.file.StandardCopyOption;
     8import java.util.Arrays;
     9import java.util.List;
     10
     11import org.junit.jupiter.api.Test;
     12import org.openstreetmap.josm.TestUtils;
     13import org.openstreetmap.josm.data.coor.LatLon;
     14import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
     15import org.openstreetmap.josm.plugins.photo_geotagging.GeotaggingAction.GeoTaggingRunnable;
     16
     17import static org.junit.jupiter.api.Assertions.assertEquals;
     18import static org.junit.jupiter.api.Assertions.assertTrue;
     19
     20class GeotaggingActionTest {
     21
     22    @Test
     23    void testProcessEntries() throws IOException {
     24        File original = new File(TestUtils.getTestDataRoot(), "_DSC1234.jpg");
     25        assertTrue(original.exists());
     26
     27        File copy = new File(TestUtils.getTestDataRoot(), "_DSC1234.copy.jpg");
     28        if (copy.exists()) copy.delete();
     29        //this method will actually override the file, so use a copy:
     30        Files.copy(original.toPath(), copy.toPath(), StandardCopyOption.REPLACE_EXISTING);
     31
     32        ImageEntry entry = new ImageEntry(copy);
     33        entry.setPos(new LatLon(1, 2));
     34        List<ImageEntry> list = Arrays.asList(entry);
     35
     36        GeoTaggingRunnable runnable = new GeotaggingAction.GeoTaggingRunnable(list, true, 0);
     37        //this causes some warnings from the PleaseWaitRunnable because not all resources are available
     38        //but that's irrelevant to the test
     39        runnable.getProgressMonitor().beginTask("test");
     40        runnable.override_backup = true;
     41        assertEquals(1, runnable.processEntries(list, false).size());
     42        assertEquals(0, runnable.processEntries(list, true).size());
     43        //test if overriding backup works:
     44        assertEquals(0, runnable.processEntries(list, true).size());
     45
     46        runnable = new GeotaggingAction.GeoTaggingRunnable(list, false, 0);
     47        runnable.getProgressMonitor().beginTask("test");
     48        //file is now "repaired" from operation above and lossless writing should work:
     49        assertEquals(0, runnable.processEntries(list, false).size());
     50        assertEquals(0, runnable.processEntries(list, true).size());
     51
     52        File backup = new File(TestUtils.getTestDataRoot(), "_DSC1234.copy.jpg_");
     53        assertTrue(backup.exists());
     54        backup.delete();
     55        copy.delete();
     56    }
     57}