Index: src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 9211)
+++ src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(working copy)
@@ -21,19 +21,15 @@
 import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.io.IOException;
-import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.GregorianCalendar;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
-import java.util.TimeZone;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -67,18 +63,9 @@
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.JpgImporter;
-import org.openstreetmap.josm.tools.ExifReader;
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.Utils;
 
-import com.drew.imaging.jpeg.JpegMetadataReader;
-import com.drew.lang.CompoundException;
-import com.drew.metadata.Directory;
-import com.drew.metadata.Metadata;
-import com.drew.metadata.MetadataException;
-import com.drew.metadata.exif.ExifIFD0Directory;
-import com.drew.metadata.exif.GpsDirectory;
-
 /**
  * Layer displaying geottaged pictures.
  */
@@ -157,18 +144,8 @@
                 progressMonitor.subTask(tr("Reading {0}...", f.getName()));
                 progressMonitor.worked(1);
 
-                ImageEntry e = new ImageEntry();
-
-                // Changed to silently cope with no time info in exif. One case
-                // of person having time that couldn't be parsed, but valid GPS info
-
-                try {
-                    e.setExifTime(ExifReader.readTime(f));
-                } catch (ParseException ex) {
-                    e.setExifTime(null);
-                }
-                e.setFile(f);
-                extractExif(e);
+                ImageEntry e = new ImageEntry(f);
+                e.extractExif();
                 data.add(e);
             }
             layer = new GeoImageLayer(data, gpxLayer);
@@ -593,125 +570,6 @@
         }
     }
 
-    /**
-     * Extract GPS metadata from image EXIF
-     *
-     * If successful, fills in the LatLon and EastNorth attributes of passed in image
-     */
-    private static void extractExif(ImageEntry e) {
-
-        Metadata metadata;
-        Directory dirExif;
-        GpsDirectory dirGps;
-
-        try {
-            metadata = JpegMetadataReader.readMetadata(e.getFile());
-            dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
-            dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
-        } catch (CompoundException | IOException p) {
-            e.setExifCoor(null);
-            e.setPos(null);
-            return;
-        }
-
-        try {
-            if (dirExif != null) {
-                int orientation = dirExif.getInt(ExifIFD0Directory.TAG_ORIENTATION);
-                e.setExifOrientation(orientation);
-            }
-        } catch (MetadataException ex) {
-            Main.debug(ex.getMessage());
-        }
-
-        if (dirGps == null) {
-            e.setExifCoor(null);
-            e.setPos(null);
-            return;
-        }
-
-        try {
-            double speed = dirGps.getDouble(GpsDirectory.TAG_SPEED);
-            String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF);
-            if ("M".equalsIgnoreCase(speedRef)) {
-                // miles per hour
-                speed *= 1.609344;
-            } else if ("N".equalsIgnoreCase(speedRef)) {
-                // knots == nautical miles per hour
-                speed *= 1.852;
-            }
-            // default is K (km/h)
-            e.setSpeed(speed);
-        } catch (Exception ex) {
-            Main.debug(ex.getMessage());
-        }
-
-        try {
-            double ele = dirGps.getDouble(GpsDirectory.TAG_ALTITUDE);
-            int d = dirGps.getInt(GpsDirectory.TAG_ALTITUDE_REF);
-            if (d == 1) {
-                ele *= -1;
-            }
-            e.setElevation(ele);
-        } catch (MetadataException ex) {
-            Main.debug(ex.getMessage());
-        }
-
-        try {
-            LatLon latlon = ExifReader.readLatLon(dirGps);
-            e.setExifCoor(latlon);
-            e.setPos(e.getExifCoor());
-
-        } catch (Exception ex) { // (other exceptions, e.g. #5271)
-            Main.error("Error reading EXIF from file: "+ex);
-            e.setExifCoor(null);
-            e.setPos(null);
-        }
-
-        try {
-            Double direction = ExifReader.readDirection(dirGps);
-            if (direction != null) {
-                e.setExifImgDir(direction.doubleValue());
-            }
-        } catch (Exception ex) { // (CompoundException and other exceptions, e.g. #5271)
-            Main.debug(ex.getMessage());
-        }
-
-        // Time and date. We can have these cases:
-        // 1) GPS_TIME_STAMP not set -> date/time will be null
-        // 2) GPS_DATE_STAMP not set -> use EXIF date or set to default
-        // 3) GPS_TIME_STAMP and GPS_DATE_STAMP are set
-        int[] timeStampComps = dirGps.getIntArray(GpsDirectory.TAG_TIME_STAMP);
-        if (timeStampComps != null) {
-            int gpsHour = timeStampComps[0];
-            int gpsMin = timeStampComps[1];
-            int gpsSec = timeStampComps[2];
-            Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
-
-            // We have the time. Next step is to check if the GPS date stamp is set.
-            // dirGps.getString() always succeeds, but the return value might be null.
-            String dateStampStr = dirGps.getString(GpsDirectory.TAG_DATE_STAMP);
-            if (dateStampStr != null && dateStampStr.matches("^\\d+:\\d+:\\d+$")) {
-                String[] dateStampComps = dateStampStr.split(":");
-                cal.set(Calendar.YEAR, Integer.parseInt(dateStampComps[0]));
-                cal.set(Calendar.MONTH, Integer.parseInt(dateStampComps[1]) - 1);
-                cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStampComps[2]));
-            } else {
-                // No GPS date stamp in EXIF data. Copy it from EXIF time.
-                // Date is not set if EXIF time is not available.
-                if (e.hasExifTime()) {
-                    // Time not set yet, so we can copy everything, not just date.
-                    cal.setTime(e.getExifTime());
-                }
-            }
-
-            cal.set(Calendar.HOUR_OF_DAY, gpsHour);
-            cal.set(Calendar.MINUTE, gpsMin);
-            cal.set(Calendar.SECOND, gpsSec);
-
-            e.setExifGpsTime(cal.getTime());
-        }
-    }
-
     public void showNextPhoto() {
         if (data != null && !data.isEmpty()) {
             currentPhoto++;
Index: src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java	(revision 9211)
+++ src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java	(working copy)
@@ -3,11 +3,26 @@
 
 import java.awt.Image;
 import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Calendar;
 import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.coor.CachedLatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.tools.ExifReader;
 
+import com.drew.imaging.jpeg.JpegMetadataReader;
+import com.drew.lang.CompoundException;
+import com.drew.metadata.Directory;
+import com.drew.metadata.Metadata;
+import com.drew.metadata.MetadataException;
+import com.drew.metadata.exif.ExifIFD0Directory;
+import com.drew.metadata.exif.GpsDirectory;
+
 /**
  * Stores info about each image
  */
@@ -50,6 +65,19 @@
     ImageEntry tmp;
 
     /**
+     * Constructs a new {@code ImageEntry}.
+     */
+    public ImageEntry() {}
+
+    /**
+     * Constructs a new {@code ImageEntry}.
+     * @param file Path to image file on disk
+     */
+    public ImageEntry(File file) {
+        setFile(file);
+    }
+
+    /**
      * getter methods that refer to the temporary value
      */
     public CachedLatLon getPos() {
@@ -85,6 +113,12 @@
         return (tmp != null && tmp.gpsTime != null) || gpsTime != null;
     }
 
+    public Double getExifImgDir() {
+        if (tmp != null)
+            return tmp.exifImgDir;
+        return exifImgDir;
+    }
+
     /**
      * other getter methods
      */
@@ -137,14 +171,14 @@
         return exifCoor;
     }
 
-    public Double getExifImgDir() {
-        return exifImgDir;
-    }
-
     public boolean hasThumbnail() {
         return thumbnail != null;
     }
 
+    public Image getThumbnail() {
+        return thumbnail;
+    }
+
     /**
      * setter methods
      */
@@ -153,7 +187,11 @@
     }
 
     public void setPos(LatLon pos) {
-        this.pos = new CachedLatLon(pos);
+        if (pos == null) {
+            this.pos = null;
+        } else {
+            this.pos = new CachedLatLon(pos);
+        }
     }
 
     public void setSpeed(Double speed) {
@@ -193,10 +231,14 @@
         this.exifCoor = exifCoor;
     }
 
-    public void setExifImgDir(double exifDir) {
+    public void setExifImgDir(Double exifDir) {
         this.exifImgDir = exifDir;
     }
 
+    //public void setExifImgDir(double exifDir) {
+    //    this.exifImgDir = exifDir;
+    //}
+
     @Override
     public ImageEntry clone() {
         Object c;
@@ -230,8 +272,23 @@
     }
 
     /**
-     * Copy the values from the temporary variable to the main instance.
+     * Get temporary variable that is used for real time parameter
+     * adjustments. The temporary variable is created if it does not exist
+     * yet. Use applyTmp() or discardTmp() if the temporary variable is not
+     * needed anymore.
      */
+    public ImageEntry getTmp() {
+        if (tmp == null) {
+            tmp = clone();
+            tmp.tmp = null;
+        }
+        return tmp;
+    }
+
+    /**
+     * Copy the values from the temporary variable to the main instance. The
+     * temporary variable is deleted.
+     */
     public void applyTmp() {
         if (tmp != null) {
             pos = tmp.pos;
@@ -238,11 +295,19 @@
             speed = tmp.speed;
             elevation = tmp.elevation;
             gpsTime = tmp.gpsTime;
+            exifImgDir = tmp.exifImgDir;
             tmp = null;
         }
     }
 
     /**
+     * Delete the temporary variable. Temporary modifications are lost.
+     */
+    public void discardTmp() {
+        tmp = null;
+    }
+
+    /**
      * If it has been tagged i.e. matched to a gpx track or retrieved lat/lon from exif
      */
     public boolean isTagged() {
@@ -287,4 +352,135 @@
     public boolean hasNewGpsData() {
         return isNewGpsData;
     }
+
+    /**
+     * Extract GPS metadata from image EXIF. Has no effect if the image file is not set
+     *
+     * If successful, fills in the LatLon, speed, elevation, image direction, and other attributes
+     */
+    public void extractExif() {
+
+        Metadata metadata;
+        Directory dirExif;
+        GpsDirectory dirGps;
+
+        if (file == null) {
+            return;
+        }
+
+        try {
+            metadata = JpegMetadataReader.readMetadata(file);
+            dirExif = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
+            dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
+        } catch (CompoundException | IOException p) {
+            setExifCoor(null);
+            setPos(null);
+            return;
+        }
+
+        try {
+            if (dirExif != null) {
+                int orientation = dirExif.getInt(ExifIFD0Directory.TAG_ORIENTATION);
+                setExifOrientation(orientation);
+            }
+        } catch (MetadataException ex) {
+            Main.debug(ex.getMessage());
+        }
+
+        if (dirGps == null) {
+            setExifCoor(null);
+            setPos(null);
+            return;
+        }
+
+        try {
+            double speed = dirGps.getDouble(GpsDirectory.TAG_SPEED);
+            String speedRef = dirGps.getString(GpsDirectory.TAG_SPEED_REF);
+            if ("M".equalsIgnoreCase(speedRef)) {
+                // miles per hour
+                speed *= 1.609344;
+            } else if ("N".equalsIgnoreCase(speedRef)) {
+                // knots == nautical miles per hour
+                speed *= 1.852;
+            }
+            // default is K (km/h)
+            setSpeed(speed);
+        } catch (Exception ex) {
+            Main.debug(ex.getMessage());
+        }
+
+        try {
+            double ele = dirGps.getDouble(GpsDirectory.TAG_ALTITUDE);
+            int d = dirGps.getInt(GpsDirectory.TAG_ALTITUDE_REF);
+            if (d == 1) {
+                ele *= -1;
+            }
+            setElevation(ele);
+        } catch (MetadataException ex) {
+            Main.debug(ex.getMessage());
+        }
+
+        try {
+            LatLon latlon = ExifReader.readLatLon(dirGps);
+            setExifCoor(latlon);
+            setPos(getExifCoor());
+
+        } catch (Exception ex) { // (other exceptions, e.g. #5271)
+            Main.error("Error reading EXIF from file: "+ex);
+            setExifCoor(null);
+            setPos(null);
+        }
+
+        try {
+            Double direction = ExifReader.readDirection(dirGps);
+            if (direction != null) {
+                setExifImgDir(direction);
+            }
+        } catch (Exception ex) { // (CompoundException and other exceptions, e.g. #5271)
+            Main.debug(ex.getMessage());
+        }
+
+        // Changed to silently cope with no time info in exif. One case
+        // of person having time that couldn't be parsed, but valid GPS info
+        try {
+            setExifTime(ExifReader.readTime(file));
+        } catch (ParseException ex) {
+            setExifTime(null);
+        }
+
+        // Time and date. We can have these cases:
+        // 1) GPS_TIME_STAMP not set -> date/time will be null
+        // 2) GPS_DATE_STAMP not set -> use EXIF date or set to default
+        // 3) GPS_TIME_STAMP and GPS_DATE_STAMP are set
+        int[] timeStampComps = dirGps.getIntArray(GpsDirectory.TAG_TIME_STAMP);
+        if (timeStampComps != null) {
+            int gpsHour = timeStampComps[0];
+            int gpsMin = timeStampComps[1];
+            int gpsSec = timeStampComps[2];
+            Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+
+            // We have the time. Next step is to check if the GPS date stamp is set.
+            // dirGps.getString() always succeeds, but the return value might be null.
+            String dateStampStr = dirGps.getString(GpsDirectory.TAG_DATE_STAMP);
+            if (dateStampStr != null && dateStampStr.matches("^\\d+:\\d+:\\d+$")) {
+                String[] dateStampComps = dateStampStr.split(":");
+                cal.set(Calendar.YEAR, Integer.parseInt(dateStampComps[0]));
+                cal.set(Calendar.MONTH, Integer.parseInt(dateStampComps[1]) - 1);
+                cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(dateStampComps[2]));
+            } else {
+                // No GPS date stamp in EXIF data. Copy it from EXIF time.
+                // Date is not set if EXIF time is not available.
+                if (hasExifTime()) {
+                    // Time not set yet, so we can copy everything, not just date.
+                    cal.setTime(getExifTime());
+                }
+            }
+
+            cal.set(Calendar.HOUR_OF_DAY, gpsHour);
+            cal.set(Calendar.MINUTE, gpsMin);
+            cal.set(Calendar.SECOND, gpsSec);
+
+            setExifGpsTime(cal.getTime());
+        }
+    }
 }
Index: src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 9211)
+++ src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(working copy)
@@ -69,6 +69,7 @@
     private JButton btnNext;
     private JButton btnPrevious;
     private JButton btnCollapse;
+    private JToggleButton tbCentre;
 
     private ImageViewerDialog() {
         super(tr("Geotagged Images"), "geoimage", tr("Display geotagged images"), Shortcut.registerShortcut("tools:geotagged",
@@ -149,7 +150,7 @@
                         "geoimage:last", tr("Geoimage: {0}", tr("Show last Image")), KeyEvent.VK_END, Shortcut.DIRECT)
         );
 
-        JToggleButton tbCentre = new JToggleButton(new ImageAction(COMMAND_CENTERVIEW,
+        tbCentre = new JToggleButton(new ImageAction(COMMAND_CENTERVIEW,
                 ImageProvider.get("dialogs", "centreview"), tr("Center view")));
         tbCentre.setPreferredSize(buttonDim);
 
@@ -275,6 +276,36 @@
         getInstance().btnNext.setEnabled(value);
     }
 
+    /**
+     * Enables (or disables) the "Center view" button.
+     * @param value {@code true} to enable the button, {@code false} otherwise
+     * @return the old enabled value. Can be used to restore the original enable state
+     */
+    public static boolean setCentreEnabled(boolean value) {
+        final ImageViewerDialog instance = getInstance();
+        boolean wasEnabled;
+        synchronized (instance) {
+            wasEnabled = instance.tbCentre.isEnabled();
+            instance.tbCentre.setEnabled(value);
+            if (value) {
+                boolean selected = instance.tbCentre.isSelected();
+                instance.centerView = selected;
+                if (selected) {
+                    // Trigger map centering in case the image position was
+                    // modified while the center view was disabled.
+                    if (Main.isDisplayingMapView()
+                        && instance.currentEntry != null
+                        && instance.currentEntry.getPos() != null) {
+                        Main.map.mapView.zoomTo(instance.currentEntry.getPos());
+                    }
+                }
+            } else {
+                instance.centerView = false;
+            }
+        }
+        return wasEnabled;
+    }
+
     private transient GeoImageLayer currentLayer;
     private transient ImageEntry currentEntry;
 
@@ -303,7 +334,7 @@
             setTitle(tr("Geotagged Images") + (entry.getFile() != null ? " - " + entry.getFile().getName() : ""));
             StringBuilder osd = new StringBuilder(entry.getFile() != null ? entry.getFile().getName() : "");
             if (entry.getElevation() != null) {
-                osd.append(tr("\nAltitude: {0} m", entry.getElevation().longValue()));
+                osd.append(tr("\nAltitude: {0} m", Math.round(entry.getElevation())));
             }
             if (entry.getSpeed() != null) {
                 osd.append(tr("\nSpeed: {0} km/h", Math.round(entry.getSpeed())));
Index: src/org/openstreetmap/josm/io/session/GeoImageSessionImporter.java
===================================================================
--- src/org/openstreetmap/josm/io/session/GeoImageSessionImporter.java	(revision 9211)
+++ src/org/openstreetmap/josm/io/session/GeoImageSessionImporter.java	(working copy)
@@ -79,7 +79,7 @@
                                             Double.parseDouble(attrElem.getAttribute("lon"))));
                                     break;
                                 case "exif-image-direction":
-                                    entry.setExifImgDir(Double.parseDouble(attrElem.getTextContent()));
+                                    entry.setExifImgDir(Double.valueOf(attrElem.getTextContent()));
                                     break;
                                 case "is-new-gps-data":
                                     if (Boolean.parseBoolean(attrElem.getTextContent())) {
